svn commit: r264083 - head/sys/arm/ti

Luiz Otavio O Souza loos at FreeBSD.org
Thu Apr 3 17:55:08 UTC 2014


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);
 


More information about the svn-src-all mailing list