1 /*
2  * Copyright (C) 2020-2021 Alibaba Group Holding Limited
3  */
4 
5 #ifndef AOS_GPIOC_CORE_H
6 #define AOS_GPIOC_CORE_H
7 
8 #include <aos/device_core.h>
9 #include <aos/gpioc.h>
10 
11 #define AOS_GPIOC_IRQ_EVENT_P   ((uint32_t)1 << 0)
12 #define AOS_GPIOC_IRQ_EVENT_N   ((uint32_t)1 << 1)
13 
14 struct aos_gpioc;
15 
16 typedef struct {
17     void (*unregister)(struct aos_gpioc *);
18     aos_status_t (*set_mode)(struct aos_gpioc *, uint32_t);
19     void (*enable_irq)(struct aos_gpioc *, uint32_t);
20     void (*disable_irq)(struct aos_gpioc *, uint32_t);
21     int (*get_value)(struct aos_gpioc *, uint32_t);
22     void (*set_value)(struct aos_gpioc *, uint32_t);
23 } aos_gpioc_ops_t;
24 
25 typedef struct {
26     uint32_t id;
27     uint32_t mode;
28     aos_gpio_irq_handler_t irq_handler;
29     void *irq_arg;
30     aos_sem_t irq_sem;
31     aos_event_t irq_event;
32     aos_task_t irq_task;
33     bool hard_irq_en;
34     int value;
35 } aos_gpioc_pin_t;
36 
37 typedef struct aos_gpioc {
38     aos_dev_t dev;
39     aos_spinlock_t lock;
40 
41     /* must be initialized before registration */
42     const aos_gpioc_ops_t *ops;
43     uint32_t num_pins;
44 
45     aos_gpioc_pin_t pins[0];
46 } aos_gpioc_t;
47 
48 #define aos_gpioc_hard_irq_handler(gpioc, pin, polarity) \
49     do { \
50         aos_gpioc_t *_gpioc = (gpioc); \
51         uint32_t _pin = (pin); \
52         uint32_t mode; \
53         uint32_t trig; \
54         uint32_t mask; \
55         aos_irqsave_t flags; \
56         flags = aos_spin_lock_irqsave(&_gpioc->lock); \
57         if (!_gpioc->pins[_pin].hard_irq_en) { \
58             aos_spin_unlock_irqrestore(&_gpioc->lock, flags); \
59             break; \
60         } \
61         mode = _gpioc->pins[_pin].mode; \
62         if ((mode & AOS_GPIO_DIR_MASK) == AOS_GPIO_DIR_INPUT) \
63             trig = mode & AOS_GPIO_IRQ_TRIG_MASK; \
64         else \
65             trig = AOS_GPIO_IRQ_TRIG_NONE; \
66         if (trig == AOS_GPIO_IRQ_TRIG_LEVEL_HIGH || trig == AOS_GPIO_IRQ_TRIG_LEVEL_LOW) { \
67             _gpioc->pins[_pin].hard_irq_en = false; \
68             _gpioc->ops->disable_irq(_gpioc, _pin); \
69         } \
70         if (trig == AOS_GPIO_IRQ_TRIG_EDGE_BOTH) { \
71             mask = (polarity) ? AOS_GPIOC_IRQ_EVENT_P : AOS_GPIOC_IRQ_EVENT_N; \
72         } else if (trig == AOS_GPIO_IRQ_TRIG_EDGE_RISING || trig == AOS_GPIO_IRQ_TRIG_LEVEL_HIGH) { \
73             mask = AOS_GPIOC_IRQ_EVENT_P; \
74         } else if (trig == AOS_GPIO_IRQ_TRIG_EDGE_FALLING || trig == AOS_GPIO_IRQ_TRIG_LEVEL_LOW) { \
75             mask = AOS_GPIOC_IRQ_EVENT_N; \
76         } else { \
77             mask = 0; \
78         } \
79         if (mask) \
80             aos_event_set(&_gpioc->pins[pin].irq_event, mask, AOS_EVENT_OR); \
81         aos_spin_unlock_irqrestore(&_gpioc->lock, flags); \
82     } while (0)
83 
84 #ifdef __cplusplus
85 extern "C" {
86 #endif
87 
88 aos_status_t aos_gpioc_register(aos_gpioc_t *gpioc);
89 aos_status_t aos_gpioc_unregister(uint32_t id);
90 
91 #ifdef __cplusplus
92 }
93 #endif
94 
95 #endif /* AOS_GPIOC_CORE_H */
96