Date: Thu, 3 Apr 2014 17:55:08 +0000 (UTC) From: Luiz Otavio O Souza <loos@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264083 - head/sys/arm/ti Message-ID: <201404031755.s33Ht8LV005305@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: loos Date: Thu Apr 3 17:55:08 2014 New Revision: 264083 URL: http://svnweb.freebsd.org/changeset/base/264083 Log: Move the GPIO bank initialization to a new function to make easier to detect errors. Reset the GPIO module during the initialization. This is guaranteed to be the same as a hardware reset. Tested on AM335x (BBB) and checked against the omap3 and omap4 TRM. Do a better job freeing resources when there are errors and on ti_gpio_detach(). Modified: head/sys/arm/ti/ti_gpio.c Modified: head/sys/arm/ti/ti_gpio.c ============================================================================== --- head/sys/arm/ti/ti_gpio.c Thu Apr 3 17:31:38 2014 (r264082) +++ head/sys/arm/ti/ti_gpio.c Thu Apr 3 17:55:08 2014 (r264083) @@ -69,6 +69,9 @@ __FBSDID("$FreeBSD$"); /* Register definitions */ #define TI_GPIO_REVISION 0x0000 #define TI_GPIO_SYSCONFIG 0x0010 +#define TI_GPIO_SYSCONFIG_SOFTRESET (1 << 1) +#define TI_GPIO_SYSCONFIG_AUTOIDLE (1 << 0) +#define TI_GPIO_SYSSTATUS_RESETDONE (1 << 0) #if defined(SOC_OMAP3) #define TI_GPIO_SYSSTATUS 0x0014 #define TI_GPIO_IRQSTATUS1 0x0018 @@ -637,6 +640,107 @@ ti_gpio_probe(device_t dev) return (0); } +static int +ti_gpio_attach_intr(device_t dev) +{ + int i; + struct ti_gpio_softc *sc; + + sc = device_get_softc(dev); + for (i = 0; i < MAX_GPIO_BANKS; i++) { + if (sc->sc_irq_res[i] == NULL) + break; + + /* + * Register our interrupt handler for each of the IRQ resources. + */ + if (bus_setup_intr(dev, sc->sc_irq_res[i], + INTR_TYPE_MISC | INTR_MPSAFE, NULL, ti_gpio_intr, sc, + &sc->sc_irq_hdl[i]) != 0) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (-1); + } + } + + return (0); +} + +static int +ti_gpio_detach_intr(device_t dev) +{ + int i; + struct ti_gpio_softc *sc; + + /* Teardown our interrupt handlers. */ + sc = device_get_softc(dev); + for (i = 0; i < MAX_GPIO_BANKS; i++) { + if (sc->sc_irq_res[i] == NULL) + break; + + if (sc->sc_irq_hdl[i]) { + bus_teardown_intr(dev, sc->sc_irq_res[i], + sc->sc_irq_hdl[i]); + } + } + + return (0); +} + +static int +ti_gpio_bank_init(device_t dev, int bank) +{ + int pin, timeout; + struct ti_gpio_softc *sc; + uint32_t flags, reg_oe; + + sc = device_get_softc(dev); + + /* Enable the interface and functional clocks for the module. */ + ti_prcm_clk_enable(GPIO0_CLK + FIRST_GPIO_BANK + bank); + + /* Reset the GPIO module. */ + timeout = 0; + ti_gpio_write_4(sc, bank, TI_GPIO_SYSCONFIG, TI_GPIO_SYSCONFIG_SOFTRESET); + while ((ti_gpio_read_4(sc, bank, TI_GPIO_SYSSTATUS) & + TI_GPIO_SYSSTATUS_RESETDONE) == 0) { + if (timeout++ > 100) + return (EBUSY); + DELAY(100); + } + + /* + * Read the revision number of the module. TI don't publish the + * actual revision numbers, so instead the values have been + * determined by experimentation. + */ + sc->sc_revision[bank] = ti_gpio_read_4(sc, bank, TI_GPIO_REVISION); + + /* Check the revision. */ + if (sc->sc_revision[bank] != TI_GPIO_REV) { + device_printf(dev, "Warning: could not determine the revision " + "of %u GPIO module (revision:0x%08x)\n", + bank, sc->sc_revision[bank]); + return (EINVAL); + } + + /* Disable interrupts for all pins. */ + ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE1, 0xffffffff); + ti_gpio_write_4(sc, bank, TI_GPIO_CLEARIRQENABLE2, 0xffffffff); + + /* Init OE register based on pads configuration. */ + reg_oe = 0xffffffff; + for (pin = 0; pin < PINS_PER_BANK; pin++) { + ti_scm_padconf_get_gpioflags(PINS_PER_BANK * bank + pin, + &flags); + if (flags & GPIO_PIN_OUTPUT) + reg_oe &= ~(1UL << pin); + } + ti_gpio_write_4(sc, bank, TI_GPIO_OE, reg_oe); + + return (0); +} + /** * ti_gpio_attach - attach function for the driver * @dev: gpio device handle @@ -653,13 +757,11 @@ ti_gpio_probe(device_t dev) static int ti_gpio_attach(device_t dev) { - struct ti_gpio_softc *sc = device_get_softc(dev); + struct ti_gpio_softc *sc; unsigned int i; - int err = 0; - int pin; - uint32_t flags; - uint32_t reg_oe; + int err; + sc = device_get_softc(dev); sc->sc_dev = dev; TI_GPIO_LOCK_INIT(sc); @@ -668,30 +770,24 @@ ti_gpio_attach(device_t dev) * memory areas on the chip. The memory range should have been set for * the driver when it was added as a child. */ - err = bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); - if (err) { + if (bus_alloc_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res) != 0) { device_printf(dev, "Error: could not allocate mem resources\n"); return (ENXIO); } /* Request the IRQ resources */ - err = bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); - if (err) { + if (bus_alloc_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res) != 0) { + bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); device_printf(dev, "Error: could not allocate irq resources\n"); return (ENXIO); } /* Setup the IRQ resources */ - for (i = 0; i < MAX_GPIO_BANKS; i++) { - if (sc->sc_irq_res[i] == NULL) - break; - - /* Register an interrupt handler for each of the IRQ resources */ - if ((bus_setup_intr(dev, sc->sc_irq_res[i], INTR_TYPE_MISC | INTR_MPSAFE, - NULL, ti_gpio_intr, sc, &(sc->sc_irq_hdl[i])))) { - device_printf(dev, "WARNING: unable to register interrupt handler\n"); - return (ENXIO); - } + if (ti_gpio_attach_intr(dev) != 0) { + ti_gpio_detach_intr(dev); + bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); + bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); + return (ENXIO); } /* We need to go through each block and ensure the clocks are running and @@ -701,38 +797,16 @@ ti_gpio_attach(device_t dev) */ for (i = 0; i < MAX_GPIO_BANKS; i++) { if (sc->sc_mem_res[i] != NULL) { - - /* Enable the interface and functional clocks for the module */ - ti_prcm_clk_enable(GPIO0_CLK + FIRST_GPIO_BANK + i); - - /* Read the revision number of the module. TI don't publish the - * actual revision numbers, so instead the values have been - * determined by experimentation. - */ - sc->sc_revision[i] = ti_gpio_read_4(sc, i, TI_GPIO_REVISION); - - /* Check the revision */ - if (sc->sc_revision[i] != TI_GPIO_REV) { - device_printf(dev, "Warning: could not determine the revision" - "of %u GPIO module (revision:0x%08x)\n", - i, sc->sc_revision[i]); - continue; - } - - /* Disable interrupts for all pins */ - ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE1, 0xffffffff); - ti_gpio_write_4(sc, i, TI_GPIO_CLEARIRQENABLE2, 0xffffffff); - - /* Init OE register based on pads configuration */ - reg_oe = 0xffffffff; - for (pin = 0; pin < 32; pin++) { - ti_scm_padconf_get_gpioflags( - PINS_PER_BANK*i + pin, &flags); - if (flags & GPIO_PIN_OUTPUT) - reg_oe &= ~(1U << pin); + /* Reset and initialize the GPIO module. */ + err = ti_gpio_bank_init(dev, i); + if (err != 0) { + ti_gpio_detach_intr(dev); + bus_release_resources(dev, ti_gpio_irq_spec, + sc->sc_irq_res); + bus_release_resources(dev, ti_gpio_mem_spec, + sc->sc_mem_res); + return (err); } - - ti_gpio_write_4(sc, i, TI_GPIO_OE, reg_oe); } } @@ -774,13 +848,10 @@ ti_gpio_detach(device_t dev) bus_generic_detach(dev); - /* Release the memory and IRQ resources */ - for (i = 0; i < MAX_GPIO_BANKS; i++) { - if (sc->sc_mem_res[i] != NULL) - bus_release_resource(dev, SYS_RES_MEMORY, i, sc->sc_mem_res[i]); - if (sc->sc_irq_res[i] != NULL) - bus_release_resource(dev, SYS_RES_IRQ, i, sc->sc_irq_res[i]); - } + /* Release the memory and IRQ resources. */ + ti_gpio_detach_intr(dev); + bus_release_resources(dev, ti_gpio_irq_spec, sc->sc_irq_res); + bus_release_resources(dev, ti_gpio_mem_spec, sc->sc_mem_res); TI_GPIO_LOCK_DESTROY(sc);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404031755.s33Ht8LV005305>