summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorloos <loos@FreeBSD.org>2015-01-07 19:15:11 +0000
committerloos <loos@FreeBSD.org>2015-01-07 19:15:11 +0000
commit173745533e391b9bdce26a35aa6462a80ce28c3b (patch)
tree807dbde92b154389d8d33379ae45837cad54cde7 /sys/arm
parent17b7ef10fda79e94515b2a9bc292f3efe4621111 (diff)
downloadFreeBSD-src-173745533e391b9bdce26a35aa6462a80ce28c3b.zip
FreeBSD-src-173745533e391b9bdce26a35aa6462a80ce28c3b.tar.gz
Fix the handling of pull-up and pull-down for RK3188.
For this to work the driver needs to know the bank it has attached to since the registers for the first 12 pins are at a different location. Move the lock initialization to simplify the code.
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/rockchip/rk30xx_gpio.c70
1 files changed, 46 insertions, 24 deletions
diff --git a/sys/arm/rockchip/rk30xx_gpio.c b/sys/arm/rockchip/rk30xx_gpio.c
index 21f5e09..6eb7db7 100644
--- a/sys/arm/rockchip/rk30xx_gpio.c
+++ b/sys/arm/rockchip/rk30xx_gpio.c
@@ -79,10 +79,14 @@ struct rk30_gpio_softc {
bus_space_tag_t sc_bst;
bus_space_handle_t sc_bsh;
void * sc_intrhand;
+ int sc_bank;
int sc_gpio_npins;
struct gpio_pin sc_gpio_pins[RK30_GPIO_PINS];
};
+/* We use our base address to find out our bank number. */
+static unsigned long rk30_gpio_base_addr[4] =
+ { 0x2000a000, 0x2003c000, 0x2003e000, 0x20080000 };
static struct rk30_gpio_softc *rk30_gpio_sc = NULL;
typedef int (*gpios_phandler_t)(phandle_t, pcell_t *, int);
@@ -153,17 +157,28 @@ rk30_gpio_set_function(struct rk30_gpio_softc *sc, uint32_t pin, uint32_t func)
static void
rk30_gpio_set_pud(struct rk30_gpio_softc *sc, uint32_t pin, uint32_t state)
{
- uint32_t bank;
-
- bank = pin / 32;
+ uint32_t pud;
/* Must be called with lock held. */
RK30_GPIO_LOCK_ASSERT(sc);
-
- if (bank == 0 && pin < 12)
- rk30_pmu_gpio_pud(pin, state);
+ switch (state) {
+ case GPIO_PIN_PULLUP:
+ pud = RK30_GPIO_PULLUP;
+ break;
+ case GPIO_PIN_PULLDOWN:
+ pud = RK30_GPIO_PULLDOWN;
+ break;
+ default:
+ pud = RK30_GPIO_NONE;
+ }
+ /*
+ * The pull up/down registers for GPIO0A and half of GPIO0B
+ * (the first 12 pins on bank 0) are at a different location.
+ */
+ if (sc->sc_bank == 0 && pin < 12)
+ rk30_pmu_gpio_pud(pin, pud);
else
- rk30_grf_gpio_pud(bank, pin, state);
+ rk30_grf_gpio_pud(sc->sc_bank, pin, pud);
}
static void
@@ -183,22 +198,15 @@ rk30_gpio_pin_configure(struct rk30_gpio_softc *sc, struct gpio_pin *pin,
pin->gp_flags |= GPIO_PIN_INPUT;
rk30_gpio_set_function(sc, pin->gp_pin, pin->gp_flags);
}
-
/* Manage Pull-up/pull-down. */
- pin->gp_flags &= ~(GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN);
- if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) {
- if (flags & GPIO_PIN_PULLUP) {
+ pin->gp_flags &= ~(GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN);
+ if (flags & (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN)) {
+ if (flags & GPIO_PIN_PULLUP)
pin->gp_flags |= GPIO_PIN_PULLUP;
- rk30_gpio_set_pud(sc, pin->gp_pin,
- RK30_GPIO_PULLUP);
- } else {
+ else
pin->gp_flags |= GPIO_PIN_PULLDOWN;
- rk30_gpio_set_pud(sc, pin->gp_pin,
- RK30_GPIO_PULLDOWN);
- }
- } else
- rk30_gpio_set_pud(sc, pin->gp_pin, RK30_GPIO_NONE);
-
+ }
+ rk30_gpio_set_pud(sc, pin->gp_pin, pin->gp_flags);
RK30_GPIO_UNLOCK(sc);
}
@@ -386,14 +394,12 @@ rk30_gpio_attach(device_t dev)
struct rk30_gpio_softc *sc = device_get_softc(dev);
int i, rid;
phandle_t gpio;
+ unsigned long start;
if (rk30_gpio_sc)
return (ENXIO);
-
sc->sc_dev = dev;
- mtx_init(&sc->sc_mtx, "rk30 gpio", "gpio", MTX_DEF);
-
rid = 0;
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
@@ -401,9 +407,23 @@ rk30_gpio_attach(device_t dev)
device_printf(dev, "cannot allocate memory window\n");
return (ENXIO);
}
-
sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
+ /* Check the unit we are attaching by our base address. */
+ sc->sc_bank = -1;
+ start = rman_get_start(sc->sc_mem_res);
+ for (i = 0; i < nitems(rk30_gpio_base_addr); i++) {
+ if (rk30_gpio_base_addr[i] == start) {
+ sc->sc_bank = i;
+ break;
+ }
+ }
+ if (sc->sc_bank == -1) {
+ device_printf(dev,
+ "unsupported device unit (only GPIO0..3 are supported)\n");
+ bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
+ return (ENXIO);
+ }
rid = 0;
sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
@@ -421,6 +441,8 @@ rk30_gpio_attach(device_t dev)
/* Node is not a GPIO controller. */
goto fail;
+ mtx_init(&sc->sc_mtx, "rk30 gpio", "gpio", MTX_DEF);
+
/* Initialize the software controlled pins. */
for (i = 0; i < RK30_GPIO_PINS; i++) {
snprintf(sc->sc_gpio_pins[i].gp_name, GPIOMAXNAME,
OpenPOWER on IntegriCloud