Port-arm archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

pin control for the ti_gpio driver



Kia ora koutou,
Is the following patch OK to commit?

Quite a while back I put together what I considered a bit of a hack to
allow the ti_gpio to access the pin controller so that it could enable
pullups and pulldowns.

After going around in circles trying several different improved methods
I discovered that other GPIO drivers do exactly the same thing as my
original "hack", so I want to just commit that.

There are two (one and half?) items to note about this patch.

1) Finding the pin controller device_t

The GPIO device needs to know the pin controller's device_t in order to
access the pin controller device driver. For other systems the pin
controller and the GPIO controller have a parent/child relationship and
so this can be trivially handled at attach time.

Texas Instruments has no interest in making it that easy for us and so
I have had to add a function to the FDT framework that allows us to
find the pin controller device_t given a pin controller phandle. This
function looks O(N*M) in time, but it practice it is O(1).

2) or 1.5) GPIO MD knowledge

Under normal circumstances we might want to invent an abstraction for
our pin controller so that the GPIO controller doesn't have to know
what each and every pin controller register value means. 

In this particular case the pin controller is an MI device driver and
so there is no question that all the knowledge about what the registers
mean must go into the GPIO controller. Luckily for us the two GPIO
controllers supported by the ti_gpio driver were only every built with
one common pin controller.

I've been running this code off and on for a while now with a
temperature sensor and I haven't had any problems.

The following patch is against -current and I'm doing a build right now
just to be sure that nothing has gone amiss since the last time I built
current.

Ngā mihi,
Lloyd

-----------------------8<-----------------------
Index: sys/arch/arm/ti/ti_gpio.c
===================================================================
RCS file: /home/lloyd/NetBSD/cvs/mirror/src/sys/arch/arm/ti/ti_gpio.c,v
retrieving revision 1.15
diff -u -r1.15 ti_gpio.c
--- sys/arch/arm/ti/ti_gpio.c	1 Apr 2024 15:52:08 -0000	1.15
+++ sys/arch/arm/ti/ti_gpio.c	28 Oct 2024 21:53:36 -0000
@@ -100,6 +100,11 @@
 	},
 };
 
+#define TI_CM_RX_ENABLE		(1 << 5)
+#define TI_CM_PULLUP		(1 << 4)
+#define TI_CM_PULL_DISABLE	(1 << 3)
+#define TI_CM_MUX_GPIO		7
+
 static const struct device_compatible_entry compat_data[] = {
 	{ .compat = "ti,omap3-gpio",	.value = TI_GPIO_OMAP3 },
 	{ .compat = "ti,omap4-gpio",	.value = TI_GPIO_OMAP4 },
@@ -127,6 +132,7 @@
 	bool sc_pinout[TI_GPIO_NPINS];
 	struct ti_gpio_intr sc_intr[TI_GPIO_NPINS];
 	device_t sc_gpiodev;
+	device_t sc_pcdev;
 };
 
 struct ti_gpio_pin {
@@ -143,6 +149,7 @@
 
 static int	ti_gpio_match(device_t, cfdata_t, void *);
 static void	ti_gpio_attach(device_t, device_t, void *);
+static int	parse_gpio_ranges(struct ti_gpio_softc * const, int);
 
 CFATTACH_DECL_NEW(ti_gpio, sizeof(struct ti_gpio_softc),
 	ti_gpio_match, ti_gpio_attach, NULL, NULL);
@@ -151,17 +158,33 @@
 ti_gpio_ctl(struct ti_gpio_softc *sc, u_int pin, int flags)
 {
 	uint32_t oe;
+	uint32_t cmd;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 
-	oe = RD4(sc, GPIO_OE);
-	if (flags & GPIO_PIN_INPUT)
-		oe |= __BIT(pin);
-	else if (flags & GPIO_PIN_OUTPUT)
-		oe &= ~__BIT(pin);
-	WR4(sc, GPIO_OE, oe);
+        if (flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) {
+		oe = RD4(sc, GPIO_OE);
+		if (flags & GPIO_PIN_INPUT)
+			oe |= __BIT(pin);
+		else if (flags & GPIO_PIN_OUTPUT)
+			oe &= ~__BIT(pin);
+		WR4(sc, GPIO_OE, oe);
+
+		sc->sc_pinout[pin] = (flags & GPIO_PIN_OUTPUT) != 0;
+	}
+
+	if (sc->sc_pins[pin].pin_num >= 0) {
+		if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
+			cmd = (flags & GPIO_PIN_PULLUP) ?
+				TI_CM_PULLUP : 0;
+		} else {
+			cmd = TI_CM_PULL_DISABLE;
+		}
+		cmd |= TI_CM_RX_ENABLE;
 
-	sc->sc_pinout[pin] = (flags & GPIO_PIN_OUTPUT) != 0;
+		pinctrl_single_set_pin(sc->sc_pcdev, sc-
>sc_pins[pin].pin_num,
+				       cmd, TI_CM_MUX_GPIO);
+	}
 
 	return 0;
 }
