summaryrefslogtreecommitdiff
path: root/sys/src/9/imx8/gpio.c
diff options
context:
space:
mode:
authorSigrid Solveig Haflínudóttir <sigrid@ftrv.se>2022-08-20 03:36:11 +0000
committerSigrid Solveig Haflínudóttir <sigrid@ftrv.se>2022-08-20 03:36:11 +0000
commit3dbca6b9fbd1d797a9e92504f950506dad2570ed (patch)
tree1f2e1e9e7975f148b123e947401a02fce4d98f47 /sys/src/9/imx8/gpio.c
parent5a5318473e00aa854d00573abba1725af7b140dd (diff)
imx8/gpio: add interrupt handlers support
Diffstat (limited to 'sys/src/9/imx8/gpio.c')
-rw-r--r--sys/src/9/imx8/gpio.c90
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");
+}