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