code: plan9front

Download patch

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,