summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanu <manu@FreeBSD.org>2016-09-05 20:07:03 +0000
committermanu <manu@FreeBSD.org>2016-09-05 20:07:03 +0000
commit587595800a40be2a71341039df8aa65b5a3cb0c7 (patch)
treeb940c9765cd96f18553ff0b1c6bd852faa645330
parent3b33ca08743db03bde702396083b670015dff9c9 (diff)
downloadFreeBSD-src-587595800a40be2a71341039df8aa65b5a3cb0c7.zip
FreeBSD-src-587595800a40be2a71341039df8aa65b5a3cb0c7.tar.gz
MFC r302470
Check that the pin function exists before setting it. This is needed for Allwinner A13 which has gpio pins with only "out" function.
-rw-r--r--sys/arm/allwinner/a10_gpio.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/sys/arm/allwinner/a10_gpio.c b/sys/arm/allwinner/a10_gpio.c
index fe9a050..b2c8874 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
OpenPOWER on IntegriCloud