@@ -532,11 +555,12 @@
 }
 
 static void
-ti_gpio_attach_ports(struct ti_gpio_softc *sc)
+ti_gpio_attach_ports(struct ti_gpio_softc *sc, int phandle)
 {
 	struct gpio_chipset_tag *gp = &sc->sc_gp;
 	struct gpiobus_attach_args gba;
 	u_int pin;
+	int pc_handle;
 
 	gp->gp_cookie = sc;
 	gp->gp_pin_read = ti_gpio_pin_read;
@@ -546,8 +570,14 @@
 	gp->gp_intr_disestablish = ti_gpio_gp_intr_disestablish;
 	gp->gp_intr_str = ti_gpio_gp_intrstr;
 
+	/*
+	 * Following on from ep93xx we also use the otherwise unused
+	 * pin_num field to refer to the pin number used by the
+	 * pinctrl module.
+	 */
+	
 	for (pin = 0; pin < __arraycount(sc->sc_pins); pin++) {
-		sc->sc_pins[pin].pin_num = pin;
+		sc->sc_pins[pin].pin_num = -1;
 		sc->sc_pins[pin].pin_caps = GPIO_PIN_INPUT |
GPIO_PIN_OUTPUT;
 		sc->sc_pins[pin].pin_intrcaps =
 		    GPIO_INTR_POS_EDGE | GPIO_INTR_NEG_EDGE |
@@ -556,6 +586,12 @@
 		sc->sc_pins[pin].pin_state = ti_gpio_pin_read(sc,
pin);
 	}
 
+	/* Maybe update pin_num and pin_caps. */
+	pc_handle = parse_gpio_ranges(sc, phandle);
+	if (pc_handle >= 0)
+		sc->sc_pcdev = fdtbus_pinctrl_lookup_dev(pc_handle);
+	/* Some logging here if sc->sc_pcdev is still NULL would be
nice. */
+
 	memset(&gba, 0, sizeof(gba));
 	gba.gba_gc = gp;
 	gba.gba_pins = sc->sc_pins;
@@ -642,7 +678,7 @@
 
 	fdtbus_register_gpio_controller(self, phandle,
&ti_gpio_funcs);
 
-	ti_gpio_attach_ports(sc);
+	ti_gpio_attach_ports(sc, phandle);
 
 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM,
 	    FDT_INTR_MPSAFE, ti_gpio_intr, sc, device_xname(self));
@@ -654,3 +690,41 @@
 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
 	fdtbus_register_interrupt_controller(self, phandle,
&ti_gpio_intrfuncs);
 }
