1 /*
2  * Copyright (c) 2021 Teslabs Engineering S.L.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT gd_gd32_gpio
8 
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/drivers/clock_control/gd32.h>
12 #include <zephyr/drivers/interrupt_controller/gd32_exti.h>
13 #include <zephyr/drivers/reset.h>
14 
15 #include <gd32_gpio.h>
16 
17 #include <zephyr/drivers/gpio/gpio_utils.h>
18 
19 #ifdef CONFIG_GD32_HAS_AF_PINMUX
20 /** SYSCFG DT node */
21 #define SYSCFG_NODE DT_NODELABEL(syscfg)
22 #else
23 /** AFIO DT node */
24 #define AFIO_NODE DT_NODELABEL(afio)
25 
26 /** GPIO mode: analog (CTL bits) */
27 #define CTL_MODE_ANALOG 0x0U
28 /** GPIO mode: input floating (CTL bits) */
29 #define CTL_MODE_INP_FLOAT 0x4U
30 /** GPIO mode: input with pull-up/down (CTL bits) */
31 #define CTL_MODE_INP_PUPD 0x8U
32 /** GPIO mode: output push-pull @ 2MHz (CTL bits) */
33 #define CTL_MODE_OUT_PP 0x2U
34 /** GPIO mode: output open-drain @ 2MHz (CTL bits) */
35 #define CTL_MODE_OUT_OD 0x6U
36 #endif /* CONFIG_GD32_HAS_AF_PINMUX */
37 
38 /** EXTISS mask */
39 #define EXTISS_MSK 0xFU
40 /** EXTISS line step size */
41 #define EXTISS_STEP 4U
42 /** EXTISS line shift */
43 #define EXTISS_LINE_SHIFT(pin) (EXTISS_STEP * ((pin) % EXTISS_STEP))
44 
45 struct gpio_gd32_config {
46 	struct gpio_driver_config common;
47 	uint32_t reg;
48 	uint16_t clkid;
49 	uint16_t clkid_exti;
50 	struct reset_dt_spec reset;
51 };
52 
53 struct gpio_gd32_data {
54 	struct gpio_driver_data common;
55 	sys_slist_t callbacks;
56 };
57 
58 /**
59  * @brief EXTI ISR callback.
60  *
61  * @param line EXTI line (equals to GPIO pin number).
62  * @param arg GPIO port instance.
63  */
gpio_gd32_isr(uint8_t line,void * arg)64 static void gpio_gd32_isr(uint8_t line, void *arg)
65 {
66 	const struct device *dev = arg;
67 	struct gpio_gd32_data *data = dev->data;
68 
69 	gpio_fire_callbacks(&data->callbacks, dev, BIT(line));
70 }
71 
72 /**
73  * @brief Configure EXTI source selection register.
74  *
75  * @param port GPIO port instance.
76  * @param pin GPIO pin number.
77  *
78  * @retval 0 on success.
79  * @retval -EINVAL if pin is not valid.
80  */
gpio_gd32_configure_extiss(const struct device * port,gpio_pin_t pin)81 static int gpio_gd32_configure_extiss(const struct device *port,
82 				      gpio_pin_t pin)
83 {
84 	const struct gpio_gd32_config *config = port->config;
85 	uint8_t port_index, shift;
86 	volatile uint32_t *extiss;
87 
88 	switch (pin / EXTISS_STEP) {
89 #ifdef CONFIG_GD32_HAS_AF_PINMUX
90 	case 0U:
91 		extiss = &SYSCFG_EXTISS0;
92 		break;
93 	case 1U:
94 		extiss = &SYSCFG_EXTISS1;
95 		break;
96 	case 2U:
97 		extiss = &SYSCFG_EXTISS2;
98 		break;
99 	case 3U:
100 		extiss = &SYSCFG_EXTISS3;
101 		break;
102 #else
103 	case 0U:
104 		extiss = &AFIO_EXTISS0;
105 		break;
106 	case 1U:
107 		extiss = &AFIO_EXTISS1;
108 		break;
109 	case 2U:
110 		extiss = &AFIO_EXTISS2;
111 		break;
112 	case 3U:
113 		extiss = &AFIO_EXTISS3;
114 		break;
115 #endif /* CONFIG_GD32_HAS_AF_PINMUX */
116 	default:
117 		return -EINVAL;
118 	}
119 
120 	port_index = (config->reg - GPIOA) / (GPIOB - GPIOA);
121 	shift = EXTISS_LINE_SHIFT(pin);
122 
123 	*extiss &= ~(EXTISS_MSK << shift);
124 	*extiss |= port_index << shift;
125 
126 	return 0;
127 }
128 
gpio_gd32_configure(const struct device * port,gpio_pin_t pin,gpio_flags_t flags)129 static inline int gpio_gd32_configure(const struct device *port, gpio_pin_t pin,
130 				      gpio_flags_t flags)
131 {
132 	const struct gpio_gd32_config *config = port->config;
133 
134 #ifdef CONFIG_GD32_HAS_AF_PINMUX
135 	uint32_t ctl, pupd;
136 
137 	ctl = GPIO_CTL(config->reg);
138 	ctl &= ~GPIO_MODE_MASK(pin);
139 
140 	pupd = GPIO_PUD(config->reg);
141 	pupd &= ~GPIO_PUPD_MASK(pin);
142 
143 	if ((flags & GPIO_OUTPUT) != 0U) {
144 		ctl |= GPIO_MODE_SET(pin, GPIO_MODE_OUTPUT);
145 
146 		if ((flags & GPIO_SINGLE_ENDED) != 0U) {
147 			if ((flags & GPIO_LINE_OPEN_DRAIN) != 0U) {
148 				GPIO_OMODE(config->reg) |= BIT(pin);
149 			} else {
150 				return -ENOTSUP;
151 			}
152 		} else {
153 			GPIO_OMODE(config->reg) &= ~BIT(pin);
154 		}
155 
156 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
157 			GPIO_BOP(config->reg) = BIT(pin);
158 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
159 			GPIO_BC(config->reg) = BIT(pin);
160 		}
161 	} else if ((flags & GPIO_INPUT) != 0U) {
162 		ctl |= GPIO_MODE_SET(pin, GPIO_MODE_INPUT);
163 	} else {
164 		ctl |= GPIO_MODE_SET(pin, GPIO_MODE_ANALOG);
165 	}
166 
167 	if ((flags & GPIO_PULL_UP) != 0U) {
168 		pupd |= GPIO_PUPD_SET(pin, GPIO_PUPD_PULLUP);
169 	} else if ((flags & GPIO_PULL_DOWN) != 0U) {
170 		pupd |= GPIO_PUPD_SET(pin, GPIO_PUPD_PULLDOWN);
171 	} else {
172 		pupd |= GPIO_PUPD_SET(pin, GPIO_PUPD_NONE);
173 	}
174 
175 	GPIO_PUD(config->reg) = pupd;
176 	GPIO_CTL(config->reg) = ctl;
177 #else
178 	volatile uint32_t *ctl_reg;
179 	uint32_t ctl, pin_bit;
180 
181 	pin_bit = BIT(pin);
182 
183 	if (pin < 8U) {
184 		ctl_reg = &GPIO_CTL0(config->reg);
185 	} else {
186 		ctl_reg = &GPIO_CTL1(config->reg);
187 		pin -= 8U;
188 	}
189 
190 	ctl = *ctl_reg;
191 	ctl &= ~GPIO_MODE_MASK(pin);
192 
193 	if ((flags & GPIO_OUTPUT) != 0U) {
194 		if ((flags & GPIO_SINGLE_ENDED) != 0U) {
195 			if ((flags & GPIO_LINE_OPEN_DRAIN) != 0U) {
196 				ctl |= GPIO_MODE_SET(pin, CTL_MODE_OUT_OD);
197 			} else {
198 				return -ENOTSUP;
199 			}
200 		} else {
201 			ctl |= GPIO_MODE_SET(pin, CTL_MODE_OUT_PP);
202 		}
203 
204 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) {
205 			GPIO_BOP(config->reg) = pin_bit;
206 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) {
207 			GPIO_BC(config->reg) = pin_bit;
208 		}
209 	} else if ((flags & GPIO_INPUT) != 0U) {
210 		if ((flags & GPIO_PULL_UP) != 0U) {
211 			ctl |= GPIO_MODE_SET(pin, CTL_MODE_INP_PUPD);
212 			GPIO_BOP(config->reg) = pin_bit;
213 		} else if ((flags & GPIO_PULL_DOWN) != 0U) {
214 			ctl |= GPIO_MODE_SET(pin, CTL_MODE_INP_PUPD);
215 			GPIO_BC(config->reg) = pin_bit;
216 		} else {
217 			ctl |= GPIO_MODE_SET(pin, CTL_MODE_INP_FLOAT);
218 		}
219 	} else {
220 		ctl |= GPIO_MODE_SET(pin, CTL_MODE_ANALOG);
221 	}
222 
223 	*ctl_reg = ctl;
224 #endif /* CONFIG_GD32_HAS_AF_PINMUX */
225 
226 	return 0;
227 }
228 
gpio_gd32_port_get_raw(const struct device * port,uint32_t * value)229 static int gpio_gd32_port_get_raw(const struct device *port, uint32_t *value)
230 {
231 	const struct gpio_gd32_config *config = port->config;
232 
233 	*value = GPIO_ISTAT(config->reg);
234 
235 	return 0;
236 }
237 
gpio_gd32_port_set_masked_raw(const struct device * port,gpio_port_pins_t mask,gpio_port_value_t value)238 static int gpio_gd32_port_set_masked_raw(const struct device *port,
239 					 gpio_port_pins_t mask,
240 					 gpio_port_value_t value)
241 {
242 	const struct gpio_gd32_config *config = port->config;
243 
244 	GPIO_OCTL(config->reg) =
245 		(GPIO_OCTL(config->reg) & ~mask) | (value & mask);
246 
247 	return 0;
248 }
249 
gpio_gd32_port_set_bits_raw(const struct device * port,gpio_port_pins_t pins)250 static int gpio_gd32_port_set_bits_raw(const struct device *port,
251 				       gpio_port_pins_t pins)
252 {
253 	const struct gpio_gd32_config *config = port->config;
254 
255 	GPIO_BOP(config->reg) = pins;
256 
257 	return 0;
258 }
259 
gpio_gd32_port_clear_bits_raw(const struct device * port,gpio_port_pins_t pins)260 static int gpio_gd32_port_clear_bits_raw(const struct device *port,
261 					 gpio_port_pins_t pins)
262 {
263 	const struct gpio_gd32_config *config = port->config;
264 
265 	GPIO_BC(config->reg) = pins;
266 
267 	return 0;
268 }
269 
gpio_gd32_port_toggle_bits(const struct device * port,gpio_port_pins_t pins)270 static int gpio_gd32_port_toggle_bits(const struct device *port,
271 				      gpio_port_pins_t pins)
272 {
273 	const struct gpio_gd32_config *config = port->config;
274 
275 #ifdef CONFIG_GD32_HAS_AF_PINMUX
276 	GPIO_TG(config->reg) = pins;
277 #else
278 	GPIO_OCTL(config->reg) ^= pins;
279 #endif /* CONFIG_GD32_HAS_AF_PINMUX */
280 
281 	return 0;
282 }
283 
gpio_gd32_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)284 static int gpio_gd32_pin_interrupt_configure(const struct device *port,
285 					     gpio_pin_t pin,
286 					     enum gpio_int_mode mode,
287 					     enum gpio_int_trig trig)
288 {
289 	if (mode == GPIO_INT_MODE_DISABLED) {
290 		gd32_exti_disable(pin);
291 		(void)gd32_exti_configure(pin, NULL, NULL);
292 		gd32_exti_trigger(pin, GD32_EXTI_TRIG_NONE);
293 	} else if (mode == GPIO_INT_MODE_EDGE) {
294 		int ret;
295 
296 		ret = gd32_exti_configure(pin, gpio_gd32_isr, (void *)port);
297 		if (ret < 0) {
298 			return ret;
299 		}
300 
301 		ret = gpio_gd32_configure_extiss(port, pin);
302 		if (ret < 0) {
303 			return ret;
304 		}
305 
306 		switch (trig) {
307 		case GPIO_INT_TRIG_LOW:
308 			gd32_exti_trigger(pin, GD32_EXTI_TRIG_FALLING);
309 			break;
310 		case GPIO_INT_TRIG_HIGH:
311 			gd32_exti_trigger(pin, GD32_EXTI_TRIG_RISING);
312 			break;
313 		case GPIO_INT_TRIG_BOTH:
314 			gd32_exti_trigger(pin, GD32_EXTI_TRIG_BOTH);
315 			break;
316 		default:
317 			return -ENOTSUP;
318 		}
319 
320 		gd32_exti_enable(pin);
321 	} else {
322 		return -ENOTSUP;
323 	}
324 
325 	return 0;
326 }
327 
gpio_gd32_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)328 static int gpio_gd32_manage_callback(const struct device *dev,
329 				     struct gpio_callback *callback, bool set)
330 {
331 	struct gpio_gd32_data *data = dev->data;
332 
333 	return gpio_manage_callback(&data->callbacks, callback, set);
334 }
335 
336 static const struct gpio_driver_api gpio_gd32_api = {
337 	.pin_configure = gpio_gd32_configure,
338 	.port_get_raw = gpio_gd32_port_get_raw,
339 	.port_set_masked_raw = gpio_gd32_port_set_masked_raw,
340 	.port_set_bits_raw = gpio_gd32_port_set_bits_raw,
341 	.port_clear_bits_raw = gpio_gd32_port_clear_bits_raw,
342 	.port_toggle_bits = gpio_gd32_port_toggle_bits,
343 	.pin_interrupt_configure = gpio_gd32_pin_interrupt_configure,
344 	.manage_callback = gpio_gd32_manage_callback,
345 };
346 
gpio_gd32_init(const struct device * port)347 static int gpio_gd32_init(const struct device *port)
348 {
349 	const struct gpio_gd32_config *config = port->config;
350 
351 	(void)clock_control_on(GD32_CLOCK_CONTROLLER,
352 			       (clock_control_subsys_t)&config->clkid);
353 	(void)clock_control_on(GD32_CLOCK_CONTROLLER,
354 			       (clock_control_subsys_t)&config->clkid_exti);
355 
356 	(void)reset_line_toggle_dt(&config->reset);
357 
358 	return 0;
359 }
360 
361 #define GPIO_GD32_DEFINE(n)						       \
362 	static const struct gpio_gd32_config gpio_gd32_config##n = {	       \
363 		.common = {						       \
364 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),   \
365 		},							       \
366 		.reg = DT_INST_REG_ADDR(n),				       \
367 		.clkid = DT_INST_CLOCKS_CELL(n, id),			       \
368 		COND_CODE_1(DT_NODE_HAS_STATUS(SYSCFG_NODE, okay),	       \
369 			    (.clkid_exti = DT_CLOCKS_CELL(SYSCFG_NODE, id),),  \
370 			    (.clkid_exti = DT_CLOCKS_CELL(AFIO_NODE, id),))    \
371 		.reset = RESET_DT_SPEC_INST_GET(n),			       \
372 	};								       \
373 									       \
374 	static struct gpio_gd32_data gpio_gd32_data##n;			       \
375 									       \
376 	DEVICE_DT_INST_DEFINE(n, &gpio_gd32_init, NULL, &gpio_gd32_data##n,    \
377 			      &gpio_gd32_config##n, PRE_KERNEL_1,	       \
378 			      CONFIG_GPIO_INIT_PRIORITY, &gpio_gd32_api);
379 
380 DT_INST_FOREACH_STATUS_OKAY(GPIO_GD32_DEFINE)
381