ref: 3dbca6b9fbd1d797a9e92504f950506dad2570ed
parent: 5a5318473e00aa854d00573abba1725af7b140dd
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri Aug 19 23:36:11 EDT 2022
imx8/gpio: add interrupt handlers support
--- a/sys/src/9/imx8/dat.h
+++ b/sys/src/9/imx8/dat.h
@@ -10,6 +10,12 @@
enum {
Mhz = 1000 * 1000,
+
+ GpioLow = 0,
+ GpioHigh,
+ GpioRising,
+ GpioFalling,
+ GpioEdge,
};
typedef struct Conf Conf;
--- a/sys/src/9/imx8/fns.h
+++ b/sys/src/9/imx8/fns.h
@@ -159,6 +159,9 @@
#define GPIO_PIN(n, m) ((n)<<5 | (m))
extern void gpioout(uint pin, int set);
extern int gpioin(uint pin);
+void gpiointrenable(uint pin, int mode, void (*f)(uint pin, void *a), void *a);
+void gpiointrdisable(uint pin);
+void gpioinit(void);
/* pciimx */
extern int pcicfgrw8(int tbdf, int rno, int data, int read);
--- a/sys/src/9/imx8/gpio.c
+++ b/sys/src/9/imx8/gpio.c
@@ -18,6 +18,13 @@
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 @@
char *clk;
u32int dir;
int enabled;
+ Ivec vec[32];
+ Lock;
};
static Ctlr ctlrs[5] = {
@@ -79,4 +88,85 @@
if(ctlr->dir & bit)
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");
}
--- a/sys/src/9/imx8/io.h
+++ b/sys/src/9/imx8/io.h
@@ -28,6 +28,17 @@
IRQsctr0 = SPI+47,
IRQsctr1 = SPI+48,
+ IRQgpio1l = SPI+64,
+ IRQgpio1h = SPI+65,
+ IRQgpio2l = SPI+66,
+ IRQgpio2h = SPI+67,
+ IRQgpio3l = SPI+68,
+ IRQgpio3h = SPI+69,
+ IRQgpio4l = SPI+70,
+ IRQgpio4h = SPI+71,
+ IRQgpio5l = SPI+72,
+ IRQgpio5h = SPI+73,
+
IRQpci2 = SPI+74,
IRQsai2 = SPI+96,