1 /*
2  * Copyright (c) 2024 TOKITA Hiroshi
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT awinic_aw9523b_gpio
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/gpio/gpio_utils.h>
12 #include <zephyr/drivers/i2c.h>
13 #include <zephyr/drivers/mfd/aw9523b.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/sys/ring_buffer.h>
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(gpio_aw9523b, CONFIG_GPIO_LOG_LEVEL);
19 
20 #define AW9523B_GPOMD             BIT(4)
21 #define AW9523B_RESET_PULSE_WIDTH 20
22 #define AW9523B_REG_CONFIG(n)     (AW9523B_REG_CONFIG0 + n)
23 #define AW9523B_REG_INT(n)        (AW9523B_REG_INT0 + n)
24 #define AW9523B_REG_OUTPUT(n)     (AW9523B_REG_OUTPUT0 + n)
25 
26 enum read_write_toggle_t {
27 	READ,
28 	WRITE,
29 	TOGGLE,
30 };
31 
32 struct gpio_aw9523b_config {
33 	struct gpio_driver_config common;
34 	const struct device *mfd_dev;
35 	struct i2c_dt_spec i2c;
36 	bool port0_push_pull;
37 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
38 	struct gpio_dt_spec reset_gpio;
39 #endif
40 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
41 	struct gpio_dt_spec int_gpio;
42 	gpio_callback_handler_t int_cb;
43 #endif
44 };
45 
46 struct gpio_aw9523b_data {
47 	struct gpio_driver_data common;
48 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
49 	const struct device *dev;
50 	sys_slist_t callbacks;
51 	struct gpio_callback gpio_callback;
52 	struct k_work intr_worker;
53 	gpio_port_value_t prev_value;
54 	gpio_port_pins_t rising_event_pins;
55 	gpio_port_pins_t falling_event_pins;
56 #endif
57 };
58 
gpio_aw9523b_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)59 static int gpio_aw9523b_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
60 {
61 	const struct gpio_aw9523b_config *const config = dev->config;
62 	const uint8_t port = (pin < 8) ? 0 : 1;
63 	const uint8_t mask = BIT(pin % 8);
64 	const uint8_t input_en = (flags & GPIO_INPUT) ? mask : 0x00;
65 	const uint8_t out_high = (flags & GPIO_OUTPUT_INIT_HIGH) ? mask : 0x00;
66 	int err;
67 
68 	/* Can't do I2C operations from an ISR */
69 	if (k_is_in_isr()) {
70 		return -EWOULDBLOCK;
71 	}
72 
73 	/* Either INPUT or OUTPUT must be set */
74 	if ((!(flags & GPIO_INPUT) && !(flags & GPIO_OUTPUT)) ||
75 	    ((flags & GPIO_INPUT) && (flags & GPIO_OUTPUT))) {
76 		return -ENOTSUP;
77 	}
78 
79 	/* Open-drain support is per port, not per pin.
80 	 * So can't really support the API as-is.
81 	 */
82 	if (port == 0 && !config->port0_push_pull) {
83 		if (!((flags & GPIO_SINGLE_ENDED) && (flags & GPIO_LINE_OPEN_DRAIN))) {
84 			return -ENOTSUP;
85 		}
86 	} else {
87 		if (flags & GPIO_SINGLE_ENDED) {
88 			return -ENOTSUP;
89 		}
90 	}
91 
92 	if ((flags & GPIO_INPUT) && ((flags & GPIO_PULL_UP) || (flags & GPIO_PULL_DOWN))) {
93 		return -ENOTSUP;
94 	}
95 
96 	k_sem_take(aw9523b_get_lock(config->mfd_dev), K_FOREVER);
97 
98 	err = i2c_reg_update_byte_dt(&config->i2c, AW9523B_REG_CONFIG(port), mask, input_en);
99 	if (err) {
100 		LOG_ERR("%s: Failed to set pin%d direction (%d)", dev->name, pin, err);
101 		goto on_error;
102 	}
103 
104 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
105 	if (config->int_gpio.port) {
106 		if (input_en) {
107 			struct gpio_aw9523b_data *const data = dev->data;
108 			uint8_t buf[2];
109 
110 			/* Read initial pin state */
111 			err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT0, buf, sizeof(buf));
112 			if (err) {
113 				LOG_ERR("%s: Read initial pin state failed (%d)", dev->name, err);
114 				goto on_error;
115 			}
116 
117 			WRITE_BIT(data->prev_value, pin, sys_get_le16(buf) & BIT(pin));
118 		} else {
119 			struct gpio_aw9523b_data *const data = dev->data;
120 
121 			WRITE_BIT(data->falling_event_pins, pin, 0);
122 			WRITE_BIT(data->rising_event_pins, pin, 0);
123 		}
124 	}
125 #endif
126 
127 	err = i2c_reg_update_byte_dt(&config->i2c, AW9523B_REG_OUTPUT(port), mask, out_high);
128 	if (err) {
129 		LOG_ERR("%s: Failed to set initial pin state (%d)", dev->name, err);
130 		return err;
131 	}
132 
133 on_error:
134 	k_sem_give(aw9523b_get_lock(config->mfd_dev));
135 
136 	return err;
137 }
138 
139 /**
140  * Common implementation of Read, Write, and Toggle
141  *
142  * @param[in]       dev Specify device instance.
143  * @param[in]      mask Register mask to select pins to operate.
144  * @param[in,out] value When mode is READ, this param is pointer to result value storing region.
145  *                      When mode is WRITE, this param is used as input value.
146  *                      When mode is TOGGLE, this param will ignored.
147  * @param[in]      mode Choose mode from READ, WRITE or TOGGLE.
148  */
gpio_aw9523b_port_read_write_toggle(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t * value,enum read_write_toggle_t mode)149 static int gpio_aw9523b_port_read_write_toggle(const struct device *dev, gpio_port_pins_t mask,
150 					       gpio_port_value_t *value,
151 					       enum read_write_toggle_t mode)
152 {
153 	const struct gpio_aw9523b_config *const config = dev->config;
154 	uint8_t buf[2];
155 	gpio_port_value_t old_value;
156 	gpio_port_value_t new_value;
157 	int err;
158 
159 	/* Can't do I2C bus operations from an ISR */
160 	if (k_is_in_isr()) {
161 		return -EWOULDBLOCK;
162 	}
163 
164 	k_sem_take(aw9523b_get_lock(config->mfd_dev), K_FOREVER);
165 
166 	/*
167 	 * As with interrupts, the INPUT values are read for each address
168 	 * to keep the internal state correct.
169 	 */
170 	err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT0, &buf[0], 1);
171 	if (err) {
172 		LOG_ERR("%s: Failed to read port0 status (%d)", dev->name, err);
173 		goto end;
174 	}
175 	err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT1, &buf[1], 1);
176 	if (err) {
177 		LOG_ERR("%s: Failed to read port1 status (%d)", dev->name, err);
178 		goto end;
179 	}
180 
181 	if (mode == READ) {
182 		goto end;
183 	}
184 
185 	old_value = sys_get_le16(buf);
186 
187 	if (mode == WRITE) {
188 		new_value = (old_value & ~mask) | (*value & mask);
189 	} else {
190 		new_value = (old_value & ~mask) | (~old_value & mask);
191 	}
192 
193 	if (new_value == old_value) {
194 		goto end;
195 	}
196 
197 	*(uint16_t *)buf = sys_get_le16((uint8_t *)&new_value);
198 	err = i2c_burst_write_dt(&config->i2c, AW9523B_REG_OUTPUT0, buf, sizeof(buf));
199 	if (err) {
200 		LOG_ERR("%s: Failed to set port (%d)", dev->name, err);
201 	}
202 
203 end:
204 	k_sem_give(aw9523b_get_lock(config->mfd_dev));
205 
206 	if (err == 0 && mode == READ) {
207 		*value = sys_get_le16(buf);
208 	}
209 
210 	return err;
211 }
212 
gpio_aw9523b_port_get_raw(const struct device * dev,gpio_port_value_t * value)213 static int gpio_aw9523b_port_get_raw(const struct device *dev, gpio_port_value_t *value)
214 {
215 	return gpio_aw9523b_port_read_write_toggle(dev, UINT16_MAX, value, READ);
216 }
217 
gpio_aw9523b_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)218 static int gpio_aw9523b_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
219 					    gpio_port_value_t value)
220 {
221 	return gpio_aw9523b_port_read_write_toggle(dev, mask, &value, WRITE);
222 }
223 
gpio_aw9523b_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)224 static int gpio_aw9523b_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
225 {
226 	return gpio_aw9523b_port_read_write_toggle(dev, pins, &pins, WRITE);
227 }
228 
gpio_aw9523b_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)229 static int gpio_aw9523b_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
230 {
231 	const gpio_port_value_t zero = 0;
232 
233 	/* If WRITE is specified, this pointer is used for reading only. It can cast. */
234 	return gpio_aw9523b_port_read_write_toggle(dev, pins, (gpio_port_value_t *)&zero, WRITE);
235 }
236 
gpio_aw9523b_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)237 static int gpio_aw9523b_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
238 {
239 	return gpio_aw9523b_port_read_write_toggle(dev, pins, NULL, TOGGLE);
240 }
241 
gpio_aw9523b_interrupt_worker(struct k_work * work)242 static __maybe_unused void gpio_aw9523b_interrupt_worker(struct k_work *work)
243 {
244 	struct gpio_aw9523b_data *const data =
245 		CONTAINER_OF(work, struct gpio_aw9523b_data, intr_worker);
246 	const struct gpio_aw9523b_config *const config = data->dev->config;
247 	gpio_port_value_t value, rising, falling;
248 	uint8_t buf[2];
249 	int err;
250 
251 	/*
252 	 * We need to read INPUT0 to deassert INTN when that is asserted by
253 	 * pin0-7 interruption, and same also INPUT1 for pin8-15.
254 	 * It cannot deassert by burst-read.
255 	 */
256 	err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT0, &buf[0], 1);
257 	if (err) {
258 		LOG_ERR("%s: Failed to read INPUT0 %d", data->dev->name, err);
259 	}
260 	err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT1, &buf[1], 1);
261 	if (err) {
262 		LOG_ERR("%s: Failed to read INPUT1 %d", data->dev->name, err);
263 	}
264 
265 	value = sys_get_le16(buf);
266 
267 	rising = (value ^ data->prev_value) & (value & data->rising_event_pins);
268 	falling = (value ^ data->prev_value) & (~value & data->falling_event_pins);
269 
270 	data->prev_value = value;
271 
272 	gpio_fire_callbacks(&data->callbacks, data->dev, rising | falling);
273 }
274 
gpio_aw9523b_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)275 static __maybe_unused int gpio_aw9523b_pin_interrupt_configure(const struct device *dev,
276 							       gpio_pin_t pin,
277 							       enum gpio_int_mode mode,
278 							       enum gpio_int_trig trig)
279 {
280 	const struct gpio_aw9523b_config *const config = dev->config;
281 	struct gpio_aw9523b_data *const data = dev->data;
282 	const uint8_t port = (pin < 8) ? 0 : 1;
283 	const uint8_t mask = BIT(port ? pin - 8 : pin);
284 	const uint8_t n_int_en = (mode & GPIO_INT_MODE_EDGE) ? 0x00 : 0xFF;
285 	uint8_t buf[2];
286 	int err;
287 
288 	/* Can't do I2C bus operations from an ISR */
289 	if (k_is_in_isr()) {
290 		return -EWOULDBLOCK;
291 	}
292 
293 	if (mode == GPIO_INT_MODE_LEVEL) {
294 		return -ENOTSUP;
295 	}
296 	if (data->common.invert & BIT(pin)) {
297 		WRITE_BIT(data->falling_event_pins, pin, trig & GPIO_INT_HIGH_1);
298 		WRITE_BIT(data->rising_event_pins, pin, trig & GPIO_INT_LOW_0);
299 	} else {
300 		WRITE_BIT(data->falling_event_pins, pin, trig & GPIO_INT_LOW_0);
301 		WRITE_BIT(data->rising_event_pins, pin, trig & GPIO_INT_HIGH_1);
302 	}
303 
304 	k_sem_take(aw9523b_get_lock(config->mfd_dev), K_FOREVER);
305 
306 	err = i2c_reg_update_byte_dt(&config->i2c, AW9523B_REG_INT(port), mask, n_int_en);
307 	if (err) {
308 		LOG_ERR("%s: Failed to configure pin interruption (%d)", dev->name, err);
309 		goto end;
310 	}
311 
312 	if (!n_int_en) {
313 		/* Read initial pin state */
314 		err = i2c_burst_read_dt(&config->i2c, AW9523B_REG_INPUT0, buf, sizeof(buf));
315 		if (err) {
316 			LOG_ERR("%s: Failed to read initial pin state (%d)", dev->name, err);
317 			goto end;
318 		}
319 
320 		WRITE_BIT(data->prev_value, pin, sys_get_le16(buf) & BIT(pin));
321 	} else {
322 		WRITE_BIT(data->falling_event_pins, pin, 0);
323 		WRITE_BIT(data->rising_event_pins, pin, 0);
324 	}
325 
326 end:
327 	k_sem_give(aw9523b_get_lock(config->mfd_dev));
328 
329 	return err;
330 }
331 
gpio_aw9523b_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)332 static __maybe_unused int gpio_aw9523b_manage_callback(const struct device *dev,
333 						       struct gpio_callback *callback, bool set)
334 {
335 	const struct gpio_aw9523b_config *const config = dev->config;
336 	struct gpio_aw9523b_data *const data = dev->data;
337 	int err;
338 
339 	k_sem_take(aw9523b_get_lock(config->mfd_dev), K_FOREVER);
340 
341 	err = gpio_manage_callback(&data->callbacks, callback, set);
342 	if (err) {
343 		LOG_ERR("%s: gpio_manage_callback failed (%d)", dev->name, err);
344 	}
345 
346 	k_sem_give(aw9523b_get_lock(config->mfd_dev));
347 
348 	return err;
349 }
350 
gpio_aw9523b_int_handler(const struct device * gpio_dev,struct gpio_callback * cb,uint32_t pins)351 static __maybe_unused void gpio_aw9523b_int_handler(const struct device *gpio_dev,
352 						    struct gpio_callback *cb, uint32_t pins)
353 {
354 	struct gpio_aw9523b_data *data = CONTAINER_OF(cb, struct gpio_aw9523b_data, gpio_callback);
355 
356 	k_work_submit(&data->intr_worker);
357 }
358 
359 static DEVICE_API(gpio, gpio_aw9523b_api) = {
360 	.pin_configure = gpio_aw9523b_pin_configure,
361 	.port_get_raw = gpio_aw9523b_port_get_raw,
362 	.port_set_masked_raw = gpio_aw9523b_port_set_masked_raw,
363 	.port_set_bits_raw = gpio_aw9523b_port_set_bits_raw,
364 	.port_clear_bits_raw = gpio_aw9523b_port_clear_bits_raw,
365 	.port_toggle_bits = gpio_aw9523b_port_toggle_bits,
366 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
367 	.pin_interrupt_configure = gpio_aw9523b_pin_interrupt_configure,
368 	.manage_callback = gpio_aw9523b_manage_callback,
369 #endif
370 };
371 
gpio_aw9523b_init(const struct device * dev)372 static int gpio_aw9523b_init(const struct device *dev)
373 {
374 	const struct gpio_aw9523b_config *const config = dev->config;
375 	const uint8_t int_init_data[] = {0xFF, 0xFF};
376 	uint8_t buf[2];
377 	int err;
378 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(int_gpios)
379 	struct gpio_aw9523b_data *const data = dev->data;
380 
381 	if (!config->int_gpio.port) {
382 		goto end_init_int_gpio;
383 	}
384 
385 	/* Store self-reference for interrupt handling */
386 	data->dev = dev;
387 
388 	/* Prepare interrupt worker */
389 	k_work_init(&data->intr_worker, gpio_aw9523b_interrupt_worker);
390 
391 	if (!gpio_is_ready_dt(&config->int_gpio)) {
392 		LOG_ERR("%s: Interrupt GPIO not ready", dev->name);
393 		return -ENODEV;
394 	}
395 
396 	err = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT);
397 	if (err) {
398 		LOG_ERR("%s: Failed to configure interrupt pin %d (%d)", dev->name,
399 			config->int_gpio.pin, err);
400 		return err;
401 	}
402 
403 	err = gpio_pin_interrupt_configure_dt(&config->int_gpio, GPIO_INT_EDGE_TO_ACTIVE);
404 	if (err) {
405 		LOG_ERR("%s: Failed to configure interrupt %d (%d)", dev->name,
406 			config->int_gpio.pin, err);
407 		return err;
408 	}
409 
410 	gpio_init_callback(&data->gpio_callback, config->int_cb, BIT(config->int_gpio.pin));
411 	err = gpio_add_callback(config->int_gpio.port, &data->gpio_callback);
412 	if (err) {
413 		LOG_ERR("%s: Failed to add interrupt callback for pin %d (%d)", dev->name,
414 			config->int_gpio.pin, err);
415 		return err;
416 	}
417 
418 end_init_int_gpio:
419 #endif
420 
421 #if DT_ANY_INST_HAS_PROP_STATUS_OKAY(reset_gpios)
422 	if (!config->reset_gpio.port) {
423 		goto end_hw_reset;
424 	}
425 
426 	if (!gpio_is_ready_dt(&config->reset_gpio)) {
427 		LOG_ERR("%s: Reset GPIO not ready", dev->name);
428 		return -ENODEV;
429 	}
430 
431 	err = gpio_pin_configure_dt(&config->reset_gpio, GPIO_OUTPUT_ACTIVE);
432 	if (err) {
433 		LOG_ERR("%s: Failed to configure reset pin %d (%d)", dev->name,
434 			config->reset_gpio.pin, err);
435 		return err;
436 	}
437 
438 	k_busy_wait(AW9523B_RESET_PULSE_WIDTH);
439 
440 	err = gpio_pin_set_dt(&config->reset_gpio, 0);
441 	if (err) {
442 		LOG_ERR("%s: Failed to set 0 reset pin %d (%d)", dev->name, config->reset_gpio.pin,
443 			err);
444 		return err;
445 	}
446 
447 end_hw_reset:
448 #endif
449 
450 	if (!device_is_ready(config->i2c.bus)) {
451 		return -ENODEV;
452 	}
453 
454 	k_sem_init(aw9523b_get_lock(config->mfd_dev), 1, 1);
455 
456 	/* Software reset */
457 	err = i2c_reg_read_byte_dt(&config->i2c, AW9523B_REG_SW_RSTN, buf);
458 	if (err) {
459 		LOG_ERR("%s: Failed to software reset (%d)", dev->name, err);
460 		return err;
461 	}
462 
463 	/* Disabling all interrupts */
464 	err = i2c_burst_write_dt(&config->i2c, AW9523B_REG_INT0, int_init_data, sizeof(buf));
465 	if (err) {
466 		LOG_ERR("%s: Failed to disable all interrupts (%d)", dev->name, err);
467 		return err;
468 	}
469 
470 	if (!config->port0_push_pull) {
471 		/* Configure port0 to push-pull mode */
472 		err = i2c_reg_update_byte_dt(&config->i2c, AW9523B_REG_CTL, AW9523B_GPOMD, 0xFF);
473 		if (err) {
474 			LOG_ERR("%s: Failed to configure port0 to push-pull (%d)", dev->name, err);
475 			return err;
476 		}
477 	}
478 
479 	return 0;
480 }
481 
482 #define GPIO_AW9523B_DEFINE(inst)                                                                  \
483 	static struct gpio_aw9523b_data gpio_aw9523b_data##inst;                                   \
484                                                                                                    \
485 	static const struct gpio_aw9523b_config gpio_aw9523b_config##inst = {                      \
486 		.common = {                                                                        \
487 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst),                    \
488 		},                                                                                 \
489 		.mfd_dev = DEVICE_DT_GET(DT_INST_PARENT(inst)),                                    \
490 		.i2c = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)),                                      \
491 		.port0_push_pull = DT_INST_PROP_OR(inst, port0_push_pull, false),                  \
492 		IF_ENABLED(DT_INST_PROP_HAS_IDX(inst, int_gpios, 0), (                             \
493 			   .int_gpio = GPIO_DT_SPEC_INST_GET(inst, int_gpios),                     \
494 			   .int_cb = gpio_aw9523b_int_handler,                                     \
495 		))                                                                                 \
496 		IF_ENABLED(DT_INST_PROP_HAS_IDX(inst, reset_gpios, 0), (                           \
497 			   .reset_gpio = GPIO_DT_SPEC_INST_GET(inst, reset_gpios),                 \
498 		))                                                                                 \
499 	};                                                                                         \
500 												   \
501 	DEVICE_DT_INST_DEFINE(inst, gpio_aw9523b_init, NULL, &gpio_aw9523b_data##inst,             \
502 			      &gpio_aw9523b_config##inst, POST_KERNEL,                             \
503 			      CONFIG_MFD_INIT_PRIORITY, &gpio_aw9523b_api);
504 
505 DT_INST_FOREACH_STATUS_OKAY(GPIO_AW9523B_DEFINE)
506