Contiki 3.x
gpio-pcal9535a.c
1 /*
2  * Copyright (C) 2015, Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "contiki.h"
32 #include "gpio.h"
33 #include "gpio-pcal9535a.h"
34 #include "i2c.h"
35 #include "stdio.h"
36 
37 #define REG_INPUT_PORT0 0x00
38 #define REG_INPUT_PORT1 0x01
39 #define REG_OUTPUT_PORT0 0x02
40 #define REG_OUTPUT_PORT1 0x03
41 #define REG_POL_INV_PORT0 0x04
42 #define REG_POL_INV_PORT1 0x05
43 #define REG_CONF_PORT0 0x06
44 #define REG_CONG_PORT1 0x07
45 #define REG_OUT_DRV_STRENGTH_PORT0_L 0x40
46 #define REG_OUT_DRV_STRENGTH_PORT0_H 0x41
47 #define REG_OUT_DRV_STRENGTH_PORT1_L 0x42
48 #define REG_OUT_DRV_STRENGTH_PORT1_H 0x43
49 #define REG_INPUT_LATCH_PORT0 0x44
50 #define REG_INPUT_LATCH_PORT1 0x45
51 #define REG_PUD_EN_PORT0 0x46
52 #define REG_PUD_EN_PORT1 0x47
53 #define REG_PUD_SEL_PORT0 0x48
54 #define REG_PUD_SEL_PORT1 0x49
55 #define REG_INT_MASK_PORT0 0x4A
56 #define REG_INT_MASK_PORT1 0x4B
57 #define REG_INT_STATUS_PORT0 0x4C
58 #define REG_INT_STATUS_PORT1 0x4D
59 #define REG_OUTPUT_PORT_CONF 0x4F
60 
61 #define READ_PORT_TIMEOUT (CLOCK_SECOND / 100)
62 #define READ_PORT_TRIES 5
63 
64 static int
65 read_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf)
66 {
67  int r;
68  uint8_t tries = READ_PORT_TRIES;
69 
70  buf->byte[0] = reg;
71  buf->byte[1] = 0;
72 
73  if(quarkX1000_i2c_write(buf->byte, 1, data->i2c_slave_addr) < 0) {
74  return -1;
75  }
76 
77  do {
78  clock_wait(READ_PORT_TIMEOUT);
79 
80  r = quarkX1000_i2c_read(buf->byte, 2, data->i2c_slave_addr);
81  if(r == 0) {
82  break;
83  }
84  } while(tries--);
85 
86  if(r < 0) {
87  return -1;
88  }
89 
90  return 0;
91 }
92 static int
93 write_port_regs(struct gpio_pcal9535a_data *data, uint8_t reg, union gpio_pcal9535a_port_data *buf)
94 {
95  uint8_t cmd[] = { reg, buf->byte[0], buf->byte[1] };
96 
97  if(quarkX1000_i2c_polling_write(cmd, sizeof(cmd), data->i2c_slave_addr) < 0) {
98  return -1;
99  }
100 
101  return 0;
102 }
103 static int
104 setup_pin_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
105 {
106  union gpio_pcal9535a_port_data *port = &data->reg_cache.dir;
107  uint16_t bit_mask, new_value = 0;
108 
109  bit_mask = 1 << pin;
110 
111  if((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) {
112  new_value = 1 << pin;
113  }
114 
115  port->all &= ~bit_mask;
116  port->all |= new_value;
117 
118  return write_port_regs(data, REG_CONF_PORT0, port);
119 }
120 static int
121 setup_pin_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
122 {
123  union gpio_pcal9535a_port_data *port;
124  uint16_t bit_mask, new_value = 0;
125 
126  if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
127  port = &data->reg_cache.pud_sel;
128  bit_mask = 1 << pin;
129 
130  if((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) {
131  new_value = 1 << pin;
132  }
133 
134  port->all &= ~bit_mask;
135  port->all |= new_value;
136 
137  if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) {
138  return -1;
139  }
140  }
141 
142  port = &data->reg_cache.pud_en;
143  bit_mask = 1 << pin;
144 
145  if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
146  new_value = 1 << pin;
147  }
148 
149  port->all &= ~bit_mask;
150  port->all |= new_value;
151 
152  return write_port_regs(data, REG_PUD_EN_PORT0, port);
153 }
154 static int
155 setup_pin_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
156 {
157  union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv;
158  uint16_t bit_mask, new_value = 0;
159 
160  bit_mask = 1 << pin;
161 
162  if((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) {
163  new_value = 1 << pin;
164  }
165 
166  port->all &= ~bit_mask;
167  port->all |= new_value;
168 
169  if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) {
170  return -1;
171  }
172 
173  data->out_pol_inv = port->all;
174 
175  return 0;
176 }
177 int
178 gpio_pcal9535a_write(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value)
179 {
180  union gpio_pcal9535a_port_data *port = &data->reg_cache.output;
181  uint16_t bit_mask, new_value;
182 
183  if(!quarkX1000_i2c_is_available()) {
184  return -1;
185  }
186 
187  bit_mask = 1 << pin;
188 
189  new_value = (value << pin) & bit_mask;
190  new_value ^= (data->out_pol_inv & bit_mask);
191  new_value &= bit_mask;
192 
193  port->all &= ~bit_mask;
194  port->all |= new_value;
195 
196  return write_port_regs(data, REG_OUTPUT_PORT0, port);
197 }
198 int
199 gpio_pcal9535a_read(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value)
200 {
201  union gpio_pcal9535a_port_data buf;
202 
203  if(!quarkX1000_i2c_is_available()) {
204  return -1;
205  }
206 
207  if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) {
208  return -1;
209  }
210 
211  *value = (buf.all >> pin) & 0x01;
212 
213  return 0;
214 }
215 int
216 gpio_pcal9535a_config(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
217 {
218  if(!quarkX1000_i2c_is_available()) {
219  return -1;
220  }
221 
222  if(setup_pin_dir(data, pin, flags) < 0) {
223  return -1;
224  }
225 
226  if(setup_pin_polarity(data, pin, flags) < 0) {
227  return -1;
228  }
229 
230  if(setup_pin_pullupdown(data, pin, flags) < 0) {
231  return -1;
232  }
233 
234  return 0;
235 }
236 static int
237 setup_port_dir(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
238 {
239  union gpio_pcal9535a_port_data *port = &data->reg_cache.dir;
240 
241  port->all = ((flags & QUARKX1000_GPIO_DIR_MASK) == QUARKX1000_GPIO_IN) ? 0xFFFF : 0x0;
242 
243  return write_port_regs(data, REG_CONF_PORT0, port);
244 }
245 static int
246 setup_port_pullupdown(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
247 {
248  union gpio_pcal9535a_port_data *port;
249 
250  if((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) {
251  port = &data->reg_cache.pud_sel;
252  port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) == QUARKX1000_GPIO_PUD_PULL_UP) ? 0xFFFF : 0x0;
253 
254  if(write_port_regs(data, REG_PUD_SEL_PORT0, port) < 0) {
255  return -1;
256  }
257  }
258 
259  port = &data->reg_cache.pud_en;
260  port->all = ((flags & QUARKX1000_GPIO_PUD_MASK) != QUARKX1000_GPIO_PUD_NORMAL) ? 0xFFFF : 0x0;
261 
262  return write_port_regs(data, REG_PUD_EN_PORT0, port);
263 }
264 static int
265 setup_port_polarity(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
266 {
267  union gpio_pcal9535a_port_data *port = &data->reg_cache.pol_inv;
268 
269  port->all = ((flags & QUARKX1000_GPIO_POL_MASK) == QUARKX1000_GPIO_POL_INV) ? 0xFFFF : 0x0;
270 
271  if(write_port_regs(data, REG_POL_INV_PORT0, port) < 0) {
272  return -1;
273  }
274 
275  data->out_pol_inv = port->all;
276 
277  return 0;
278 }
279 int
280 gpio_pcal9535a_write_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t value)
281 {
282  union gpio_pcal9535a_port_data *port = &data->reg_cache.output;
283  uint16_t bit_mask, new_value;
284 
285  if(!quarkX1000_i2c_is_available()) {
286  return -1;
287  }
288 
289  port->all = value;
290  bit_mask = data->out_pol_inv;
291 
292  new_value = value & bit_mask;
293  new_value ^= data->out_pol_inv;
294  new_value &= bit_mask;
295 
296  port->all &= ~bit_mask;
297  port->all |= new_value;
298 
299  return write_port_regs(data, REG_OUTPUT_PORT0, port);
300 }
301 int
302 gpio_pcal9535a_read_port(struct gpio_pcal9535a_data *data, uint32_t pin, uint32_t *value)
303 {
304  union gpio_pcal9535a_port_data buf;
305 
306  if(!quarkX1000_i2c_is_available()) {
307  return -1;
308  }
309 
310  if(read_port_regs(data, REG_INPUT_PORT0, &buf) < 0) {
311  return -1;
312  }
313 
314  *value = buf.all;
315 
316  return 0;
317 }
318 int
319 gpio_pcal9535a_config_port(struct gpio_pcal9535a_data *data, uint32_t pin, int flags)
320 {
321  if(!quarkX1000_i2c_is_available()) {
322  return -1;
323  }
324 
325  if(setup_port_dir(data, pin, flags) < 0) {
326  return -1;
327  }
328 
329  if(setup_port_polarity(data, pin, flags) < 0) {
330  return -1;
331  }
332 
333  if(setup_port_pullupdown(data, pin, flags) < 0) {
334  return -1;
335  }
336 
337  return 0;
338 }
339 int
340 gpio_pcal9535a_init(struct gpio_pcal9535a_data *data, uint16_t i2c_slave_addr)
341 {
342  /* has to init after I2C master */
343  if(!quarkX1000_i2c_is_available()) {
344  return -1;
345  }
346 
347  data->i2c_slave_addr = i2c_slave_addr;
348 
349  /* default for registers according to datasheet */
350  data->reg_cache.output.all = 0xFFFF;
351  data->reg_cache.pol_inv.all = 0x0;
352  data->reg_cache.dir.all = 0xFFFF;
353  data->reg_cache.pud_en.all = 0x0;
354  data->reg_cache.pud_sel.all = 0xFFFF;
355 
356  return 0;
357 }
void clock_wait(clock_time_t t)
Wait for a given number of ticks.
Definition: clock.c:162