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