13
#include <kernel/lthread/lthread.h>
14
#include <mem/misc/pool.h>
16
#include <lib/libds/bit.h>
17
#include <lib/libds/dlist.h>
18
#include <lib/libds/array.h>
20
#include <drivers/gpio/gpio.h>
21
#include <drivers/gpio/gpio_driver.h>
23
#define GPIO_CHIPS_COUNT OPTION_GET(NUMBER,gpio_chips_count)
24
#define GPIO_IRQS_COUNT OPTION_GET(NUMBER,gpio_irqs_count)
25
#define GPIO_HND_PRIORITY OPTION_GET(NUMBER,gpio_hnd_prio)
27
ARRAY_SPREAD_DECLARE(struct gpio_chip *, __gpio_chip_registry);
29
static struct gpio_chip *gpio_chip_registry[GPIO_CHIPS_COUNT];
31
int gpio_register_chip(struct gpio_chip *chip, unsigned char chip_id) {
34
if (chip_id >= GPIO_CHIPS_COUNT) {
35
log_error("GPIO chip id=%d exceeds max id=%d\n",
36
chip_id, GPIO_CHIPS_COUNT);
39
if (gpio_chip_registry[chip_id]) {
40
log_error("GPIO chip id%d is registered already\n", chip_id);
43
gpio_chip_registry[chip_id] = chip;
48
static struct gpio_chip *gpio_get_chip(unsigned char chip_nr) {
50
if ((GPIO_CHIPS_COUNT - 1) < chip_nr) {
53
if (NULL != gpio_chip_registry[chip_nr]) {
54
return gpio_chip_registry[chip_nr];
57
if (ARRAY_SPREAD_SIZE(__gpio_chip_registry) != 0) {
58
return __gpio_chip_registry[0];
63
int gpio_setup_mode(unsigned short port, gpio_mask_t pins, int mode) {
64
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
67
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
70
port = GPIO_PORT(port);
71
if (port >= chip->nports) {
72
log_error("port (%d) is out of range (nports=%d)",
73
port, chip->nports - 1);
76
assert(chip->setup_mode);
78
return chip->setup_mode(port, pins, mode);
81
void gpio_set(unsigned short port, gpio_mask_t pins, char level) {
82
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
85
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
88
port = GPIO_PORT(port);
89
if (port >= chip->nports) {
90
log_error("port (%d) is out of range (nports=%d)",
91
port, chip->nports - 1);
95
chip->set(port, pins, level);
98
gpio_mask_t gpio_get(unsigned short port, gpio_mask_t pins) {
99
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
102
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
105
port = GPIO_PORT(port);
106
if (port >= chip->nports) {
107
log_error("port (%d) is out of range (nports=%d)",
108
port, chip->nports - 1);
113
return chip->get(port, pins);
116
void gpio_toggle(unsigned short port, gpio_mask_t pins) {
117
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
121
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
124
port = GPIO_PORT(port);
125
if (port >= chip->nports) {
126
log_error("port (%d) is out of range (nports=%d)",
127
port, chip->nports - 1);
130
assert(chip->get && chip->set);
131
state = chip->get(port, pins);
132
chip->set(port, state, 0);
133
chip->set(port, ~state & pins, 1);
136
#if (GPIO_IRQS_COUNT > 0)
137
#define DO_IPL_LOCKED(job) \
139
ipl_t _ipl = ipl_save(); \
144
struct gpio_irq_handler {
145
struct gpio_chip *chip;
149
void (*handler)(void *);
150
struct dlist_head link;
153
static int gpio_lthread_irq_hnd(struct lthread *self);
154
static LTHREAD_DEF(gpio_lthread, gpio_lthread_irq_hnd, GPIO_HND_PRIORITY);
156
POOL_DEF(gpio_irq_pool, struct gpio_irq_handler, GPIO_IRQS_COUNT);
158
static DLIST_DEFINE(gpio_irq_list);
159
static DLIST_DEFINE(gpio_pending_irq_list);
161
int gpio_irq_attach(unsigned short port, uint32_t pin,
162
void (*pin_handler)(void *), void *data) {
163
struct gpio_irq_handler *gpio_hnd;
164
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
167
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
170
port = GPIO_PORT(port);
171
if (port >= chip->nports) {
172
log_error("port (%d) is out of range (nports=%d)",
173
port, chip->nports - 1);
176
gpio_hnd = pool_alloc(&gpio_irq_pool);
178
log_error("chip=%d, gpio_hnd=%p",
179
GPIO_CHIP(port), gpio_hnd);
183
gpio_hnd->chip = chip;
184
gpio_hnd->port = port;
186
gpio_hnd->data = data;
187
gpio_hnd->handler = pin_handler;
190
dlist_add_next(dlist_head_init(&gpio_hnd->link), &gpio_irq_list);
196
int gpio_irq_detach(unsigned short port, uint32_t pin) {
197
struct gpio_irq_handler *gpio_hnd;
198
struct gpio_chip *chip = gpio_get_chip(GPIO_CHIP(port));
201
log_error("Chip not found, chip=%d", GPIO_CHIP(port));
205
port = GPIO_PORT(port);
207
dlist_foreach_entry_safe(gpio_hnd, &gpio_irq_list, link) {
208
if ((gpio_hnd->chip == chip)
209
&& (gpio_hnd->port == port)
210
&& (gpio_hnd->pin == pin)) {
211
DO_IPL_LOCKED(dlist_del(&gpio_hnd->link));
212
pool_free(&gpio_irq_pool, gpio_hnd);
221
static int gpio_lthread_irq_hnd(struct lthread *self) {
222
struct gpio_irq_handler *gpio_hnd;
224
dlist_foreach_entry_safe(gpio_hnd, &gpio_pending_irq_list, link) {
225
gpio_hnd->handler(gpio_hnd->data);
229
dlist_del(&gpio_hnd->link);
230
dlist_add_prev(&gpio_hnd->link, &gpio_irq_list);
237
void gpio_handle_irq(struct gpio_chip *chip, uint8_t port, gpio_mask_t pins) {
238
struct gpio_irq_handler *gpio_hnd;
242
bit_foreach(pin, pins) {
243
dlist_foreach_entry_safe(gpio_hnd, &gpio_irq_list, link) {
244
if ((gpio_hnd->chip == chip)
245
&& (gpio_hnd->port == port)
246
&& (gpio_hnd->pin == (1 << pin))) {
250
dlist_del(&gpio_hnd->link);
251
dlist_add_prev(&gpio_hnd->link, &gpio_pending_irq_list);
260
lthread_launch(&gpio_lthread);