Author: adrian
Date: Sun Jul 31 06:51:34 2016
New Revision: 303577
URL: https://svnweb.freebsd.org/changeset/base/303577

Log:
  [ar71xx_gpio] handle AR934x and QCA953x GPIO OE polarity.
  
  For reasons I won't comment on, the AR934x and QCA953x GPIO_OE register
  value is inverted - bit set == input, bit clear == output.
  
  So, fix this in the output setting, in reading the initial state from
  the boot loader, and also setting any gpiofunc pins that are necessary.

Modified:
  head/sys/mips/atheros/ar71xx_gpio.c

Modified: head/sys/mips/atheros/ar71xx_gpio.c
==============================================================================
--- head/sys/mips/atheros/ar71xx_gpio.c Sun Jul 31 06:34:49 2016        
(r303576)
+++ head/sys/mips/atheros/ar71xx_gpio.c Sun Jul 31 06:51:34 2016        
(r303577)
@@ -138,13 +138,56 @@ ar71xx_gpio_function_disable(struct ar71
                GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask);
 }
 
+/*
+ * On most platforms, GPIO_OE is a bitmap where the bit set
+ * means "enable output."
+ *
+ * On AR934x and QCA953x, it's the opposite - the bit set means
+ * "input enable".
+ */
+static int
+ar71xx_gpio_oe_is_high(void)
+{
+       switch (ar71xx_soc) {
+       case AR71XX_SOC_AR9344:
+       case AR71XX_SOC_QCA9533:
+       case AR71XX_SOC_QCA9533_V2:
+               return 0;
+       default:
+               return 1;
+       }
+}
+
 static void
-ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin,
-    unsigned int flags)
+ar71xx_gpio_oe_set_output(struct ar71xx_gpio_softc *sc, int b)
+{
+       uint32_t mask;
+
+       mask = 1 << b;
+
+       if (ar71xx_gpio_oe_is_high())
+               GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask);
+       else
+               GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask);
+}
+
+static void
+ar71xx_gpio_oe_set_input(struct ar71xx_gpio_softc *sc, int b)
 {
        uint32_t mask;
 
-       mask = 1 << pin->gp_pin;
+       mask = 1 << b;
+
+       if (ar71xx_gpio_oe_is_high())
+               GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask);
+       else
+               GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask);
+}
+
+static void
+ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin,
+    unsigned int flags)
+{
 
        /*
         * Manage input/output
@@ -153,11 +196,10 @@ ar71xx_gpio_pin_configure(struct ar71xx_
                pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT);
                if (flags & GPIO_PIN_OUTPUT) {
                        pin->gp_flags |= GPIO_PIN_OUTPUT;
-                       GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask);
-               }
-               else {
+                       ar71xx_gpio_oe_set_output(sc, pin->gp_pin);
+               } else {
                        pin->gp_flags |= GPIO_PIN_INPUT;
-                       GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask);
+                       ar71xx_gpio_oe_set_input(sc, pin->gp_pin);
                }
        }
 }
@@ -455,6 +497,14 @@ ar71xx_gpio_attach(device_t dev)
        }
        /* Iniatilize the GPIO pins, keep the loader settings. */
        oe = GPIO_READ(sc, AR71XX_GPIO_OE);
+       /*
+        * For AR934x and QCA953x, the meaning of oe is inverted;
+        * so flip it the right way around so we can parse the GPIO
+        * state.
+        */
+       if (!ar71xx_gpio_oe_is_high())
+               oe = ~oe;
+
        sc->gpio_pins = malloc(sizeof(*sc->gpio_pins) * sc->gpio_npins,
            M_DEVBUF, M_WAITOK | M_ZERO);
        for (i = 0, j = 0; j <= maxpin; j++) {
@@ -515,16 +565,14 @@ ar71xx_gpio_attach(device_t dev)
                    gpiofunc,
                    gpiomode);
 
-               /* Set output (bit == 0) */
-               oe = GPIO_READ(sc, AR71XX_GPIO_OE);
-               oe &= ~ (1 << i);
-               GPIO_WRITE(sc, AR71XX_GPIO_OE, oe);
-
                /* Set pin value = 0, so it stays low by default */
                oe = GPIO_READ(sc, AR71XX_GPIO_OUT);
                oe &= ~ (1 << i);
                GPIO_WRITE(sc, AR71XX_GPIO_OUT, oe);
 
+               /* Set output */
+               ar71xx_gpio_oe_set_output(sc, i);
+
                /* Finally: Set the output config */
                ar71xx_gpio_ouput_configure(i, gpiofunc);
        }
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to