7
7
#include <zephyr/drivers/clock_control.h>
8
8
#include <zephyr/drivers/gpio.h>
9
9
#include <zephyr/drivers/gpio/gpio_utils.h>
10
+ #include <zephyr/drivers/interrupt_controller/wch_exti.h>
10
11
#include <zephyr/dt-bindings/gpio/gpio.h>
11
12
#include <zephyr/irq.h>
12
13
@@ -23,6 +24,7 @@ struct gpio_ch32v00x_config {
23
24
24
25
struct gpio_ch32v00x_data {
25
26
struct gpio_driver_data common ;
27
+ sys_slist_t callbacks ;
26
28
};
27
29
28
30
static int gpio_ch32v00x_configure (const struct device * dev , gpio_pin_t pin , gpio_flags_t flags )
@@ -111,13 +113,142 @@ static int gpio_ch32v00x_port_toggle_bits(const struct device *dev, uint32_t pin
111
113
return 0 ;
112
114
}
113
115
116
+ #if defined(CONFIG_GPIO_WCH_GPIO_INTERRUPTS )
117
+
118
+ static void gpio_ch32v00x_isr (uint8_t line , void * user )
119
+ {
120
+ const struct device * dev = user ;
121
+ struct gpio_ch32v00x_data * data = dev -> data ;
122
+
123
+ gpio_fire_callbacks (& data -> callbacks , dev , BIT (line ));
124
+ }
125
+
126
+ static int gpio_ch32v00x_configure_exti (const struct device * dev , gpio_pin_t pin )
127
+ {
128
+ const struct gpio_ch32v00x_config * config = dev -> config ;
129
+ AFIO_TypeDef * afio = (AFIO_TypeDef * )DT_REG_ADDR (DT_NODELABEL (pinctrl ));
130
+ uint8_t port_id ;
131
+ uint8_t cr_id ;
132
+ uint8_t bit0 ;
133
+
134
+ /* Convert the device into a port ID by checking the address */
135
+ switch ((uintptr_t )config -> regs ) {
136
+ case DT_REG_ADDR (DT_NODELABEL (gpioa )):
137
+ port_id = 0 ;
138
+ break ;
139
+ #if DT_NODE_EXISTS (DT_NODELABEL (gpiob ))
140
+ case DT_REG_ADDR (DT_NODELABEL (gpiob )):
141
+ port_id = 1 ;
142
+ break ;
143
+ #endif
144
+ case DT_REG_ADDR (DT_NODELABEL (gpioc )):
145
+ port_id = 2 ;
146
+ break ;
147
+ case DT_REG_ADDR (DT_NODELABEL (gpiod )):
148
+ port_id = 3 ;
149
+ break ;
150
+ #if DT_NODE_EXISTS (DT_NODELABEL (gpioe ))
151
+ case DT_REG_ADDR (DT_NODELABEL (gpioe )):
152
+ port_id = 4 ;
153
+ break ;
154
+ #endif
155
+ default :
156
+ return - EINVAL ;
157
+ }
158
+
159
+ #if defined(AFIO_EXTICR_EXTI0 )
160
+ /* CH32V003 style with one register with 2 bits per map. */
161
+ BUILD_ASSERT (AFIO_EXTICR_EXTI0 == 0x03 );
162
+
163
+ (void )cr_id ;
164
+ bit0 = pin << 1 ;
165
+ afio -> EXTICR = (afio -> EXTICR & ~(AFIO_EXTICR_EXTI0 << bit0 )) | (port_id << bit0 );
166
+ #elif defined(AFIO_EXTICR1_EXTI0 )
167
+ /*
168
+ * CH32V20x style with multiple registers with 4 pins per register and 4 bits per
169
+ * map.
170
+ */
171
+ BUILD_ASSERT (AFIO_EXTICR1_EXTI0 == 0x0F );
172
+ BUILD_ASSERT (ARRAY_SIZE (afio -> EXTICR ) == 4 );
173
+
174
+ cr_id = pin / 4 ;
175
+ bit0 = (pin % 4 ) << 4 ;
176
+ afio -> EXTICR [cr_id ] =
177
+ (afio -> EXTICR [cr_id ] & ~(AFIO_EXTICR1_EXTI0 << bit0 )) | (port_id << bit0 );
178
+ #else
179
+ #error Unrecognised EXTICR format
180
+ #endif
181
+
182
+ return 0 ;
183
+ }
184
+
185
+ static int gpio_ch32v00x_pin_interrupt_configure (const struct device * dev , gpio_pin_t pin ,
186
+ enum gpio_int_mode mode ,
187
+ enum gpio_int_trig trigger )
188
+ {
189
+ int err ;
190
+
191
+ switch (mode ) {
192
+ case GPIO_INT_MODE_DISABLED :
193
+ wch_exti_disable (pin );
194
+ err = wch_exti_configure (pin , NULL , NULL );
195
+ break ;
196
+ case GPIO_INT_MODE_EDGE :
197
+ err = wch_exti_configure (pin , gpio_ch32v00x_isr , (void * )dev );
198
+ if (err != 0 ) {
199
+ break ;
200
+ }
201
+
202
+ err = gpio_ch32v00x_configure_exti (dev , pin );
203
+ if (err != 0 ) {
204
+ break ;
205
+ }
206
+
207
+ switch (trigger ) {
208
+ case GPIO_INT_TRIG_LOW :
209
+ wch_exti_set_trigger (pin , WCH_EXTI_TRIGGER_FALLING_EDGE );
210
+ break ;
211
+ case GPIO_INT_TRIG_HIGH :
212
+ wch_exti_set_trigger (pin , WCH_EXTI_TRIGGER_RISING_EDGE );
213
+ break ;
214
+ case GPIO_INT_TRIG_BOTH :
215
+ wch_exti_set_trigger (pin , WCH_EXTI_TRIGGER_FALLING_EDGE |
216
+ WCH_EXTI_TRIGGER_RISING_EDGE );
217
+ break ;
218
+ default :
219
+ return - ENOTSUP ;
220
+ }
221
+
222
+ wch_exti_enable (pin );
223
+ break ;
224
+ default :
225
+ return - ENOTSUP ;
226
+ }
227
+
228
+ return err ;
229
+ }
230
+
231
+ static int gpio_ch32v00x_manage_callback (const struct device * dev , struct gpio_callback * callback ,
232
+ bool set )
233
+ {
234
+ struct gpio_ch32v00x_data * data = dev -> data ;
235
+
236
+ return gpio_manage_callback (& data -> callbacks , callback , set );
237
+ }
238
+
239
+ #endif /* CONFIG_GPIO_WCH_GPIO_INTERRUPTS */
240
+
114
241
static DEVICE_API (gpio , gpio_ch32v00x_driver_api ) = {
115
242
.pin_configure = gpio_ch32v00x_configure ,
116
243
.port_get_raw = gpio_ch32v00x_port_get_raw ,
117
244
.port_set_masked_raw = gpio_ch32v00x_port_set_masked_raw ,
118
245
.port_set_bits_raw = gpio_ch32v00x_port_set_bits_raw ,
119
246
.port_clear_bits_raw = gpio_ch32v00x_port_clear_bits_raw ,
120
247
.port_toggle_bits = gpio_ch32v00x_port_toggle_bits ,
248
+ #if defined(CONFIG_GPIO_WCH_GPIO_INTERRUPTS )
249
+ .pin_interrupt_configure = gpio_ch32v00x_pin_interrupt_configure ,
250
+ .manage_callback = gpio_ch32v00x_manage_callback ,
251
+ #endif
121
252
};
122
253
123
254
static int gpio_ch32v00x_init (const struct device * dev )
0 commit comments