ARM: tegra: don't enable GPIOs until direction is set
authorStephen Warren <swarren@nvidia.com>
Wed, 23 Sep 2015 18:13:00 +0000 (12:13 -0600)
committerTom Warren <twarren@nvidia.com>
Fri, 2 Oct 2015 18:05:01 +0000 (11:05 -0700)
Tegra's GPIO driver currently enables pins as GPIO as soon as they're
requested. This is not safe, since the desired direction and output value
are not yet known. This could cause a glitch on the output pins between
gpio_request() and gpio_direction_*(), depending on what values happen to
be in the GPIO controller's in/out and out-value registers vs. the final
desired configuration.

To solve this, defer enabling pins as GPIOs until some gpio_direction_*()
is invoked, and the desired configuration is explicitly programmed.

In theory this change could cause regressions, if code exists that claims
a GPIO, never explicitly sets a direction, and then gets/sets the GPIO
value based on that assumption. However, I've read through all the Tegra-
related board files and device drivers that touch GPIOs and I do not see
such buggy code anywhere.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Tom Warren <twarren@nvidia.com>
drivers/gpio/tegra_gpio.c

index c0ae7719e2c9b97c2952ea50ca01383543570bab..2dfd02d62053cb2cf0d14c96141a2ff12adcde88 100644 (file)
@@ -136,17 +136,6 @@ static void set_level(unsigned gpio, int high)
  * Generic_GPIO primitives.
  */
 
-static int tegra_gpio_request(struct udevice *dev, unsigned offset,
-                             const char *label)
-{
-       struct tegra_port_info *state = dev_get_priv(dev);
-
-       /* Configure as a GPIO */
-       set_config(state->base_gpio + offset, 1);
-
-       return 0;
-}
-
 /* set GPIO pin 'gpio' as an input */
 static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset)
 {
@@ -155,6 +144,9 @@ static int tegra_gpio_direction_input(struct udevice *dev, unsigned offset)
        /* Configure GPIO direction as input. */
        set_direction(state->base_gpio + offset, 0);
 
+       /* Enable the pin as a GPIO */
+       set_config(state->base_gpio + offset, 1);
+
        return 0;
 }
 
@@ -171,6 +163,9 @@ static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset,
        /* Configure GPIO direction as output. */
        set_direction(gpio, 1);
 
+       /* Enable the pin as a GPIO */
+       set_config(state->base_gpio + offset, 1);
+
        return 0;
 }
 
@@ -256,7 +251,6 @@ static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
 }
 
 static const struct dm_gpio_ops gpio_tegra_ops = {
-       .request                = tegra_gpio_request,
        .direction_input        = tegra_gpio_direction_input,
        .direction_output       = tegra_gpio_direction_output,
        .get_value              = tegra_gpio_get_value,