1 /*
2  * Copyright (c) 2021 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_nct38xx_gpio
8 
9 #include <zephyr/device.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/drivers/gpio/gpio_nct38xx.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys/util_macro.h>
14 
15 #include "gpio_nct38xx.h"
16 
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(gpio_ntc38xx, CONFIG_GPIO_LOG_LEVEL);
19 
nct38xx_gpio_alert_handler(const struct device * dev)20 void nct38xx_gpio_alert_handler(const struct device *dev)
21 {
22 	const struct gpio_nct38xx_config *const config = dev->config;
23 
24 	for (int i = 0; i < config->sub_gpio_port_num; i++) {
25 		gpio_nct38xx_dispatch_port_isr(config->sub_gpio_dev[i]);
26 	}
27 }
28 
nct38xx_init_interrupt(const struct device * dev)29 static int nct38xx_init_interrupt(const struct device *dev)
30 {
31 	uint16_t alert, alert_mask = 0;
32 
33 	/* Disable all interrupt */
34 	if (nct38xx_reg_burst_write(dev, NCT38XX_REG_ALERT_MASK, (uint8_t *)&alert_mask,
35 				    sizeof(alert_mask))) {
36 		return -EIO;
37 	}
38 
39 	/* Enable vendor-defined alert for GPIO. */
40 	alert_mask |= BIT(NCT38XX_REG_ALERT_MASK_VENDOR_DEFINDED_ALERT);
41 
42 	/* Clear alert */
43 	if (nct38xx_reg_burst_read(dev, NCT38XX_REG_ALERT, (uint8_t *)&alert, sizeof(alert))) {
44 		return -EIO;
45 	}
46 	alert &= alert_mask;
47 	if (alert) {
48 		if (nct38xx_reg_burst_write(dev, NCT38XX_REG_ALERT, (uint8_t *)&alert,
49 					    sizeof(alert))) {
50 			return -EIO;
51 		}
52 	}
53 
54 	if (nct38xx_reg_burst_write(dev, NCT38XX_REG_ALERT_MASK, (uint8_t *)&alert_mask,
55 				    sizeof(alert_mask))) {
56 		return -EIO;
57 	}
58 
59 	return 0;
60 }
61 
nct38xx_gpio_init(const struct device * dev)62 static int nct38xx_gpio_init(const struct device *dev)
63 {
64 	const struct gpio_nct38xx_config *const config = dev->config;
65 
66 	/* Check I2C is ready  */
67 	if (!device_is_ready(config->i2c_dev.bus)) {
68 		LOG_ERR("%s device not ready", config->i2c_dev.bus->name);
69 		return -ENODEV;
70 	}
71 
72 	if (IS_ENABLED(CONFIG_GPIO_NCT38XX_INTERRUPT)) {
73 		nct38xx_init_interrupt(dev);
74 	}
75 
76 	return 0;
77 }
78 
79 #define GPIO_NCT38XX_DEVICE_INSTANCE(inst)                                                         \
80 	static const struct device *sub_gpio_dev_##inst[] = {                                      \
81 		DT_INST_FOREACH_CHILD_STATUS_OKAY_SEP(inst, DEVICE_DT_GET, (,))                    \
82 	};                                                                                         \
83 	static const struct gpio_nct38xx_config gpio_nct38xx_cfg_##inst = {                        \
84 		.i2c_dev = I2C_DT_SPEC_INST_GET(inst),                                             \
85 		.sub_gpio_dev = sub_gpio_dev_##inst,                                               \
86 		.sub_gpio_port_num = ARRAY_SIZE(sub_gpio_dev_##inst),                              \
87 	};                                                                                         \
88 	static struct gpio_nct38xx_data gpio_nct38xx_data_##inst = {                               \
89 		.dev = DEVICE_DT_INST_GET(inst),                                                   \
90 	};                                                                                         \
91 	DEVICE_DT_INST_DEFINE(inst, nct38xx_gpio_init, NULL, &gpio_nct38xx_data_##inst,            \
92 			      &gpio_nct38xx_cfg_##inst, POST_KERNEL,                               \
93 			      CONFIG_GPIO_NCT38XX_INIT_PRIORITY, NULL);
94 
95 DT_INST_FOREACH_STATUS_OKAY(GPIO_NCT38XX_DEVICE_INSTANCE)
96