1 /*
2 * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3 */
4
5 #include <aos/gpioc_core.h>
6
7 #define IRQ_TASK_STACK_SIZE 4096
8 #define IRQ_TASK_DEFAULT_PRIO 30
9
mode_to_irq_trig(uint32_t mode)10 static uint32_t mode_to_irq_trig(uint32_t mode)
11 {
12 uint32_t trig;
13
14 if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_INPUT)
15 trig = mode & AOS_GPIO_IRQ_TRIG_MASK;
16 else
17 trig = AOS_GPIO_IRQ_TRIG_NONE;
18
19 return trig;
20 }
21
aos_gpioc_get(aos_gpioc_ref_t * ref,uint32_t id)22 aos_status_t aos_gpioc_get(aos_gpioc_ref_t *ref, uint32_t id)
23 {
24 return aos_dev_get(ref, AOS_DEV_TYPE_GPIOC, id);
25 }
26
aos_gpioc_put(aos_gpioc_ref_t * ref)27 void aos_gpioc_put(aos_gpioc_ref_t *ref)
28 {
29 aos_dev_put(ref);
30 }
31
aos_gpioc_get_num_pins(aos_gpioc_ref_t * ref)32 aos_status_t aos_gpioc_get_num_pins(aos_gpioc_ref_t *ref)
33 {
34 aos_gpioc_t *gpioc;
35
36 if (!ref || !aos_dev_ref_is_valid(ref))
37 return -EINVAL;
38
39 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
40
41 return gpioc->num_pins;
42 }
43
aos_gpioc_get_mode(aos_gpioc_ref_t * ref,uint32_t pin,uint32_t * mode)44 aos_status_t aos_gpioc_get_mode(aos_gpioc_ref_t *ref, uint32_t pin, uint32_t *mode)
45 {
46 aos_gpioc_t *gpioc;
47
48 if (!ref || !aos_dev_ref_is_valid(ref) || !mode)
49 return -EINVAL;
50
51 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
52
53 if (pin >= gpioc->num_pins)
54 return -EINVAL;
55
56 aos_dev_lock(ref->dev);
57 *mode = gpioc->pins[pin].mode;
58 aos_dev_unlock(ref->dev);
59
60 return 0;
61 }
62
aos_gpioc_set_mode(aos_gpioc_ref_t * ref,uint32_t pin,uint32_t mode)63 aos_status_t aos_gpioc_set_mode(aos_gpioc_ref_t *ref, uint32_t pin, uint32_t mode)
64 {
65 return aos_gpioc_set_mode_irq(ref, pin, mode, NULL, NULL);
66 }
67
irq_task_func(void * arg)68 static void irq_task_func(void *arg)
69 {
70 aos_gpioc_pin_t *pin = (aos_gpioc_pin_t *)arg;
71 aos_gpioc_t *gpioc;
72
73 gpioc = aos_container_of(pin, aos_gpioc_t, pins[pin->id]);
74
75 while (1) {
76 uint32_t event_mask;
77 uint32_t event_value;
78 uint32_t trig;
79
80 event_mask = AOS_GPIOC_IRQ_EVENT_P | AOS_GPIOC_IRQ_EVENT_N;
81 (void)aos_event_get(&pin->irq_event, event_mask, AOS_EVENT_OR_CLEAR, &event_value, AOS_WAIT_FOREVER);
82 (void)aos_sem_wait(&pin->irq_sem, AOS_WAIT_FOREVER);
83 trig = mode_to_irq_trig(pin->mode);
84 if (trig == AOS_GPIO_IRQ_TRIG_NONE) {
85 aos_sem_signal(&pin->irq_sem);
86 continue;
87 }
88
89 if ((trig == AOS_GPIO_IRQ_TRIG_LEVEL_HIGH || trig == AOS_GPIO_IRQ_TRIG_EDGE_RISING ||
90 trig == AOS_GPIO_IRQ_TRIG_EDGE_BOTH) &&
91 (event_value & AOS_GPIOC_IRQ_EVENT_P))
92 pin->irq_handler(1, pin->irq_arg);
93
94 if ((trig == AOS_GPIO_IRQ_TRIG_LEVEL_LOW || trig == AOS_GPIO_IRQ_TRIG_EDGE_FALLING ||
95 trig == AOS_GPIO_IRQ_TRIG_EDGE_BOTH) &&
96 (event_value & AOS_GPIOC_IRQ_EVENT_N))
97 pin->irq_handler(0, pin->irq_arg);
98
99 if (trig == AOS_GPIO_IRQ_TRIG_LEVEL_HIGH || trig == AOS_GPIO_IRQ_TRIG_LEVEL_LOW) {
100 aos_irqsave_t flags;
101 flags = aos_spin_lock_irqsave(&gpioc->lock);
102 pin->hard_irq_en = true;
103 gpioc->ops->enable_irq(gpioc, pin->id);
104 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
105 }
106
107 aos_sem_signal(&pin->irq_sem);
108 }
109 }
110
aos_gpioc_set_mode_irq(aos_gpioc_ref_t * ref,uint32_t pin,uint32_t mode,aos_gpio_irq_handler_t irq_handler,void * irq_arg)111 aos_status_t aos_gpioc_set_mode_irq(aos_gpioc_ref_t *ref, uint32_t pin, uint32_t mode,
112 aos_gpio_irq_handler_t irq_handler, void *irq_arg)
113 {
114 aos_gpioc_t *gpioc;
115 uint32_t old_mode;
116 aos_gpio_irq_handler_t old_irq_handler;
117 void *old_irq_arg;
118 aos_task_t old_task;
119 aos_status_t ret;
120
121 if (!ref || !aos_dev_ref_is_valid(ref))
122 return -EINVAL;
123
124 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
125
126 if (pin >= gpioc->num_pins)
127 return -EINVAL;
128
129 if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_NONE) {
130 } else if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_INPUT) {
131 switch (mode & AOS_GPIO_INPUT_CFG_MASK) {
132 case AOS_GPIO_INPUT_CFG_DEFAULT:
133 case AOS_GPIO_INPUT_CFG_HI:
134 case AOS_GPIO_INPUT_CFG_PU:
135 case AOS_GPIO_INPUT_CFG_PD:
136 break;
137 default:
138 return -EINVAL;
139 }
140
141 switch (mode & AOS_GPIO_IRQ_TRIG_MASK) {
142 case AOS_GPIO_IRQ_TRIG_NONE:
143 if (irq_handler)
144 return -EINVAL;
145 break;
146 case AOS_GPIO_IRQ_TRIG_EDGE_RISING:
147 case AOS_GPIO_IRQ_TRIG_EDGE_FALLING:
148 case AOS_GPIO_IRQ_TRIG_EDGE_BOTH:
149 case AOS_GPIO_IRQ_TRIG_LEVEL_HIGH:
150 case AOS_GPIO_IRQ_TRIG_LEVEL_LOW:
151 if (!irq_handler)
152 return -EINVAL;
153 break;
154 default:
155 return -EINVAL;
156 }
157 } else if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_OUTPUT) {
158 switch (mode & AOS_GPIO_OUTPUT_CFG_MASK) {
159 case AOS_GPIO_OUTPUT_CFG_DEFAULT:
160 case AOS_GPIO_OUTPUT_CFG_PP:
161 case AOS_GPIO_OUTPUT_CFG_ODNP:
162 case AOS_GPIO_OUTPUT_CFG_ODPU:
163 break;
164 default:
165 return -EINVAL;
166 }
167 } else {
168 return -EINVAL;
169 }
170
171 (void)aos_sem_wait(&gpioc->pins[pin].irq_sem, AOS_WAIT_FOREVER);
172 old_mode = gpioc->pins[pin].mode;
173 old_irq_handler = gpioc->pins[pin].irq_handler;
174 old_irq_arg = gpioc->pins[pin].irq_arg;
175
176 if (mode_to_irq_trig(old_mode) != AOS_GPIO_IRQ_TRIG_NONE) {
177 aos_irqsave_t flags;
178
179 old_task = gpioc->pins[pin].irq_task;
180 flags = aos_spin_lock_irqsave(&gpioc->lock);
181 (void)aos_event_set(&gpioc->pins[pin].irq_event, 0, AOS_EVENT_AND);
182
183 if (gpioc->pins[pin].hard_irq_en) {
184 gpioc->pins[pin].hard_irq_en = false;
185 gpioc->ops->disable_irq(gpioc, pin);
186 }
187
188 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
189 }
190
191 if (mode_to_irq_trig(mode) != AOS_GPIO_IRQ_TRIG_NONE) {
192 uint32_t prio;
193
194 if ((mode & AOS_GPIO_IRQ_PRIO_MASK) == AOS_GPIO_IRQ_PRIO_DEFAULT)
195 prio = IRQ_TASK_DEFAULT_PRIO;
196 else
197 prio = (mode & AOS_GPIO_IRQ_PRIO_MASK) >> 16;
198
199 ret = aos_task_new_ext(&gpioc->pins[pin].irq_task, "gpio_irq_task", irq_task_func,
200 &gpioc->pins[pin], IRQ_TASK_STACK_SIZE, prio);
201 if (ret) {
202 if (mode_to_irq_trig(old_mode) != AOS_GPIO_IRQ_TRIG_NONE) {
203 aos_irqsave_t flags;
204 gpioc->pins[pin].irq_task = old_task;
205 flags = aos_spin_lock_irqsave(&gpioc->lock);
206 gpioc->pins[pin].hard_irq_en = true;
207 gpioc->ops->enable_irq(gpioc, pin);
208 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
209 }
210
211 aos_sem_signal(&gpioc->pins[pin].irq_sem);
212 return ret;
213 }
214 }
215
216 aos_dev_lock(ref->dev);
217 gpioc->pins[pin].mode = mode;
218 gpioc->pins[pin].irq_handler = irq_handler;
219 gpioc->pins[pin].irq_arg = irq_arg;
220
221 if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_OUTPUT)
222 gpioc->pins[pin].value = !!(mode & AOS_GPIO_OUTPUT_INIT_HIGH);
223 else
224 gpioc->pins[pin].value = 0;
225
226 ret = gpioc->ops->set_mode(gpioc, pin);
227 if (ret) {
228 gpioc->pins[pin].mode = old_mode;
229 gpioc->pins[pin].irq_handler = old_irq_handler;
230 gpioc->pins[pin].irq_arg = old_irq_arg;
231 aos_dev_unlock(ref->dev);
232
233 if (mode_to_irq_trig(mode) != AOS_GPIO_IRQ_TRIG_NONE)
234 (void)aos_task_delete(&gpioc->pins[pin].irq_task);
235
236 if (mode_to_irq_trig(old_mode) != AOS_GPIO_IRQ_TRIG_NONE) {
237 aos_irqsave_t flags;
238 gpioc->pins[pin].irq_task = old_task;
239 flags = aos_spin_lock_irqsave(&gpioc->lock);
240 gpioc->pins[pin].hard_irq_en = true;
241 gpioc->ops->enable_irq(gpioc, pin);
242 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
243 }
244
245 aos_sem_signal(&gpioc->pins[pin].irq_sem);
246 return ret;
247 }
248
249 aos_dev_unlock(ref->dev);
250
251 if (mode_to_irq_trig(old_mode) != AOS_GPIO_IRQ_TRIG_NONE)
252 (void)aos_task_delete(&old_task);
253
254 if (mode_to_irq_trig(mode) != AOS_GPIO_IRQ_TRIG_NONE) {
255 aos_irqsave_t flags;
256 flags = aos_spin_lock_irqsave(&gpioc->lock);
257 gpioc->pins[pin].hard_irq_en = true;
258 gpioc->ops->enable_irq(gpioc, pin);
259 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
260 }
261
262 aos_sem_signal(&gpioc->pins[pin].irq_sem);
263
264 return 0;
265 }
266
aos_gpioc_get_value(aos_gpioc_ref_t * ref,uint32_t pin)267 aos_status_t aos_gpioc_get_value(aos_gpioc_ref_t *ref, uint32_t pin)
268 {
269 aos_gpioc_t *gpioc;
270 uint32_t mode;
271 aos_status_t ret;
272
273 if (!ref || !aos_dev_ref_is_valid(ref))
274 return -EINVAL;
275
276 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
277
278 if (pin >= gpioc->num_pins)
279 return -EINVAL;
280
281 aos_dev_lock(ref->dev);
282 mode = gpioc->pins[pin].mode;
283
284 if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_INPUT)
285 ret = (aos_status_t)!!gpioc->ops->get_value(gpioc, pin);
286 else if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_OUTPUT)
287 ret = (aos_status_t)gpioc->pins[pin].value;
288 else
289 ret = -ENOTSUP;
290
291 aos_dev_unlock(ref->dev);
292
293 return ret;
294 }
295
aos_gpioc_set_value(aos_gpioc_ref_t * ref,uint32_t pin,int val)296 aos_status_t aos_gpioc_set_value(aos_gpioc_ref_t *ref, uint32_t pin, int val)
297 {
298 aos_gpioc_t *gpioc;
299 uint32_t mode;
300
301 if (!ref || !aos_dev_ref_is_valid(ref) || val < 0)
302 return -EINVAL;
303
304 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
305
306 if (pin >= gpioc->num_pins)
307 return -EINVAL;
308
309 aos_dev_lock(ref->dev);
310 mode = gpioc->pins[pin].mode;
311
312 if ((mode & AOS_GPIO_DIR_MASK) != AOS_GPIO_DIR_OUTPUT) {
313 aos_dev_unlock(ref->dev);
314 return -ENOTSUP;
315 }
316
317 val = !!val;
318 if (gpioc->pins[pin].value == val) {
319 aos_dev_unlock(ref->dev);
320 return 0;
321 }
322
323 gpioc->pins[pin].value = val;
324 gpioc->ops->set_value(gpioc, pin);
325 aos_dev_unlock(ref->dev);
326
327 return 0;
328 }
329
aos_gpioc_toggle(aos_gpioc_ref_t * ref,uint32_t pin)330 aos_status_t aos_gpioc_toggle(aos_gpioc_ref_t *ref, uint32_t pin)
331 {
332 aos_gpioc_t *gpioc;
333 uint32_t mode;
334
335 if (!ref || !aos_dev_ref_is_valid(ref))
336 return -EINVAL;
337
338 gpioc = aos_container_of(ref->dev, aos_gpioc_t, dev);
339
340 if (pin >= gpioc->num_pins)
341 return -EINVAL;
342
343 aos_dev_lock(ref->dev);
344 mode = gpioc->pins[pin].mode;
345
346 if ((mode & AOS_GPIO_DIR_MASK) != AOS_GPIO_DIR_OUTPUT) {
347 aos_dev_unlock(ref->dev);
348 return -ENOTSUP;
349 }
350
351 gpioc->pins[pin].value = !gpioc->pins[pin].value;
352 gpioc->ops->set_value(gpioc, pin);
353 aos_dev_unlock(ref->dev);
354
355 return 0;
356 }
357
dev_gpioc_unregister(aos_dev_t * dev)358 static void dev_gpioc_unregister(aos_dev_t *dev)
359 {
360 aos_gpioc_t *gpioc = aos_container_of(dev, aos_gpioc_t, dev);
361
362 for (uint32_t i = 0; i < gpioc->num_pins; i++) {
363 aos_gpioc_pin_t *pin = &gpioc->pins[i];
364
365 if (mode_to_irq_trig(pin->mode) != AOS_GPIO_IRQ_TRIG_NONE) {
366 aos_irqsave_t flags;
367
368 /* no deadlock here */
369 (void)aos_sem_wait(&pin->irq_sem, AOS_WAIT_FOREVER);
370 (void)aos_task_delete(&pin->irq_task);
371 flags = aos_spin_lock_irqsave(&gpioc->lock);
372
373 if (pin->hard_irq_en) {
374 pin->hard_irq_en = false;
375 gpioc->ops->disable_irq(gpioc, i);
376 }
377
378 aos_spin_unlock_irqrestore(&gpioc->lock, flags);
379 }
380
381 pin->mode = AOS_GPIO_DIR_NONE;
382 (void)gpioc->ops->set_mode(gpioc, i);
383 aos_sem_free(&pin->irq_sem);
384 aos_event_free(&pin->irq_event);
385 }
386
387 if (gpioc->ops->unregister)
388 gpioc->ops->unregister(gpioc);
389 }
390
dev_gpioc_get(aos_dev_ref_t * ref)391 static aos_status_t dev_gpioc_get(aos_dev_ref_t *ref)
392 {
393 return 0;
394 }
395
dev_gpioc_put(aos_dev_ref_t * ref)396 static void dev_gpioc_put(aos_dev_ref_t *ref)
397 {
398 }
399
400 static const aos_dev_ops_t dev_gpioc_ops = {
401 .unregister = dev_gpioc_unregister,
402 .get = dev_gpioc_get,
403 .put = dev_gpioc_put,
404 };
405
aos_gpioc_register(aos_gpioc_t * gpioc)406 aos_status_t aos_gpioc_register(aos_gpioc_t *gpioc)
407 {
408 aos_status_t ret;
409
410 if (!gpioc)
411 return -EINVAL;
412
413 if (!gpioc->ops || !gpioc->ops->set_mode || !gpioc->ops->enable_irq ||
414 !gpioc->ops->disable_irq || !gpioc->ops->get_value || !gpioc->ops->set_value)
415 return -EINVAL;
416
417 gpioc->dev.type = AOS_DEV_TYPE_GPIOC;
418 gpioc->dev.ops = &dev_gpioc_ops;
419 #ifdef AOS_COMP_VFS
420 gpioc->dev.vfs_helper.name[0] = '\0';
421 gpioc->dev.vfs_helper.ops = NULL;
422 #endif
423 aos_spin_lock_init(&gpioc->lock);
424
425 for (uint32_t i = 0; i < gpioc->num_pins; i++) {
426 aos_gpioc_pin_t *pin = &gpioc->pins[i];
427
428 pin->id = i;
429 pin->mode = AOS_GPIO_DIR_NONE;
430 pin->irq_handler = NULL;
431 pin->irq_arg = NULL;
432 pin->hard_irq_en = false;
433 pin->value = 0;
434
435 ret = aos_sem_new(&pin->irq_sem, 1);
436 if (ret) {
437 for (uint32_t j = 0; j < i; j++) {
438 aos_sem_free(&gpioc->pins[j].irq_sem);
439 aos_event_free(&gpioc->pins[j].irq_event);
440 }
441
442 return ret;
443 }
444
445 ret = aos_event_new(&pin->irq_event, 0);
446 if (ret) {
447 aos_sem_free(&gpioc->pins[i].irq_sem);
448
449 for (uint32_t j = 0; j < i; j++) {
450 aos_sem_free(&gpioc->pins[j].irq_sem);
451 aos_event_free(&gpioc->pins[j].irq_event);
452 }
453
454 return ret;
455 }
456 }
457
458 ret = aos_dev_register(&gpioc->dev);
459 if (ret) {
460 for (uint32_t i = 0; i < gpioc->num_pins; i++) {
461 aos_sem_free(&gpioc->pins[i].irq_sem);
462 aos_event_free(&gpioc->pins[i].irq_event);
463 }
464
465 return ret;
466 }
467
468 return 0;
469 }
470
aos_gpioc_unregister(uint32_t id)471 aos_status_t aos_gpioc_unregister(uint32_t id)
472 {
473 return aos_dev_unregister(AOS_DEV_TYPE_GPIOC, id);
474 }
475