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