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_exti
8
9 #include <errno.h>
10
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/interrupt_controller/gd32_exti.h>
13 #include <zephyr/sys/__assert.h>
14 #include <zephyr/irq.h>
15 #include <zephyr/sys/util_macro.h>
16
17 #include <gd32_exti.h>
18
19 /** Unsupported line indicator */
20 #define EXTI_NOTSUP 0xFFU
21
22 /** Number of EXTI lines. */
23 #define NUM_EXTI_LINES DT_INST_PROP(0, num_lines)
24
25 /** @brief EXTI line ranges hold by a single ISR */
26 struct gd32_exti_range {
27 /** Start of the range */
28 uint8_t min;
29 /** End of the range */
30 uint8_t max;
31 };
32
33 /** @brief EXTI line interrupt callback. */
34 struct gd32_cb_data {
35 /** Callback function */
36 gd32_exti_cb_t cb;
37 /** User data. */
38 void *user;
39 };
40
41 /** EXTI driver data. */
42 struct gd32_exti_data {
43 /** Array of callbacks. */
44 struct gd32_cb_data cbs[NUM_EXTI_LINES];
45 };
46
47 #ifdef CONFIG_GPIO_GD32
48 static const struct gd32_exti_range line0_range = {0U, 0U};
49 static const struct gd32_exti_range line1_range = {1U, 1U};
50 static const struct gd32_exti_range line2_range = {2U, 2U};
51 static const struct gd32_exti_range line3_range = {3U, 3U};
52 static const struct gd32_exti_range line4_range = {4U, 4U};
53 static const struct gd32_exti_range line5_9_range = {5U, 9U};
54 static const struct gd32_exti_range line10_15_range = {10U, 15U};
55 #endif /* CONFIG_GPIO_GD32 */
56
57 /** @brief Obtain line IRQ number if enabled. */
58 #define EXTI_LINE_IRQ_COND(enabled, line) \
59 COND_CODE_1(enabled, (DT_INST_IRQ_BY_NAME(0, line, irq)), (EXTI_NOTSUP))
60
61 static const uint8_t line2irq[NUM_EXTI_LINES] = {
62 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line0),
63 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line1),
64 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line2),
65 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line3),
66 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line4),
67 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
68 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
69 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
70 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
71 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line5_9),
72 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
73 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
74 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
75 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
76 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
77 EXTI_LINE_IRQ_COND(CONFIG_GPIO_GD32, line10_15),
78 EXTI_NOTSUP,
79 EXTI_NOTSUP,
80 EXTI_NOTSUP,
81 #ifdef CONFIG_SOC_SERIES_GD32F4XX
82 EXTI_NOTSUP,
83 EXTI_NOTSUP,
84 EXTI_NOTSUP,
85 EXTI_NOTSUP,
86 #endif /* CONFIG_SOC_SERIES_GD32F4XX */
87 };
88
gd32_exti_isr(const void * isr_data)89 __unused static void gd32_exti_isr(const void *isr_data)
90 {
91 const struct device *const dev = DEVICE_DT_INST_GET(0);
92 struct gd32_exti_data *data = dev->data;
93 const struct gd32_exti_range *range = isr_data;
94
95 for (uint8_t i = range->min; i <= range->max; i++) {
96 if ((EXTI_PD & BIT(i)) != 0U) {
97 EXTI_PD = BIT(i);
98
99 if (data->cbs[i].cb != NULL) {
100 data->cbs[i].cb(i, data->cbs[i].user);
101 }
102 }
103 }
104 }
105
gd32_exti_enable(uint8_t line)106 void gd32_exti_enable(uint8_t line)
107 {
108 __ASSERT_NO_MSG(line < NUM_EXTI_LINES);
109 __ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
110
111 EXTI_INTEN |= BIT(line);
112
113 irq_enable(line2irq[line]);
114 }
115
gd32_exti_disable(uint8_t line)116 void gd32_exti_disable(uint8_t line)
117 {
118 __ASSERT_NO_MSG(line < NUM_EXTI_LINES);
119 __ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
120
121 EXTI_INTEN &= ~BIT(line);
122 }
123
gd32_exti_trigger(uint8_t line,uint8_t trigger)124 void gd32_exti_trigger(uint8_t line, uint8_t trigger)
125 {
126 __ASSERT_NO_MSG(line < NUM_EXTI_LINES);
127 __ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
128
129 if ((trigger & GD32_EXTI_TRIG_RISING) != 0U) {
130 EXTI_RTEN |= BIT(line);
131 } else {
132 EXTI_RTEN &= ~BIT(line);
133 }
134
135 if ((trigger & GD32_EXTI_TRIG_FALLING) != 0U) {
136 EXTI_FTEN |= BIT(line);
137 } else {
138 EXTI_FTEN &= ~BIT(line);
139 }
140 }
141
gd32_exti_configure(uint8_t line,gd32_exti_cb_t cb,void * user)142 int gd32_exti_configure(uint8_t line, gd32_exti_cb_t cb, void *user)
143 {
144 const struct device *const dev = DEVICE_DT_INST_GET(0);
145 struct gd32_exti_data *data = dev->data;
146
147 __ASSERT_NO_MSG(line < NUM_EXTI_LINES);
148 __ASSERT_NO_MSG(line2irq[line] != EXTI_NOTSUP);
149
150 if ((data->cbs[line].cb != NULL) && (cb != NULL)) {
151 return -EALREADY;
152 }
153
154 data->cbs[line].cb = cb;
155 data->cbs[line].user = user;
156
157 return 0;
158 }
159
gd32_exti_init(const struct device * dev)160 static int gd32_exti_init(const struct device *dev)
161 {
162 #ifdef CONFIG_GPIO_GD32
163 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line0, irq),
164 DT_INST_IRQ_BY_NAME(0, line0, priority),
165 gd32_exti_isr, &line0_range, 0);
166
167 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line1, irq),
168 DT_INST_IRQ_BY_NAME(0, line1, priority),
169 gd32_exti_isr, &line1_range, 0);
170
171 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line2, irq),
172 DT_INST_IRQ_BY_NAME(0, line2, priority),
173 gd32_exti_isr, &line2_range, 0);
174
175 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line3, irq),
176 DT_INST_IRQ_BY_NAME(0, line3, priority),
177 gd32_exti_isr, &line3_range, 0);
178
179 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line4, irq),
180 DT_INST_IRQ_BY_NAME(0, line4, priority),
181 gd32_exti_isr, &line4_range, 0);
182
183 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line5_9, irq),
184 DT_INST_IRQ_BY_NAME(0, line5_9, priority),
185 gd32_exti_isr, &line5_9_range, 0);
186
187 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, line10_15, irq),
188 DT_INST_IRQ_BY_NAME(0, line10_15, priority),
189 gd32_exti_isr, &line10_15_range, 0);
190 #endif /* CONFIG_GPIO_GD32 */
191
192 return 0;
193 }
194
195 static struct gd32_exti_data data;
196
197 DEVICE_DT_INST_DEFINE(0, gd32_exti_init, NULL, &data, NULL, PRE_KERNEL_1,
198 CONFIG_INTC_INIT_PRIORITY, NULL);
199