[PATCH] gpio_direction_output() needs an initial value
authorDavid Brownell <david-b@pacbell.net>
Fri, 16 Mar 2007 21:38:14 +0000 (13:38 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Sat, 17 Mar 2007 02:25:04 +0000 (19:25 -0700)
It's been pointed out that output GPIOs should have an initial value, to
avoid signal glitching ...  among other things, it can be some time before
a driver is ready.  This patch corrects that oversight, fixing

 - documentation
 - platforms supporting the GPIO interface
 - users of that call (just one for now, others are pending)

There's only one user of this call for now since most platforms are still
using non-generic GPIO setup code, which in most cases already couples the
initial value with its "set output mode" request.

Note that most platforms are clear about the hardware letting the output
value be set before the pin direction is changed, but the s3c241x docs are
vague on that topic ...  so those chips might not avoid the glitches.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-by: Andrew Victor <andrew@sanpeople.com>
Acked-by: Milan Svoboda <msvoboda@ra.rockwell.com>
Acked-by: Haavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Documentation/gpio.txt
arch/arm/mach-at91/gpio.c
arch/arm/mach-sa1100/generic.c
arch/avr32/mach-at32ap/pio.c
drivers/spi/atmel_spi.c
include/asm-arm/arch-at91/gpio.h
include/asm-arm/arch-omap/gpio.h
include/asm-arm/arch-pxa/gpio.h
include/asm-arm/arch-s3c2410/gpio.h
include/asm-arm/arch-sa1100/gpio.h
include/asm-avr32/arch-at32ap/gpio.h

index 576ce463cf442d7fb806fea31eb373c883647d86..989f1130f4f33e6960459b971b41862b10713a2d 100644 (file)
@@ -105,12 +105,15 @@ setting up a platform_device using the GPIO, is mark its direction:
 
        /* set as input or output, returning 0 or negative errno */
        int gpio_direction_input(unsigned gpio);
-       int gpio_direction_output(unsigned gpio);
+       int gpio_direction_output(unsigned gpio, int value);
 
 The return value is zero for success, else a negative errno.  It should
 be checked, since the get/set calls don't have error returns and since
 misconfiguration is possible.  (These calls could sleep.)
 
+For output GPIOs, the value provided becomes the initial output value.
+This helps avoid signal glitching during system startup.
+
 Setting the direction can fail if the GPIO number is invalid, or when
 that particular GPIO can't be used in that mode.  It's generally a bad
 idea to rely on boot firmware to have set the direction correctly, since
index 44211a0af19a805fd81a0d1a5783f07ed4db958f..ba4a1bb3ee4027c8dd51392abe670dd0e2ce3992 100644 (file)
@@ -215,13 +215,14 @@ int gpio_direction_input(unsigned pin)
 }
 EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned pin)
+int gpio_direction_output(unsigned pin, int value)
 {
        void __iomem    *pio = pin_to_controller(pin);
        unsigned        mask = pin_to_mask(pin);
 
        if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
                return -EINVAL;
+       __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
        __raw_writel(mask, pio + PIO_OER);
        return 0;
 }
index 192a5a26cf2b4c16ff5f9a5cd044c578468432dd..edc349e5fcf71eed240875491c657f84472f2793 100644 (file)
@@ -153,7 +153,7 @@ int gpio_direction_input(unsigned gpio)
 
 EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned gpio)
+int gpio_direction_output(unsigned gpio, int value)
 {
        unsigned long flags;
 
@@ -161,6 +161,7 @@ int gpio_direction_output(unsigned gpio)
                return -EINVAL;
 
        local_irq_save(flags);
+       gpio_set_value(gpio, value);
        GPDR |= GPIO_GPIO(gpio);
        local_irq_restore(flags);
        return 0;
index 9ba5654cde110dda279fe83498ab5a1c25d33144..1eb99b814f5bcaf021f06ef46ea26c3cc96fa67f 100644 (file)
@@ -214,7 +214,7 @@ int gpio_direction_input(unsigned int gpio)
 }
 EXPORT_SYMBOL(gpio_direction_input);
 
