diff options
author | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-08-20 03:36:11 +0000 |
---|---|---|
committer | Sigrid Solveig Haflínudóttir <sigrid@ftrv.se> | 2022-08-20 03:36:11 +0000 |
commit | 3dbca6b9fbd1d797a9e92504f950506dad2570ed (patch) | |
tree | 1f2e1e9e7975f148b123e947401a02fce4d98f47 /sys/src/9/imx8/gpio.c | |
parent | 5a5318473e00aa854d00573abba1725af7b140dd (diff) |
imx8/gpio: add interrupt handlers support
Diffstat (limited to 'sys/src/9/imx8/gpio.c')
-rw-r--r-- | sys/src/9/imx8/gpio.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/sys/src/9/imx8/gpio.c b/sys/src/9/imx8/gpio.c index 0fdb3aefd..27092a17e 100644 --- a/sys/src/9/imx8/gpio.c +++ b/sys/src/9/imx8/gpio.c @@ -18,6 +18,13 @@ enum { GPIO_EDGE_SEL = 0x1C/4, }; +typedef struct Ivec Ivec; +struct Ivec +{ + void (*f)(uint pin, void *a); + void *a; +}; + typedef struct Ctlr Ctlr; struct Ctlr { @@ -25,6 +32,8 @@ struct Ctlr char *clk; u32int dir; int enabled; + Ivec vec[32]; + Lock; }; static Ctlr ctlrs[5] = { @@ -80,3 +89,84 @@ gpioin(uint pin) ctlr->reg[GPIO_GDIR] = ctlr->dir &= ~bit; return (ctlr->reg[GPIO_DR] & bit) != 0; } + +void +gpiointrenable(uint pin, int mode, void (*f)(uint pin, void *a), void *a) +{ + u32int bit = 1 << (pin % 32); + Ctlr *ctlr = enable(pin); + if(ctlr == nil) + return; + ctlr->reg[GPIO_IMR] &= ~bit; + + ilock(ctlr); + if(ctlr->dir & bit) + ctlr->reg[GPIO_GDIR] = ctlr->dir &= ~bit; + + if(mode == GpioEdge) + ctlr->reg[GPIO_EDGE_SEL] |= bit; + else if(bit < 16) + ctlr->reg[GPIO_ICR1] |= mode << (bit*2); + else + ctlr->reg[GPIO_ICR2] |= mode << (bit-16)*2; + + ctlr->vec[pin % 32].f = f; + ctlr->vec[pin % 32].a = a; + iunlock(ctlr); + + ctlr->reg[GPIO_IMR] |= bit; +} + +void +gpiointrdisable(uint pin) +{ + u32int bit = 1 << (pin % 32); + Ctlr *ctlr = enable(pin); + if(ctlr == nil) + return; + + ctlr->reg[GPIO_IMR] &= ~bit; + + ilock(ctlr); + ctlr->vec[pin % 32].f = nil; + ctlr->vec[pin % 32].a = nil; + iunlock(ctlr); +} + +static void +gpiointerrupt(Ureg *, void *arg) +{ + Ctlr *ctlr = arg; + u32int status; + Ivec *vec; + int pin; + + status = ctlr->reg[GPIO_ISR]; + if(status == 0) + return; + ctlr->reg[GPIO_ISR] = status; + + ilock(ctlr); + for(vec = ctlr->vec; status != 0 && vec < &ctlr->vec[nelem(ctlr->vec)]; vec++, status >>= 1){ + if((status & 1) != 0 && vec->f != nil){ + pin = (ctlr - ctlrs + 1)<<5 | (vec - ctlr->vec); + (*vec->f)(pin, vec->a); + } + } + iunlock(ctlr); +} + +void +gpioinit(void) +{ + intrenable(IRQgpio1l, gpiointerrupt, &ctlrs[0], BUSUNKNOWN, "gpio1"); + intrenable(IRQgpio1h, gpiointerrupt, &ctlrs[0], BUSUNKNOWN, "gpio1"); + intrenable(IRQgpio2l, gpiointerrupt, &ctlrs[1], BUSUNKNOWN, "gpio2"); + intrenable(IRQgpio2h, gpiointerrupt, &ctlrs[1], BUSUNKNOWN, "gpio2"); + intrenable(IRQgpio3l, gpiointerrupt, &ctlrs[2], BUSUNKNOWN, "gpio3"); + intrenable(IRQgpio3h, gpiointerrupt, &ctlrs[2], BUSUNKNOWN, "gpio3"); + intrenable(IRQgpio4l, gpiointerrupt, &ctlrs[3], BUSUNKNOWN, "gpio4"); + intrenable(IRQgpio4h, gpiointerrupt, &ctlrs[3], BUSUNKNOWN, "gpio4"); + intrenable(IRQgpio5l, gpiointerrupt, &ctlrs[4], BUSUNKNOWN, "gpio5"); + intrenable(IRQgpio5h, gpiointerrupt, &ctlrs[4], BUSUNKNOWN, "gpio5"); +} |