1 /*
2 * Copyright (c) 2018 Peter Bigot Consulting, LLC
3 * Copyright (c) 2018 Aapo Vienamo
4 * Copyright (c) 2019 Nordic Semiconductor ASA
5 * Copyright (c) 2019 Vestas Wind Systems A/S
6 * Copyright (c) 2020 ZedBlox Ltd.
7 * Copyright (c) 2021 Laird Connectivity
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <errno.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/device.h>
15 #include <zephyr/init.h>
16 #include <zephyr/drivers/gpio.h>
17 #include <zephyr/drivers/i2c.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/sys/util.h>
20
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(pca953x, CONFIG_GPIO_LOG_LEVEL);
23
24 #include <zephyr/drivers/gpio/gpio_utils.h>
25
26 /* PCA953X Register addresses */
27 #define PCA953X_INPUT_PORT 0x00
28 #define PCA953X_OUTPUT_PORT 0x01
29 #define PCA953X_CONFIGURATION 0x03
30
31 /* Number of pins supported by the device */
32 #define NUM_PINS 8
33
34 /* Max to select all pins supported on the device. */
35 #define ALL_PINS ((uint8_t)BIT_MASK(NUM_PINS))
36
37 /** Cache of the output configuration and data of the pins. */
38 struct pca953x_pin_state {
39 uint8_t dir;
40 uint8_t input;
41 uint8_t output;
42 };
43
44 struct pca953x_irq_state {
45 uint8_t rising;
46 uint8_t falling;
47 };
48
49 /** Runtime driver data */
50 struct pca953x_drv_data {
51 /* gpio_driver_data needs to be first */
52 struct gpio_driver_data common;
53 struct pca953x_pin_state pin_state;
54 struct k_sem lock;
55 struct gpio_callback gpio_cb;
56 struct k_work work;
57 struct pca953x_irq_state irq_state;
58 const struct device *dev;
59 /* user ISR cb */
60 sys_slist_t cb;
61 };
62
63 /** Configuration data */
64 struct pca953x_config {
65 /* gpio_driver_config needs to be first */
66 struct gpio_driver_config common;
67 struct i2c_dt_spec i2c;
68 const struct gpio_dt_spec gpio_int;
69 bool interrupt_enabled;
70 };
71
72 /**
73 * @brief Gets the state of input pins of the PCA953X I/O Port and
74 * stores in driver data struct.
75 *
76 * @param dev Pointer to the device structure for the driver instance.
77 *
78 * @retval 0 If successful.
79 * @retval Negative value for error code.
80 */
update_input(const struct device * dev)81 static int update_input(const struct device *dev)
82 {
83 const struct pca953x_config *cfg = dev->config;
84 struct pca953x_drv_data *drv_data = dev->data;
85 uint8_t input_states;
86 int rc = 0;
87
88 rc = i2c_reg_read_byte_dt(&cfg->i2c, PCA953X_INPUT_PORT, &input_states);
89
90 if (rc == 0) {
91 drv_data->pin_state.input = input_states;
92 }
93 return rc;
94 }
95
96 /**
97 * @brief Handles interrupt triggered by the interrupt pin of PCA953X I/O Port.
98 *
99 * If nint_gpios is configured in device tree then this will be triggered each
100 * time a gpio configured as an input changes state. The gpio input states are
101 * read in this function which clears the interrupt.
102 *
103 * @param dev Pointer to the device structure for the driver instance.
104 */
gpio_pca953x_handle_interrupt(const struct device * dev)105 static void gpio_pca953x_handle_interrupt(const struct device *dev)
106 {
107 struct pca953x_drv_data *drv_data = dev->data;
108 struct pca953x_irq_state *irq_state = &drv_data->irq_state;
109 int rc;
110 uint8_t previous_state;
111 uint8_t current_state;
112 uint8_t transitioned_pins;
113 uint8_t interrupt_status = 0;
114
115 k_sem_take(&drv_data->lock, K_FOREVER);
116
117 /* Any interrupts enabled? */
118 if (!irq_state->rising && !irq_state->falling) {
119 rc = -EINVAL;
120 goto out;
121 }
122
123 /* Store previous input state then read new value */
124 previous_state = drv_data->pin_state.input;
125 rc = update_input(dev);
126 if (rc != 0) {
127 goto out;
128 }
129
130 /* Find out which input pins have changed state */
131 current_state = drv_data->pin_state.input;
132 transitioned_pins = previous_state ^ current_state;
133
134 /* Mask gpio transactions with rising/falling edge interrupt config */
135 interrupt_status = (irq_state->rising & transitioned_pins &
136 current_state);
137 interrupt_status |= (irq_state->falling & transitioned_pins &
138 previous_state);
139
140 out:
141 k_sem_give(&drv_data->lock);
142
143 if ((rc == 0) && (interrupt_status)) {
144 gpio_fire_callbacks(&drv_data->cb, dev, interrupt_status);
145 }
146 }
147
148 /**
149 * @brief Work handler for PCA953X interrupt
150 *
151 * @param work Work struct that contains pointer to interrupt handler function
152 */
gpio_pca953x_work_handler(struct k_work * work)153 static void gpio_pca953x_work_handler(struct k_work *work)
154 {
155 struct pca953x_drv_data *drv_data =
156 CONTAINER_OF(work, struct pca953x_drv_data, work);
157
158 gpio_pca953x_handle_interrupt(drv_data->dev);
159 }
160
161 /**
162 * @brief ISR for interrupt pin of PCA953X
163 *
164 * @param dev Pointer to the device structure for the driver instance.
165 * @param gpio_cb Pointer to callback function struct
166 * @param pins Bitmask of pins that triggered interrupt
167 */
gpio_pca953x_init_cb(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)168 static void gpio_pca953x_init_cb(const struct device *dev,
169 struct gpio_callback *gpio_cb, uint32_t pins)
170 {
171 struct pca953x_drv_data *drv_data =
172 CONTAINER_OF(gpio_cb, struct pca953x_drv_data, gpio_cb);
173
174 ARG_UNUSED(pins);
175
176 k_work_submit(&drv_data->work);
177 }
178
gpio_pca953x_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)179 static int gpio_pca953x_config(const struct device *dev, gpio_pin_t pin,
180 gpio_flags_t flags)
181 {
182 const struct pca953x_config *cfg = dev->config;
183 struct pca953x_drv_data *drv_data = dev->data;
184 struct pca953x_pin_state *pins = &drv_data->pin_state;
185 int rc = 0;
186 bool data_first = false;
187
188 /* Can't do I2C bus operations from an ISR */
189 if (k_is_in_isr()) {
190 return -EWOULDBLOCK;
191 }
192
193 /* Single Ended lines (Open drain and open source) not supported */
194 if ((flags & GPIO_SINGLE_ENDED) != 0) {
195 return -ENOTSUP;
196 }
197
198 /* The PCA953X has no internal pull up support */
199 if (((flags & GPIO_PULL_UP) != 0) || ((flags & GPIO_PULL_DOWN) != 0)) {
200 return -ENOTSUP;
201 }
202
203 /* Simultaneous input & output mode not supported */
204 if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
205 return -ENOTSUP;
206 }
207
208 k_sem_take(&drv_data->lock, K_FOREVER);
209
210 /* Ensure either Output or Input is specified */
211 if ((flags & GPIO_OUTPUT) != 0) {
212 pins->dir &= ~BIT(pin);
213 if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
214 pins->output &= ~BIT(pin);
215 data_first = true;
216 } else if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
217 pins->output |= BIT(pin);
218 data_first = true;
219 }
220 } else if ((flags & GPIO_INPUT) != 0) {
221 pins->dir |= BIT(pin);
222 } else {
223 rc = -ENOTSUP;
224 goto out;
225 }
226
227 /* Set output values */
228 if (data_first) {
229 rc = i2c_reg_write_byte_dt(&cfg->i2c, PCA953X_OUTPUT_PORT, pins->output);
230 }
231
232 if (rc == 0) {
233 /* Set pin directions */
234 rc = i2c_reg_write_byte_dt(&cfg->i2c, PCA953X_CONFIGURATION, pins->dir);
235 }
236
237 if (rc == 0) {
238 /* Refresh input status */
239 rc = update_input(dev);
240 }
241
242 out:
243 k_sem_give(&drv_data->lock);
244 return rc;
245 }
246
gpio_pca953x_port_read(const struct device * dev,gpio_port_value_t * value)247 static int gpio_pca953x_port_read(const struct device *dev,
248 gpio_port_value_t *value)
249 {
250 const struct pca953x_config *cfg = dev->config;
251 struct pca953x_drv_data *drv_data = dev->data;
252 uint8_t input_pin_data;
253 int rc = 0;
254
255 /* Can't do I2C bus operations from an ISR */
256 if (k_is_in_isr()) {
257 return -EWOULDBLOCK;
258 }
259
260 k_sem_take(&drv_data->lock, K_FOREVER);
261
262 /* Read Input Register */
263 rc = i2c_reg_read_byte_dt(&cfg->i2c, PCA953X_INPUT_PORT, &input_pin_data);
264
265 LOG_DBG("read %x got %d", input_pin_data, rc);
266
267 if (rc == 0) {
268 drv_data->pin_state.input = input_pin_data;
269 *value = (gpio_port_value_t)(drv_data->pin_state.input);
270 }
271
272 k_sem_give(&drv_data->lock);
273 return rc;
274 }
275
gpio_pca953x_port_write(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value,gpio_port_value_t toggle)276 static int gpio_pca953x_port_write(const struct device *dev,
277 gpio_port_pins_t mask,
278 gpio_port_value_t value,
279 gpio_port_value_t toggle)
280 {
281 const struct pca953x_config *cfg = dev->config;
282 struct pca953x_drv_data *drv_data = dev->data;
283 uint8_t *outp = &drv_data->pin_state.output;
284 int rc;
285 uint8_t orig_out;
286 uint8_t out;
287
288 /* Can't do I2C bus operations from an ISR */
289 if (k_is_in_isr()) {
290 return -EWOULDBLOCK;
291 }
292
293 k_sem_take(&drv_data->lock, K_FOREVER);
294
295 orig_out = *outp;
296 out = ((orig_out & ~mask) | (value & mask)) ^ toggle;
297
298 rc = i2c_reg_write_byte_dt(&cfg->i2c, PCA953X_OUTPUT_PORT, out);
299
300 if (rc == 0) {
301 *outp = out;
302 }
303
304 k_sem_give(&drv_data->lock);
305
306 LOG_DBG("write %x msk %08x val %08x => %x: %d", orig_out, mask,
307 value, out, rc);
308
309 return rc;
310 }
311
gpio_pca953x_port_set_masked(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)312 static int gpio_pca953x_port_set_masked(const struct device *dev,
313 gpio_port_pins_t mask,
314 gpio_port_value_t value)
315 {
316 return gpio_pca953x_port_write(dev, mask, value, 0);
317 }
318
gpio_pca953x_port_set_bits(const struct device * dev,gpio_port_pins_t pins)319 static int gpio_pca953x_port_set_bits(const struct device *dev,
320 gpio_port_pins_t pins)
321 {
322 return gpio_pca953x_port_write(dev, pins, pins, 0);
323 }
324
gpio_pca953x_port_clear_bits(const struct device * dev,gpio_port_pins_t pins)325 static int gpio_pca953x_port_clear_bits(const struct device *dev,
326 gpio_port_pins_t pins)
327 {
328 return gpio_pca953x_port_write(dev, pins, 0, 0);
329 }
330
gpio_pca953x_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)331 static int gpio_pca953x_port_toggle_bits(const struct device *dev,
332 gpio_port_pins_t pins)
333 {
334 return gpio_pca953x_port_write(dev, 0, 0, pins);
335 }
336
gpio_pca953x_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)337 static int gpio_pca953x_pin_interrupt_configure(const struct device *dev,
338 gpio_pin_t pin,
339 enum gpio_int_mode mode,
340 enum gpio_int_trig trig)
341 {
342 const struct pca953x_config *cfg = dev->config;
343 struct pca953x_drv_data *drv_data = dev->data;
344 struct pca953x_irq_state *irq = &drv_data->irq_state;
345
346 if (!cfg->interrupt_enabled) {
347 return -ENOTSUP;
348 }
349 /* Device does not support level-triggered interrupts. */
350 if (mode == GPIO_INT_MODE_LEVEL) {
351 return -ENOTSUP;
352 }
353
354 k_sem_take(&drv_data->lock, K_FOREVER);
355
356 if (mode == GPIO_INT_MODE_DISABLED) {
357 irq->falling &= ~BIT(pin);
358 irq->rising &= ~BIT(pin);
359 } else { /* GPIO_INT_MODE_EDGE */
360 if (trig == GPIO_INT_TRIG_BOTH) {
361 irq->falling |= BIT(pin);
362 irq->rising |= BIT(pin);
363 } else if (trig == GPIO_INT_TRIG_LOW) {
364 irq->falling |= BIT(pin);
365 irq->rising &= ~BIT(pin);
366 } else if (trig == GPIO_INT_TRIG_HIGH) {
367 irq->falling &= ~BIT(pin);
368 irq->rising |= BIT(pin);
369 }
370 }
371
372 k_sem_give(&drv_data->lock);
373
374 return 0;
375 }
376
gpio_pca953x_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)377 static int gpio_pca953x_manage_callback(const struct device *dev,
378 struct gpio_callback *callback,
379 bool set)
380 {
381 struct pca953x_drv_data *data = dev->data;
382
383 return gpio_manage_callback(&data->cb, callback, set);
384 }
385
386 /**
387 * @brief Initialization function of PCA953X
388 *
389 * This sets initial input/ output configuration and output states.
390 * The interrupt is configured if this is enabled.
391 *
392 * @param dev Device struct
393 * @return 0 if successful, failed otherwise.
394 */
gpio_pca953x_init(const struct device * dev)395 static int gpio_pca953x_init(const struct device *dev)
396 {
397 const struct pca953x_config *cfg = dev->config;
398 struct pca953x_drv_data *drv_data = dev->data;
399 int rc = 0;
400
401 if (!device_is_ready(cfg->i2c.bus)) {
402 LOG_ERR("I2C bus device not found");
403 goto out;
404 }
405
406 /* Do an initial read, this clears the interrupt pin and sets
407 * up the initial value of the pin state input data.
408 */
409 rc = update_input(dev);
410 if (rc) {
411 goto out;
412 }
413
414 if (cfg->interrupt_enabled) {
415 if (!device_is_ready(cfg->gpio_int.port)) {
416 LOG_ERR("Cannot get pointer to gpio interrupt device");
417 rc = -EINVAL;
418 goto out;
419 }
420
421 drv_data->dev = dev;
422
423 k_work_init(&drv_data->work, gpio_pca953x_work_handler);
424
425 rc = gpio_pin_configure_dt(&cfg->gpio_int, GPIO_INPUT);
426 if (rc) {
427 goto out;
428 }
429
430 rc = gpio_pin_interrupt_configure_dt(&cfg->gpio_int,
431 GPIO_INT_EDGE_TO_ACTIVE);
432 if (rc) {
433 goto out;
434 }
435
436 gpio_init_callback(&drv_data->gpio_cb,
437 gpio_pca953x_init_cb,
438 BIT(cfg->gpio_int.pin));
439
440 rc = gpio_add_callback(cfg->gpio_int.port,
441 &drv_data->gpio_cb);
442 }
443 out:
444 if (rc) {
445 LOG_ERR("%s init failed: %d", dev->name, rc);
446 } else {
447 LOG_INF("%s init ok", dev->name);
448 }
449 return rc;
450 }
451
452 static const struct gpio_driver_api api_table = {
453 .pin_configure = gpio_pca953x_config,
454 .port_get_raw = gpio_pca953x_port_read,
455 .port_set_masked_raw = gpio_pca953x_port_set_masked,
456 .port_set_bits_raw = gpio_pca953x_port_set_bits,
457 .port_clear_bits_raw = gpio_pca953x_port_clear_bits,
458 .port_toggle_bits = gpio_pca953x_port_toggle_bits,
459 .pin_interrupt_configure = gpio_pca953x_pin_interrupt_configure,
460 .manage_callback = gpio_pca953x_manage_callback,
461 };
462
463 #define GPIO_PCA953X_INIT(n) \
464 static const struct pca953x_config pca953x_cfg_##n = { \
465 .i2c = I2C_DT_SPEC_INST_GET(n), \
466 .common = { \
467 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
468 }, \
469 .interrupt_enabled = DT_INST_NODE_HAS_PROP(n, nint_gpios), \
470 .gpio_int = GPIO_DT_SPEC_INST_GET_OR(n, nint_gpios, {0}), \
471 }; \
472 \
473 static struct pca953x_drv_data pca953x_drvdata_##n = { \
474 .lock = Z_SEM_INITIALIZER(pca953x_drvdata_##n.lock, 1, 1), \
475 .pin_state.dir = ALL_PINS, \
476 .pin_state.output = ALL_PINS, \
477 }; \
478 DEVICE_DT_INST_DEFINE(n, \
479 gpio_pca953x_init, \
480 NULL, \
481 &pca953x_drvdata_##n, \
482 &pca953x_cfg_##n, \
483 POST_KERNEL, \
484 CONFIG_GPIO_PCA953X_INIT_PRIORITY, \
485 &api_table);
486
487 #define DT_DRV_COMPAT ti_tca9538
488 DT_INST_FOREACH_STATUS_OKAY(GPIO_PCA953X_INIT)
489