From f8f34e91da7b66528e29ae703d42214a70e69f86 Mon Sep 17 00:00:00 2001 From: Emmanuel Vadot Date: Fri, 8 Jul 2016 23:08:59 +0000 Subject: [PATCH] Check that the pin function exists before setting it. This is needed for Allwinner A13 which has gpio pins with only "out" function. --- sys/arm/allwinner/a10_gpio.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/sys/arm/allwinner/a10_gpio.c b/sys/arm/allwinner/a10_gpio.c index d088152df79..ebad4027fa7 100644 --- a/sys/arm/allwinner/a10_gpio.c +++ b/sys/arm/allwinner/a10_gpio.c @@ -198,11 +198,15 @@ a10_gpio_get_function(struct a10_gpio_softc *sc, uint32_t pin) return (0); } -static void +static int a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f) { uint32_t bank, data, offset; + /* Check if the function exists in the padconf data */ + if (sc->padconf->pins[pin].functions[f] == NULL) + return (EINVAL); + /* Must be called with lock held. */ A10_GPIO_LOCK_ASSERT(sc); @@ -214,6 +218,8 @@ a10_gpio_set_function(struct a10_gpio_softc *sc, uint32_t pin, uint32_t f) data &= ~(7 << offset); data |= (f << offset); A10_GPIO_WRITE(sc, A10_GPIO_GP_CFG(bank, pin >> 3), data); + + return (0); } static uint32_t @@ -275,9 +281,10 @@ a10_gpio_set_drv(struct a10_gpio_softc *sc, uint32_t pin, uint32_t drive) A10_GPIO_WRITE(sc, A10_GPIO_GP_DRV(bank, pin >> 4), val); } -static void +static int a10_gpio_pin_configure(struct a10_gpio_softc *sc, uint32_t pin, uint32_t flags) { + int err = 0; /* Must be called with lock held. */ A10_GPIO_LOCK_ASSERT(sc); @@ -285,11 +292,14 @@ a10_gpio_pin_configure(struct a10_gpio_softc *sc, uint32_t pin, uint32_t flags) /* Manage input/output. */ if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) { if (flags & GPIO_PIN_OUTPUT) - a10_gpio_set_function(sc, pin, A10_GPIO_OUTPUT); + err = a10_gpio_set_function(sc, pin, A10_GPIO_OUTPUT); else - a10_gpio_set_function(sc, pin, A10_GPIO_INPUT); + err = a10_gpio_set_function(sc, pin, A10_GPIO_INPUT); } + if (err) + return (err); + /* Manage Pull-up/pull-down. */ if (flags & (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)) { if (flags & GPIO_PIN_PULLUP) @@ -298,6 +308,8 @@ a10_gpio_pin_configure(struct a10_gpio_softc *sc, uint32_t pin, uint32_t flags) a10_gpio_set_pud(sc, pin, A10_GPIO_PULLDOWN); } else a10_gpio_set_pud(sc, pin, A10_GPIO_NONE); + + return (0); } static device_t @@ -372,16 +384,17 @@ static int a10_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { struct a10_gpio_softc *sc; + int err; sc = device_get_softc(dev); if (pin > sc->padconf->npins) return (EINVAL); A10_GPIO_LOCK(sc); - a10_gpio_pin_configure(sc, pin, flags); + err = a10_gpio_pin_configure(sc, pin, flags); A10_GPIO_UNLOCK(sc); - return (0); + return (err); } static int