1 /*
2  * Copyright (c) 2022 SEAL AG
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_numicro_gpio
8 
9 #include <errno.h>
10 #include <stdint.h>
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/irq.h>
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/drivers/gpio/gpio_utils.h>
16 #include <zephyr/dt-bindings/gpio/numicro-gpio.h>
17 #include <NuMicro.h>
18 
19 #define MODE_PIN_SHIFT(pin)	((pin) * 2)
20 #define MODE_MASK(pin)		(3 << MODE_PIN_SHIFT(pin))
21 #define DINOFF_PIN_SHIFT(pin)	((pin) + 16)
22 #define DINOFF_MASK(pin)	(1 << DINOFF_PIN_SHIFT(pin))
23 #define PUSEL_PIN_SHIFT(pin)	((pin) * 2)
24 #define PUSEL_MASK(pin)		(3 << PUSEL_PIN_SHIFT(pin))
25 
26 #define PORT_PIN_MASK		0xFFFF
27 
28 struct gpio_numicro_config {
29 	/* gpio_driver_config needs to be first */
30 	struct gpio_driver_config common;
31 	GPIO_T *regs;
32 };
33 
34 struct gpio_numicro_data {
35 	/* gpio_driver_data needs to be first */
36 	struct gpio_driver_data common;
37 	/* port ISR callback routine address */
38 	sys_slist_t callbacks;
39 #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT
40 	/*
41 	 * backup of the INTEN register.
42 	 * The higher half is RHIEN for whether rising trigger is enabled, and
43 	 * the lower half is FLIEN for whether falling trigger is enabled.
44 	 */
45 	uint32_t interrupt_en_reg_bak;
46 #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */
47 };
48 
gpio_numicro_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)49 static int gpio_numicro_configure(const struct device *dev,
50 			       gpio_pin_t pin, gpio_flags_t flags)
51 {
52 	const struct gpio_numicro_config *cfg = dev->config;
53 	GPIO_T * const regs = cfg->regs;
54 
55 	uint32_t mode;
56 	uint32_t debounce_enable = 0;
57 	uint32_t schmitt_enable = 0;
58 	uint32_t disable_input_path = 0;
59 	uint32_t bias = GPIO_PUSEL_DISABLE;
60 
61 	/* Pin mode */
62 	if ((flags & GPIO_OUTPUT) != 0) {
63 		/* Output */
64 
65 		if ((flags & GPIO_SINGLE_ENDED) != 0) {
66 			if ((flags & GPIO_LINE_OPEN_DRAIN) != 0) {
67 				mode = GPIO_MODE_OPEN_DRAIN;
68 			} else {
69 				/* Output can't be open source */
70 				return -ENOTSUP;
71 			}
72 		} else {
73 			mode = GPIO_MODE_OUTPUT;
74 		}
75 	} else if ((flags & GPIO_INPUT) != 0) {
76 		/* Input */
77 
78 		mode = GPIO_MODE_INPUT;
79 
80 		if ((flags & NUMICRO_GPIO_INPUT_DEBOUNCE) != 0) {
81 			debounce_enable = 1;
82 		}
83 
84 		if ((flags & NUMICRO_GPIO_INPUT_SCHMITT) != 0) {
85 			schmitt_enable = 1;
86 		}
87 	} else {
88 		/* Deactivated: Analog */
89 
90 		mode = GPIO_MODE_INPUT;
91 		disable_input_path = 1;
92 	}
93 
94 	/* Bias */
95 	if ((flags & GPIO_OUTPUT) != 0 || (flags & GPIO_INPUT) != 0) {
96 		if ((flags & GPIO_PULL_UP) != 0) {
97 			bias = GPIO_PUSEL_PULL_UP;
98 		} else if ((flags & GPIO_PULL_DOWN) != 0) {
99 			bias = GPIO_PUSEL_PULL_DOWN;
100 		}
101 	}
102 
103 	regs->MODE = (regs->MODE & ~MODE_MASK(pin)) |
104 		     (mode << MODE_PIN_SHIFT(pin));
105 	regs->DBEN = (regs->DBEN & ~BIT(pin)) | (debounce_enable << pin);
106 	regs->SMTEN = (regs->SMTEN & ~BIT(pin)) | (schmitt_enable << pin);
107 	regs->DINOFF = (regs->DINOFF & ~DINOFF_MASK(pin)) |
108 		       (disable_input_path << DINOFF_PIN_SHIFT(pin));
109 	regs->PUSEL = (regs->PUSEL & ~PUSEL_MASK(pin)) |
110 		      (bias << PUSEL_PIN_SHIFT(pin));
111 
112 	return 0;
113 }
114 
gpio_numicro_port_get_raw(const struct device * dev,uint32_t * value)115 static int gpio_numicro_port_get_raw(const struct device *dev, uint32_t *value)
116 {
117 	const struct gpio_numicro_config *cfg = dev->config;
118 
119 	*value = cfg->regs->PIN & PORT_PIN_MASK;
120 
121 	return 0;
122 }
123 
gpio_numicro_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)124 static int gpio_numicro_port_set_masked_raw(const struct device *dev,
125 					 uint32_t mask,
126 					 uint32_t value)
127 {
128 	const struct gpio_numicro_config *cfg = dev->config;
129 
130 	cfg->regs->DATMSK = ~mask;
131 	cfg->regs->DOUT = value;
132 
133 	return 0;
134 }
135 
gpio_numicro_port_set_bits_raw(const struct device * dev,uint32_t mask)136 static int gpio_numicro_port_set_bits_raw(const struct device *dev,
137 				       uint32_t mask)
138 {
139 	const struct gpio_numicro_config *cfg = dev->config;
140 
141 	cfg->regs->DATMSK = ~mask;
142 	cfg->regs->DOUT = PORT_PIN_MASK;
143 
144 	return 0;
145 }
146 
gpio_numicro_port_clear_bits_raw(const struct device * dev,uint32_t mask)147 static int gpio_numicro_port_clear_bits_raw(const struct device *dev,
148 					 uint32_t mask)
149 {
150 	const struct gpio_numicro_config *cfg = dev->config;
151 
152 	cfg->regs->DATMSK = ~mask;
153 	cfg->regs->DOUT = 0;
154 
155 	return 0;
156 }
157 
gpio_numicro_port_toggle_bits(const struct device * dev,uint32_t mask)158 static int gpio_numicro_port_toggle_bits(const struct device *dev, uint32_t mask)
159 {
160 	const struct gpio_numicro_config *cfg = dev->config;
161 
162 	cfg->regs->DATMSK = 0;
163 	cfg->regs->DOUT ^= mask;
164 
165 	return 0;
166 }
167 
gpio_numicro_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)168 static int gpio_numicro_pin_interrupt_configure(const struct device *dev,
169 					     gpio_pin_t pin, enum gpio_int_mode mode,
170 					     enum gpio_int_trig trig)
171 {
172 	const struct gpio_numicro_config *cfg = dev->config;
173 #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT
174 	struct gpio_numicro_data *data = dev->data;
175 #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */
176 	uint32_t int_type = 0;
177 	uint32_t int_level = 0;
178 	uint32_t int_level_mask = BIT(pin) | BIT(pin + 16);
179 
180 #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT
181 	if (mode == GPIO_INT_MODE_DISABLE_ONLY) {
182 		cfg->regs->INTEN &= ~(BIT(pin) | BIT(pin + 16));
183 		return 0;
184 	} else if (mode == GPIO_INT_MODE_ENABLE_ONLY) {
185 		cfg->regs->INTEN |= data->interrupt_en_reg_bak & (BIT(pin) | BIT(pin + 16));
186 		return 0;
187 	}
188 #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */
189 
190 	if (mode != GPIO_INT_MODE_DISABLED) {
191 		int_type = (mode == GPIO_INT_MODE_LEVEL) ? 1 : 0;
192 
193 		switch (trig) {
194 		case GPIO_INT_TRIG_LOW:
195 			int_level = BIT(pin);
196 			break;
197 		case GPIO_INT_TRIG_HIGH:
198 			int_level = BIT(pin + 16);
199 			break;
200 		case GPIO_INT_TRIG_BOTH:
201 			int_level = BIT(pin) | BIT(pin + 16);
202 			break;
203 		}
204 	}
205 
206 	cfg->regs->INTTYPE = (cfg->regs->INTTYPE & ~BIT(pin)) | (int_type << pin);
207 	cfg->regs->INTEN = (cfg->regs->INTEN & ~int_level_mask) | int_level;
208 #ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT
209 	data->interrupt_en_reg_bak = cfg->regs->INTEN;
210 #endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */
211 
212 	return 0;
213 }
214 
gpio_numicro_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)215 static int gpio_numicro_manage_callback(const struct device *dev,
216 					struct gpio_callback *callback,
217 					bool set)
218 {
219 	struct gpio_numicro_data *data = dev->data;
220 
221 	return gpio_manage_callback(&data->callbacks, callback, set);
222 }
223 
gpio_numicro_isr(const struct device * dev)224 static void gpio_numicro_isr(const struct device *dev)
225 {
226 	const struct gpio_numicro_config *cfg = dev->config;
227 	struct gpio_numicro_data *data = dev->data;
228 	uint32_t int_status;
229 
230 	int_status = cfg->regs->INTSRC;
231 
232 	/* Clear the port interrupts */
233 	cfg->regs->INTSRC = int_status;
234 
235 	gpio_fire_callbacks(&data->callbacks, dev, int_status);
236 }
237 
238 static const struct gpio_driver_api gpio_numicro_driver_api = {
239 	.pin_configure = gpio_numicro_configure,
240 	.port_get_raw = gpio_numicro_port_get_raw,
241 	.port_set_masked_raw = gpio_numicro_port_set_masked_raw,
242 	.port_set_bits_raw = gpio_numicro_port_set_bits_raw,
243 	.port_clear_bits_raw = gpio_numicro_port_clear_bits_raw,
244 	.port_toggle_bits = gpio_numicro_port_toggle_bits,
245 	.pin_interrupt_configure = gpio_numicro_pin_interrupt_configure,
246 	.manage_callback = gpio_numicro_manage_callback,
247 };
248 
249 #define GPIO_NUMICRO_INIT(n)						\
250 	static int gpio_numicro_port##n##_init(const struct device *dev)\
251 	{								\
252 		IRQ_CONNECT(DT_INST_IRQN(n),				\
253 			    DT_INST_IRQ(n, priority),			\
254 			    gpio_numicro_isr,				\
255 			    DEVICE_DT_INST_GET(n), 0);			\
256 		irq_enable(DT_INST_IRQN(n));				\
257 		return 0;						\
258 	}								\
259 									\
260 	static struct gpio_numicro_data gpio_numicro_port##n##_data;	\
261 									\
262 	static const struct gpio_numicro_config gpio_numicro_port##n##_config = {\
263 		.common = {						\
264 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),\
265 		},							\
266 		.regs = (GPIO_T *)DT_INST_REG_ADDR(n),			\
267 	};								\
268 									\
269 	DEVICE_DT_INST_DEFINE(n,					\
270 			      gpio_numicro_port##n##_init,		\
271 			      NULL,					\
272 			      &gpio_numicro_port##n##_data,		\
273 			      &gpio_numicro_port##n##_config,		\
274 			      PRE_KERNEL_1,				\
275 			      CONFIG_GPIO_INIT_PRIORITY,		\
276 			      &gpio_numicro_driver_api);
277 
278 DT_INST_FOREACH_STATUS_OKAY(GPIO_NUMICRO_INIT)
279