Author: ian
Date: Fri May  4 19:28:05 2018
New Revision: 333260
URL: https://svnweb.freebsd.org/changeset/base/333260

Log:
  Properly support the GPIO_PIN_PRESET_{LOW,HIGH} options when configuring
  a gpio pin.  If neither of the options is specified, pre-set the pin's
  output value to the pin's current input value, to achieve glitch-free
  transitions to output mode on pins that are pulled up or down at reset
  or via fdt pinctrl data.

Modified:
  head/sys/arm/freescale/imx/imx_gpio.c

Modified: head/sys/arm/freescale/imx/imx_gpio.c
==============================================================================
--- head/sys/arm/freescale/imx/imx_gpio.c       Fri May  4 18:59:01 2018        
(r333259)
+++ head/sys/arm/freescale/imx/imx_gpio.c       Fri May  4 19:28:05 2018        
(r333260)
@@ -506,21 +506,41 @@ static void
 imx51_gpio_pin_configure(struct imx51_gpio_softc *sc, struct gpio_pin *pin,
     unsigned int flags)
 {
-       u_int newflags;
+       u_int newflags, pad;
 
        mtx_lock_spin(&sc->sc_mtx);
 
        /*
-        * Manage input/output; other flags not supported yet.
+        * Manage input/output; other flags not supported yet (maybe not ever,
+        * since we have no connection to the pad config registers from here).
         *
+        * When setting a pin to output, honor the PRESET_[LOW,HIGH] flags if
+        * present.  Otherwise, for glitchless transistions on pins with pulls,
+        * read the current state of the pad and preset the DR register to drive
+        * the current value onto the pin before enabling the pin for output.
+        *
         * Note that changes to pin->gp_flags must be acccumulated in newflags
         * and stored with a single writeback to gp_flags at the end, to enable
-        * unlocked reads of that value elsewhere.
+        * unlocked reads of that value elsewhere. This is only about unlocked
+        * access to gp_flags from elsewhere; we still use locking in this
+        * function to protect r-m-w access to the hardware registers.
         */
        if (flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) {
                newflags = pin->gp_flags & ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT);
                if (flags & GPIO_PIN_OUTPUT) {
+                       if (flags & GPIO_PIN_PRESET_LOW) {
+                               pad = 0;
+                       } else if (flags & GPIO_PIN_PRESET_HIGH) {
+                               pad = 1;
+                       } else {
+                               if (flags & GPIO_PIN_OPENDRAIN)
+                                       pad = READ4(sc, IMX_GPIO_PSR_REG);
+                               else
+                                       pad = READ4(sc, IMX_GPIO_DR_REG);
+                               pad = (pad >> pin->gp_pin) & 1;
+                       }
                        newflags |= GPIO_PIN_OUTPUT;
+                       SET4(sc, IMX_GPIO_DR_REG, (pad << pin->gp_pin));
                        SET4(sc, IMX_GPIO_OE_REG, (1U << pin->gp_pin));
                } else {
                        newflags |= GPIO_PIN_INPUT;
@@ -692,7 +712,7 @@ imx51_gpio_pin_access_32(device_t dev, uint32_t first_
        sc = device_get_softc(dev);
 
        if (orig_pins != NULL)
-               *orig_pins = READ4(sc, IMX_GPIO_PSR_REG);
+               *orig_pins = READ4(sc, IMX_GPIO_DR_REG);
 
        if ((clear_pins | change_pins) != 0) {
                mtx_lock_spin(&sc->sc_mtx);
@@ -718,7 +738,7 @@ imx51_gpio_pin_config_32(device_t dev, uint32_t first_
                return (EINVAL);
 
        drclr = drset = oeclr = oeset = 0;
-       pads = READ4(sc, IMX_GPIO_PSR_REG);
+       pads = READ4(sc, IMX_GPIO_DR_REG);
 
        for (i = 0; i < num_pins; ++i) {
                bit = 1u << i;
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to