From e780d0fc82da8f4ddfb8d62e7690e13a79192cbd Mon Sep 17 00:00:00 2001 From: Ian Lepore Date: Fri, 4 May 2018 16:23:54 +0000 Subject: [PATCH] Make reading imx6 gpio pins work correctly whether the pin is in open-drain mode or not. An earlier attempt to make this work was done in r320456, by always reading the pad status register (PSR) instead of the data register. But it turns out the values in PSR only reflect the electrical level of an output pin if the pad is configured with the SION (Set Input On) bit in the pinmux config, and most output gpio pads are not configured that way. So now a gpio read is done by returning the value from the data register, which works right whether the pin is configured for input or output, unless the pin has been set for OPENDRAIN mode, in which case the PSR is read instead. For this to work, the pin must also be configured with SION turned on in the fdt pinmux data, which is a reasonable thing to require for the unusual case of reading an open-drain output pin. --- sys/arm/freescale/imx/imx_gpio.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/sys/arm/freescale/imx/imx_gpio.c b/sys/arm/freescale/imx/imx_gpio.c index f64deba15817..503bd0e3800e 100644 --- a/sys/arm/freescale/imx/imx_gpio.c +++ b/sys/arm/freescale/imx/imx_gpio.c @@ -644,7 +644,20 @@ imx51_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) if (pin >= sc->gpio_npins) return (EINVAL); - *val = (READ4(sc, IMX_GPIO_PSR_REG) >> pin) & 1; + /* + * Normally a pin set for output can be read by reading the DR reg which + * indicates what value is being driven to that pin. The exception is + * pins configured for open-drain mode, in which case we have to read + * the pad status register in case the pin is being driven externally. + * Doing so requires that the SION bit be configured in pinmux, which + * isn't the case for most normal gpio pins, so only try to read via PSR + * if the OPENDRAIN flag is set, and it's the user's job to correctly + * configure SION along with open-drain output mode for those pins. + */ + if (sc->gpio_pins[pin].gp_flags & GPIO_PIN_OPENDRAIN) + *val = (READ4(sc, IMX_GPIO_PSR_REG) >> pin) & 1; + else + *val = (READ4(sc, IMX_GPIO_DR_REG) >> pin) & 1; return (0); }