+
+static int
+parse_gpio_ranges(struct ti_gpio_softc * const sc, int phandle)
+{
+	const u_int *ranges;
+	int rangeslen;
+	int pc_handle;
+	u_int gpio_offset, pinctrl_offset, npins;
+	int i;
+	
+	ranges = fdtbus_get_prop(phandle, "gpio-ranges", &rangeslen);
+	if (ranges == NULL)
+		return -1;
+
+	KASSERT((rangeslen & 0x0f) == 0);
+
+	pc_handle = -1;
+	for (rangeslen = rangeslen >> 4; rangeslen > 0; rangeslen--) {
+		pc_handle =
fdtbus_get_phandle_from_native(be32toh(ranges[0]));
+		gpio_offset = be32toh(ranges[1]);
+		pinctrl_offset = be32toh(ranges[2]);
+		npins = be32toh(ranges[3]);
+
+		if (gpio_offset + npins > __arraycount(sc->sc_pins)) {
+			aprint_error_dev(sc->sc_dev, ": gpio-ranges
%u+%u is too big\n", gpio_offset, npins);
+			return -1;
+		}
+
+		for (i = 0; i < npins; i++) {
+			sc->sc_pins[gpio_offset+i].pin_num =
pinctrl_offset + i;
+			sc->sc_pins[gpio_offset+i].pin_caps |=
GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN;
+		}
+
+		ranges += 4;		
+	}
+
+	return pc_handle;
+}
Index: sys/dev/fdt/fdt_pinctrl.c
===================================================================
RCS file: /home/lloyd/NetBSD/cvs/mirror/src/sys/dev/fdt/fdt_pinctrl.c,v
retrieving revision 1.10
diff -u -r1.10 fdt_pinctrl.c
--- sys/dev/fdt/fdt_pinctrl.c	1 Oct 2019 23:32:52 -0000	1.10
+++ sys/dev/fdt/fdt_pinctrl.c	28 Oct 2024 04:47:42 -0000
@@ -80,6 +80,20 @@
 	return NULL;
 }
 
+device_t
+fdtbus_pinctrl_lookup_dev(int phandle)
+{
+	struct fdtbus_pinctrl_controller *pc;
+
+	LIST_FOREACH(pc, &fdtbus_pinctrl_controllers, pc_next) {
+		if (OF_parent(pc->pc_phandle) == phandle)
+			return pc->pc_dev;
+	}
+
+	return NULL;
+}
+
+
 int
 fdtbus_pinctrl_set_config_index(int phandle, u_int index)
 {
@@ -270,7 +284,9 @@
 
 	return -1;
 }
-int fdtbus_pinctrl_parse_input_output(int phandle, int *output_value)
+
+int
+fdtbus_pinctrl_parse_input_output(int phandle, int *output_value)
 {
 	int direction = -1;
 	int pinval = -1;
Index: sys/dev/fdt/fdtvar.h
===================================================================
RCS file: /home/lloyd/NetBSD/cvs/mirror/src/sys/dev/fdt/fdtvar.h,v
retrieving revision 1.80
diff -u -r1.80 fdtvar.h
--- sys/dev/fdt/fdtvar.h	30 Jun 2024 17:55:28 -0000	1.80
+++ sys/dev/fdt/fdtvar.h	28 Oct 2024 03:29:30 -0000
@@ -491,6 +491,9 @@
 int		fdtbus_pinctrl_parse_drive(int);
 int		fdtbus_pinctrl_parse_drive_strength(int);
 int		fdtbus_pinctrl_parse_input_output(int, int *);
+device_t	fdtbus_pinctrl_lookup_dev(int);
+void		pinctrl_single_set_pin(device_t, int, int, int);
+
 
 pwm_tag_t	fdtbus_pwm_acquire(int, const char *);
 pwm_tag_t	fdtbus_pwm_acquire_index(int, const char *, int);
Index: sys/dev/fdt/pinctrl_single.c
===================================================================
RCS file:
/home/lloyd/NetBSD/cvs/mirror/src/sys/dev/fdt/pinctrl_single.c,v
retrieving revision 1.6
diff -u -r1.6 pinctrl_single.c
--- sys/dev/fdt/pinctrl_single.c	7 Nov 2021 17:12:25 -
0000	1.6
+++ sys/dev/fdt/pinctrl_single.c	28 Oct 2024 21:45:13 -0000
@@ -203,3 +203,13 @@
 
 CFATTACH_DECL_NEW(pinctrl_single, sizeof(struct pinctrl_single_softc),
 	pinctrl_single_match, pinctrl_single_attach, NULL, NULL);
+
+void
+pinctrl_single_set_pin(device_t self, int pin, int val, int mux)
+{
+	struct pinctrl_single_softc * const sc = device_private(self);
+	u_int offset;
+
+	offset = pin * (sc->sc_regwidth >> 3);
+	pinctrl_single_pins_write(sc, offset, val | mux);
+}



Home | Main Index | Thread Index | Old Index