1 /*
2  * Copyright (c) 2022 Chromium OS Authors
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #define DT_DRV_COMPAT ti_tca6424a
7 
8 #include <zephyr/drivers/gpio/gpio_utils.h>
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/i2c.h>
11 #include <zephyr/logging/log.h>
12 #include <zephyr/sys/byteorder.h>
13 #include <zephyr/sys/util.h>
14 LOG_MODULE_REGISTER(gpio_tca6424a, CONFIG_GPIO_LOG_LEVEL);
15 
16 /* TCA6424A auto increment register addresses */
17 #define TCA6424A_REG_INPUT			0x80
18 #define TCA6424A_REG_OUTPUT			0x84
19 #define TCA6424A_REG_POLARITY_INVERSION		0x88
20 #define TCA6424A_REG_CONFIGURATION		0x8C
21 
22 /** Cache of the output configuration and data of the pins. */
23 struct tca6424a_pins_state {
24 	uint32_t input;
25 	uint32_t output;
26 	uint32_t config;
27 };
28 
29 struct tca6424a_irq_state {
30 	uint32_t rising;
31 	uint32_t falling;
32 };
33 
34 /** Configuration data */
35 struct tca6424a_drv_cfg {
36 	/* gpio_driver_config needs to be first */
37 	struct gpio_driver_config common;
38 
39 	struct i2c_dt_spec i2c_spec;
40 	struct gpio_dt_spec int_gpio;
41 	struct gpio_dt_spec reset_gpio;
42 };
43 
44 /** Runtime driver data */
45 struct tca6424a_drv_data {
46 	/* gpio_driver_data needs to be first */
47 	struct gpio_driver_data common;
48 
49 	sys_slist_t callbacks;
50 	struct k_sem lock;
51 	struct k_work work;
52 	const struct device *dev;
53 	struct gpio_callback int_gpio_cb;
54 	struct tca6424a_pins_state pins_state;
55 	struct tca6424a_irq_state irq_state;
56 };
57 
58 /**
59  * @brief Gets the state of a specified block of 3 registers from the TCA6424A
60  * and stores it in specified cache and buffer variables.
61  *
62  * @param dev Pointer to the device structure for the driver instance.
63  * @param reg Address of the first of 3 registers to be read.
64  * @param cache Pointer to the location to cache the pins states.
65  * @param buf Pointer to the buffer to output the register.
66  *
67  * @retval 0 if successful.
68  * @retval Negative value for error code.
69  */
read_port_regs(const struct device * dev,uint8_t reg,uint32_t * buf)70 static int read_port_regs(const struct device *dev, uint8_t reg, uint32_t *buf)
71 {
72 	const struct tca6424a_drv_cfg *const config = dev->config;
73 	uint32_t port_data, value;
74 	int ret;
75 
76 	ret = i2c_burst_read_dt(&config->i2c_spec, reg, (uint8_t *)&port_data, 3);
77 	if (ret != 0) {
78 		LOG_ERR("%s: error reading register 0x%X (%d)", dev->name,
79 			reg, ret);
80 		return ret;
81 	}
82 
83 	value = sys_le24_to_cpu(port_data);
84 	*buf = value;
85 	LOG_DBG("%s: Read: REG[0x%X] = 0x%X, REG[0x%X] = 0x%X, "
86 		"REG[0x%X] = 0x%X",
87 		dev->name, reg, (*buf & 0xFF), (reg + 1), ((*buf >> 8) & 0xFF),
88 		(reg + 2), ((*buf >> 16) & 0xFF));
89 
90 	return 0;
91 }
92 
93 /**
94  * @brief writes to a specified block of 3 registers from the TCA6424A
95  * and stores it in a specified cache variable.
96  *
97  * @param dev Pointer to the device structure for the driver instance.
98  * @param reg Address of the first of 3 registers to be written.
99  * @param cache Pointer to the location to cache the pins states.
100  * @param value The pin value to be written into the registers.
101  *
102  * @retval 0 if successful.
103  * @retval Negative value for error code.
104  */
write_port_regs(const struct device * dev,uint8_t reg,uint32_t value)105 static int write_port_regs(const struct device *dev, uint8_t reg, uint32_t value)
106 {
107 	const struct tca6424a_drv_cfg *const config = dev->config;
108 	uint8_t buf[4];
109 	int ret;
110 
111 	LOG_DBG("%s: Write: REG[0x%X] = 0x%X, REG[0x%X] = 0x%X, "
112 		"REG[0x%X] = 0x%X",
113 		dev->name, reg, (value & 0xFF), (reg + 1), ((value >> 8) & 0xFF),
114 		(reg + 2), ((value >> 16) & 0xFF));
115 
116 	buf[0] = reg;
117 	sys_put_le24(value, &buf[1]);
118 	ret = i2c_write_dt(&config->i2c_spec, buf, sizeof(buf));
119 	if (ret != 0) {
120 		LOG_ERR("%s: error writing to register 0x%X "
121 			"(%d)",
122 			dev->name, reg, ret);
123 	}
124 	return ret;
125 }
126 
update_input_regs(const struct device * dev,uint32_t * buf)127 static inline int update_input_regs(const struct device *dev, uint32_t *buf)
128 {
129 	int ret;
130 	struct tca6424a_drv_data *const drv_data = dev->data;
131 
132 	ret = read_port_regs(dev, TCA6424A_REG_INPUT, buf);
133 	if (ret == 0) {
134 		drv_data->pins_state.input = *buf;
135 	}
136 
137 	return ret;
138 }
139 
update_output_regs(const struct device * dev,uint32_t value)140 static inline int update_output_regs(const struct device *dev, uint32_t value)
141 {
142 	int ret;
143 	struct tca6424a_drv_data *const drv_data = dev->data;
144 
145 	ret = write_port_regs(dev, TCA6424A_REG_OUTPUT, value);
146 	if (ret == 0) {
147 		drv_data->pins_state.output = value;
148 	}
149 
150 	return ret;
151 }
152 
update_invers_regs(const struct device * dev,uint32_t value)153 static inline int update_invers_regs(const struct device *dev, uint32_t value)
154 {
155 	return write_port_regs(dev, TCA6424A_REG_POLARITY_INVERSION, value);
156 }
157 
update_config_regs(const struct device * dev,uint32_t value)158 static inline int update_config_regs(const struct device *dev, uint32_t value)
159 {
160 	int ret;
161 	struct tca6424a_drv_data *const drv_data = dev->data;
162 
163 	ret = write_port_regs(dev, TCA6424A_REG_CONFIGURATION, value);
164 	if (ret == 0) {
165 		drv_data->pins_state.config = value;
166 	}
167 
168 	return ret;
169 }
170 
171 /**
172  * @brief Handles interrupt triggered by the interrupt pin of TCA6424A.
173  *
174  * If int_gpios is configured in device tree then this will be triggered each
175  * time a gpio configured as an input changes state. The gpio input states are
176  * read in this function which clears the interrupt.
177  *
178  * @param dev Pointer to the device structure for the driver instance.
179  */
tca6424a_handle_interrupt(const struct device * dev)180 static void tca6424a_handle_interrupt(const struct device *dev)
181 {
182 	struct tca6424a_drv_data *drv_data = dev->data;
183 	struct tca6424a_irq_state *irq_state = &drv_data->irq_state;
184 	int ret;
185 	uint32_t previous_state;
186 	uint32_t current_state;
187 	uint32_t transitioned_pins;
188 	uint32_t interrupt_status;
189 
190 	k_sem_take(&drv_data->lock, K_FOREVER);
191 
192 	/* Any interrupts enabled? */
193 	if (!irq_state->rising && !irq_state->falling) {
194 		k_sem_give(&drv_data->lock);
195 		return;
196 	}
197 
198 	/* Store previous input state then read new value */
199 	previous_state = drv_data->pins_state.input;
200 	ret = update_input_regs(dev, &current_state);
201 	if (ret != 0) {
202 		k_sem_give(&drv_data->lock);
203 		return;
204 	}
205 
206 	/* Find out which input pins have changed state */
207 	transitioned_pins = previous_state ^ current_state;
208 
209 	/* Mask gpio transactions with rising/falling edge interrupt config */
210 	interrupt_status = (irq_state->rising & transitioned_pins & current_state);
211 	interrupt_status |= (irq_state->falling & transitioned_pins & previous_state);
212 	k_sem_give(&drv_data->lock);
213 
214 	if (interrupt_status) {
215 		gpio_fire_callbacks(&drv_data->callbacks, dev, interrupt_status);
216 	}
217 }
218 
219 /**
220  * @brief Work handler for TCA6424A interrupt
221  *
222  * @param work Work struct that contains pointer to interrupt handler function
223  */
tca6424a_work_handler(struct k_work * work)224 static void tca6424a_work_handler(struct k_work *work)
225 {
226 	struct tca6424a_drv_data *drv_data = CONTAINER_OF(work, struct tca6424a_drv_data, work);
227 
228 	tca6424a_handle_interrupt(drv_data->dev);
229 }
230 
231 /**
232  * @brief ISR for interrupt pin of TCA6424A
233  *
234  * @param dev Pointer to the device structure for the driver instance.
235  * @param gpio_cb Pointer to callback function struct
236  * @param pins Bitmask of pins that triggered interrupt
237  */
tca6424a_int_gpio_handler(const struct device * dev,struct gpio_callback * gpio_cb,uint32_t pins)238 static void tca6424a_int_gpio_handler(const struct device *dev, struct gpio_callback *gpio_cb,
239 				      uint32_t pins)
240 {
241 	ARG_UNUSED(dev);
242 	ARG_UNUSED(pins);
243 
244 	struct tca6424a_drv_data *drv_data =
245 		CONTAINER_OF(gpio_cb, struct tca6424a_drv_data, int_gpio_cb);
246 
247 	k_work_submit(&drv_data->work);
248 }
249 
tca6424a_setup_pin(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)250 static int tca6424a_setup_pin(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
251 {
252 	struct tca6424a_drv_data *const drv_data = dev->data;
253 	uint32_t reg_cfg = drv_data->pins_state.config;
254 	uint32_t reg_out = drv_data->pins_state.output;
255 	int ret;
256 
257 	/* For each pin, 0 == output, 1 == input */
258 	if ((flags & GPIO_OUTPUT) != 0) {
259 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
260 			reg_out |= BIT(pin);
261 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
262 			reg_out &= ~BIT(pin);
263 		}
264 		ret = update_output_regs(dev, reg_out);
265 		if (ret != 0) {
266 			return ret;
267 		}
268 		reg_cfg &= ~BIT(pin);
269 	} else {
270 		reg_cfg |= BIT(pin);
271 	}
272 
273 	ret = update_config_regs(dev, reg_cfg);
274 
275 	return ret;
276 }
277 
tca6424a_pin_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)278 static int tca6424a_pin_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
279 {
280 	int ret;
281 	struct tca6424a_drv_data *const drv_data = dev->data;
282 
283 	/* Does not support disconnected pin */
284 	if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) {
285 		return -ENOTSUP;
286 	}
287 
288 	/* Single Ended lines (Open drain and open source) not supported */
289 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
290 		return -ENOTSUP;
291 	}
292 
293 	/* The TCA6424A has no internal pull up support */
294 	if (((flags & GPIO_PULL_UP) != 0) || ((flags & GPIO_PULL_DOWN) != 0)) {
295 		return -ENOTSUP;
296 	}
297 
298 	/* Simultaneous input & output mode not supported */
299 	if (((flags & GPIO_INPUT) != 0) && ((flags & GPIO_OUTPUT) != 0)) {
300 		return -ENOTSUP;
301 	}
302 
303 	/* Can't do I2C bus operations from an ISR */
304 	if (k_is_in_isr()) {
305 		return -EWOULDBLOCK;
306 	}
307 
308 	k_sem_take(&drv_data->lock, K_FOREVER);
309 
310 	ret = tca6424a_setup_pin(dev, pin, flags);
311 	if (ret != 0) {
312 		LOG_ERR("%s: error setting pin direction (%d)", dev->name, ret);
313 	}
314 
315 	k_sem_give(&drv_data->lock);
316 	return ret;
317 }
318 
tca6424a_port_get_raw(const struct device * dev,gpio_port_value_t * value)319 static int tca6424a_port_get_raw(const struct device *dev, gpio_port_value_t *value)
320 {
321 	struct tca6424a_drv_data *const drv_data = dev->data;
322 	uint32_t buf;
323 	int ret;
324 
325 	/* Can't do I2C bus operations from an ISR */
326 	if (k_is_in_isr()) {
327 		return -EWOULDBLOCK;
328 	}
329 
330 	k_sem_take(&drv_data->lock, K_FOREVER);
331 
332 	ret = update_input_regs(dev, &buf);
333 	if (ret == 0) {
334 		*value = buf;
335 	}
336 
337 	k_sem_give(&drv_data->lock);
338 	return ret;
339 }
340 
tca6424a_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)341 static int tca6424a_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
342 					gpio_port_value_t value)
343 {
344 	struct tca6424a_drv_data *const drv_data = dev->data;
345 	uint32_t reg_out;
346 	int ret;
347 
348 	/* Can't do I2C bus operations from an ISR */
349 	if (k_is_in_isr()) {
350 		return -EWOULDBLOCK;
351 	}
352 
353 	k_sem_take(&drv_data->lock, K_FOREVER);
354 
355 	reg_out = drv_data->pins_state.output;
356 	reg_out = (reg_out & ~mask) | (mask & value);
357 
358 	ret = update_output_regs(dev, reg_out);
359 
360 	k_sem_give(&drv_data->lock);
361 
362 	return ret;
363 }
364 
tca6424a_port_set_bits_raw(const struct device * dev,gpio_port_pins_t mask)365 static int tca6424a_port_set_bits_raw(const struct device *dev, gpio_port_pins_t mask)
366 {
367 	return tca6424a_port_set_masked_raw(dev, mask, mask);
368 }
369 
tca6424a_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t mask)370 static int tca6424a_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t mask)
371 {
372 	return tca6424a_port_set_masked_raw(dev, mask, 0);
373 }
374 
tca6424a_port_toggle_bits(const struct device * dev,gpio_port_pins_t mask)375 static int tca6424a_port_toggle_bits(const struct device *dev, gpio_port_pins_t mask)
376 {
377 	struct tca6424a_drv_data *const drv_data = dev->data;
378 	uint32_t reg_out;
379 	int ret;
380 
381 	/* Can't do I2C bus operations from an ISR */
382 	if (k_is_in_isr()) {
383 		return -EWOULDBLOCK;
384 	}
385 
386 	k_sem_take(&drv_data->lock, K_FOREVER);
387 
388 	reg_out = drv_data->pins_state.output;
389 	reg_out ^= mask;
390 
391 	ret = update_output_regs(dev, reg_out);
392 
393 	k_sem_give(&drv_data->lock);
394 
395 	return ret;
396 }
397 
tca6424a_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)398 static int tca6424a_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
399 					    enum gpio_int_mode mode, enum gpio_int_trig trig)
400 {
401 	struct tca6424a_drv_data *drv_data = dev->data;
402 	struct tca6424a_irq_state *irq = &drv_data->irq_state;
403 
404 	/* Device does not support level-triggered interrupts. */
405 	if (mode == GPIO_INT_MODE_LEVEL) {
406 		return -ENOTSUP;
407 	}
408 
409 	k_sem_take(&drv_data->lock, K_FOREVER);
410 
411 	if (mode == GPIO_INT_MODE_DISABLED) {
412 		irq->falling &= ~BIT(pin);
413 		irq->rising &= ~BIT(pin);
414 	} else { /* GPIO_INT_MODE_EDGE */
415 		if (trig == GPIO_INT_TRIG_BOTH) {
416 			irq->falling |= BIT(pin);
417 			irq->rising |= BIT(pin);
418 		} else if (trig == GPIO_INT_TRIG_LOW) {
419 			irq->falling |= BIT(pin);
420 			irq->rising &= ~BIT(pin);
421 		} else if (trig == GPIO_INT_TRIG_HIGH) {
422 			irq->falling &= ~BIT(pin);
423 			irq->rising |= BIT(pin);
424 		}
425 	}
426 
427 	k_sem_give(&drv_data->lock);
428 
429 	return 0;
430 }
431 
tca6424a_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)432 static int tca6424a_manage_callback(const struct device *dev, struct gpio_callback *callback,
433 				    bool set)
434 {
435 	struct tca6424a_drv_data *drv_data = dev->data;
436 
437 	return gpio_manage_callback(&drv_data->callbacks, callback, set);
438 }
439 
440 static const struct gpio_driver_api tca6424a_drv_api = {
441 	.pin_configure = tca6424a_pin_config,
442 	.port_get_raw = tca6424a_port_get_raw,
443 	.port_set_masked_raw = tca6424a_port_set_masked_raw,
444 	.port_set_bits_raw = tca6424a_port_set_bits_raw,
445 	.port_clear_bits_raw = tca6424a_port_clear_bits_raw,
446 	.port_toggle_bits = tca6424a_port_toggle_bits,
447 	.pin_interrupt_configure = tca6424a_pin_interrupt_configure,
448 	.manage_callback = tca6424a_manage_callback,
449 };
450 
451 /**
452  * @brief Initialization function of TCA6424A
453  *
454  * This sets initial input/output configuration and output states.
455  * The interrupt is configured if it is enabled.
456  *
457  * @param dev Device struct
458  *
459  * @retval 0 if successful.
460  * @retval Negative value for error code.
461  */
tca6424a_init(const struct device * dev)462 static int tca6424a_init(const struct device *dev)
463 {
464 	const struct tca6424a_drv_cfg *drv_cfg = dev->config;
465 	struct tca6424a_drv_data *drv_data = dev->data;
466 	int ret;
467 
468 	if (!device_is_ready(drv_cfg->i2c_spec.bus)) {
469 		LOG_ERR("I2C device not found");
470 		return -ENODEV;
471 	}
472 	/* If the RESET line is available, use it to reset the expander.
473 	 * Otherwise, write reset values to registers that are not used by
474 	 * this driver.
475 	 */
476 	if (drv_cfg->reset_gpio.port) {
477 		if (!gpio_is_ready_dt(&drv_cfg->reset_gpio)) {
478 			LOG_ERR("%s is not ready", drv_cfg->reset_gpio.port->name);
479 			return -ENODEV;
480 		}
481 		ret = gpio_pin_configure_dt(&drv_cfg->reset_gpio, GPIO_OUTPUT_ACTIVE);
482 		if (ret != 0) {
483 			LOG_ERR("%s: failed to configure RESET line: %d", dev->name, ret);
484 			return ret;
485 		}
486 		/* RESET signal needs to be active for a minimum of 30 ns. */
487 		k_busy_wait(1);
488 
489 		ret = gpio_pin_set_dt(&drv_cfg->reset_gpio, 0);
490 		if (ret != 0) {
491 			LOG_ERR("%s: failed to deactivate RESET line: %d", dev->name, ret);
492 			return ret;
493 		}
494 		/* Give the expander at least 200 ns to recover after reset. */
495 		k_busy_wait(1);
496 	} else {
497 		ret = update_invers_regs(dev, 0x0);
498 		if (ret != 0) {
499 			LOG_ERR("%s: failed to reset inversion register: %d", dev->name, ret);
500 			return ret;
501 		}
502 	}
503 	/* Set initial configuration of the pins. */
504 	ret = update_config_regs(dev, 0xFFFFFF);
505 	if (ret != 0) {
506 		return ret;
507 	}
508 
509 	ret = update_output_regs(dev, 0x0);
510 	if (ret != 0) {
511 		return ret;
512 	}
513 
514 	/* Read initial state of the input port register. */
515 	ret = update_input_regs(dev, &drv_data->pins_state.input);
516 	if (ret != 0) {
517 		LOG_ERR("%s: failed to initially read input port: %d", dev->name, ret);
518 		return ret;
519 	}
520 
521 	/* If the INT line is available, configure the callback for it. */
522 	if (drv_cfg->int_gpio.port) {
523 		if (!gpio_is_ready_dt(&drv_cfg->int_gpio)) {
524 			LOG_ERR("Cannot get pointer to gpio interrupt device "
525 				"%s init failed", dev->name);
526 			return -EINVAL;
527 		}
528 
529 		drv_data->dev = dev;
530 
531 		k_work_init(&drv_data->work, tca6424a_work_handler);
532 
533 		ret = gpio_pin_configure_dt(&drv_cfg->int_gpio, GPIO_INPUT);
534 		if (ret != 0) {
535 			LOG_ERR("%s init failed: %d", dev->name, ret);
536 			return ret;
537 		}
538 
539 		ret = gpio_pin_interrupt_configure_dt(&drv_cfg->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
540 		if (ret != 0) {
541 			LOG_ERR("%s init failed: %d", dev->name, ret);
542 			return ret;
543 		}
544 
545 		gpio_init_callback(&drv_data->int_gpio_cb, tca6424a_int_gpio_handler,
546 				   BIT(drv_cfg->int_gpio.pin));
547 
548 		ret = gpio_add_callback(drv_cfg->int_gpio.port, &drv_data->int_gpio_cb);
549 		if (ret != 0) {
550 			LOG_ERR("%s init failed: %d", dev->name, ret);
551 			return ret;
552 		}
553 	}
554 
555 	LOG_DBG("%s init ok", dev->name);
556 	return ret;
557 }
558 
559 #define TCA6424A_INST(idx)                                                                         \
560 	static const struct tca6424a_drv_cfg tca6424a_cfg##idx = {                                 \
561 		.common = {                                                                        \
562 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(idx),                     \
563 		},                                                                                 \
564 		.i2c_spec = I2C_DT_SPEC_INST_GET(idx),                                             \
565 		.int_gpio = GPIO_DT_SPEC_INST_GET_OR(idx, int_gpios, {0}),                         \
566 		.reset_gpio = GPIO_DT_SPEC_INST_GET_OR(idx, reset_gpios, {0}),                     \
567 	};                                                                                         \
568 	static struct tca6424a_drv_data tca6424a_data##idx = {                                     \
569 		.lock = Z_SEM_INITIALIZER(tca6424a_data##idx.lock, 1, 1),                          \
570 		.work = Z_WORK_INITIALIZER(tca6424a_work_handler),                                 \
571 		.dev = DEVICE_DT_INST_GET(idx),                                                    \
572 	};                                                                                         \
573 	DEVICE_DT_INST_DEFINE(idx, tca6424a_init, NULL, &tca6424a_data##idx, &tca6424a_cfg##idx,   \
574 			      POST_KERNEL, CONFIG_GPIO_TCA6424A_INIT_PRIORITY, &tca6424a_drv_api);
575 
576 DT_INST_FOREACH_STATUS_OKAY(TCA6424A_INST)
577