-int gpio_direction_output(unsigned int gpio)
+int gpio_direction_output(unsigned int gpio, int value)
 {
        struct pio_device *pio;
        unsigned int pin;
@@ -223,6 +223,8 @@ int gpio_direction_output(unsigned int gpio)
        if (!pio)
                return -ENODEV;
 
+       gpio_set_value(gpio, value);
+
        pin = gpio & 0x1f;
        pio_writel(pio, OER, 1 << pin);
 
index 6fa260d1a9be06607be15658bcbc3b7a452b18e8..66e7bc985797a0d8acce875c3281e744f7db9849 100644 (file)
@@ -425,7 +425,7 @@ static int atmel_spi_setup(struct spi_device *spi)
                if (ret)
                        return ret;
                spi->controller_state = (void *)npcs_pin;
-               gpio_direction_output(npcs_pin);
+               gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
        }
 
        dev_dbg(&spi->dev,
index 98ad2114f43a2bbae4c68c19225dd25270d7a533..0a241e2fb672212b52293872dcb445e53c081be3 100644 (file)
@@ -223,7 +223,7 @@ static inline void gpio_free(unsigned gpio)
 }
 
 extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
 
 static inline int gpio_get_value(unsigned gpio)
 {
index 3762a6ae6a7f345d1343d1defa43737546b9e445..590917efc94acdecca3be6fad273f31b24a9ef41 100644 (file)
@@ -113,8 +113,9 @@ static inline int gpio_direction_input(unsigned gpio)
        return __gpio_set_direction(gpio, 1);
 }
 
-static inline int gpio_direction_output(unsigned gpio)
+static inline int gpio_direction_output(unsigned gpio, int value)
 {
+       omap_set_gpio_dataout(gpio, value);
        return __gpio_set_direction(gpio, 0);
 }
 
index 3d348a3511575fb4083359a944740fe12746098c..aeba24347f8e43355619711b3a4f10e4ec0a8c4d 100644 (file)
@@ -43,9 +43,9 @@ static inline int gpio_direction_input(unsigned gpio)
        return pxa_gpio_mode(gpio | GPIO_IN);
 }
 
-static inline int gpio_direction_output(unsigned gpio)
+static inline int gpio_direction_output(unsigned gpio, int value)
 {
-       return pxa_gpio_mode(gpio | GPIO_OUT);
+       return pxa_gpio_mode(gpio | GPIO_OUT | (value ? 0 : GPIO_DFLT_LOW));
 }
 
 static inline int __gpio_get_value(unsigned gpio)
index d47ae453f8cae3eb4728964bc5c08d4546e0687e..7583895fd336fa7e8aabff426645e71824e3c273 100644 (file)
@@ -44,9 +44,11 @@ static inline int gpio_direction_input(unsigned gpio)
        return 0;
 }
 
-static inline int gpio_direction_output(unsigned gpio)
+static inline int gpio_direction_output(unsigned gpio, int value)
 {
        s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
+       /* REVISIT can we write the value first, to avoid glitching? */
+       s3c2410_gpio_setpin(gpio, value);
        return 0;
 }
 
index da7575b0e5d0f2f00ca58b09cc4aeaa22635f93a..e7a9d26e22a8b0a4baa1d0de08b65d672e418a79 100644 (file)
@@ -38,7 +38,7 @@ static inline void gpio_free(unsigned gpio)
 }
 
 extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio);
+extern int gpio_direction_output(unsigned gpio, int value);
 
 
 static inline int gpio_get_value(unsigned gpio)
index fcb756bdaa8e01922901c374f17a3a744ba3204f..80a21aa9ae77016158e12bad83064ca4a9d2a39f 100644 (file)
@@ -10,7 +10,7 @@ int __must_check gpio_request(unsigned int gpio, const char *label);
 void gpio_free(unsigned int gpio);
 
 int gpio_direction_input(unsigned int gpio);
-int gpio_direction_output(unsigned int gpio);
+int gpio_direction_output(unsigned int gpio, int value);
 int gpio_get_value(unsigned int gpio);
 void gpio_set_value(unsigned int gpio, int value);