提交 28735a72 编写于 作者: D David Brownell 提交者: Linus Torvalds

[PATCH] gpio_direction_output() needs an initial value

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: NDavid Brownell <dbrownell@users.sourceforge.net>
Acked-by: NAndrew Victor <andrew@sanpeople.com>
Acked-by: NMilan Svoboda <msvoboda@ra.rockwell.com>
Acked-by: NHaavard Skinnemoen <hskinnemoen@atmel.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
上级 a836f585
...@@ -105,12 +105,15 @@ setting up a platform_device using the GPIO, is mark its direction: ...@@ -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 */ /* set as input or output, returning 0 or negative errno */
int gpio_direction_input(unsigned gpio); 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 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 be checked, since the get/set calls don't have error returns and since
misconfiguration is possible. (These calls could sleep.) 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 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 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 idea to rely on boot firmware to have set the direction correctly, since
......
...@@ -215,13 +215,14 @@ int gpio_direction_input(unsigned pin) ...@@ -215,13 +215,14 @@ int gpio_direction_input(unsigned pin)
} }
EXPORT_SYMBOL(gpio_direction_input); 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); void __iomem *pio = pin_to_controller(pin);
unsigned mask = pin_to_mask(pin); unsigned mask = pin_to_mask(pin);
if (!pio || !(__raw_readl(pio + PIO_PSR) & mask)) if (!pio || !(__raw_readl(pio + PIO_PSR) & mask))
return -EINVAL; return -EINVAL;
__raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
__raw_writel(mask, pio + PIO_OER); __raw_writel(mask, pio + PIO_OER);
return 0; return 0;
} }
......
...@@ -153,7 +153,7 @@ int gpio_direction_input(unsigned gpio) ...@@ -153,7 +153,7 @@ int gpio_direction_input(unsigned gpio)
EXPORT_SYMBOL(gpio_direction_input); EXPORT_SYMBOL(gpio_direction_input);
int gpio_direction_output(unsigned gpio) int gpio_direction_output(unsigned gpio, int value)
{ {
unsigned long flags; unsigned long flags;
...@@ -161,6 +161,7 @@ int gpio_direction_output(unsigned gpio) ...@@ -161,6 +161,7 @@ int gpio_direction_output(unsigned gpio)
return -EINVAL; return -EINVAL;
local_irq_save(flags); local_irq_save(flags);
gpio_set_value(gpio, value);
GPDR |= GPIO_GPIO(gpio); GPDR |= GPIO_GPIO(gpio);
local_irq_restore(flags); local_irq_restore(flags);
return 0; return 0;
......
...@@ -214,7 +214,7 @@ int gpio_direction_input(unsigned int gpio) ...@@ -214,7 +214,7 @@ int gpio_direction_input(unsigned int gpio)
} }
EXPORT_SYMBOL(gpio_direction_input); 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; struct pio_device *pio;
unsigned int pin; unsigned int pin;
...@@ -223,6 +223,8 @@ int gpio_direction_output(unsigned int gpio) ...@@ -223,6 +223,8 @@ int gpio_direction_output(unsigned int gpio)
if (!pio) if (!pio)
return -ENODEV; return -ENODEV;
gpio_set_value(gpio, value);
pin = gpio & 0x1f; pin = gpio & 0x1f;
pio_writel(pio, OER, 1 << pin); pio_writel(pio, OER, 1 << pin);
......
...@@ -425,7 +425,7 @@ static int atmel_spi_setup(struct spi_device *spi) ...@@ -425,7 +425,7 @@ static int atmel_spi_setup(struct spi_device *spi)
if (ret) if (ret)
return ret; return ret;
spi->controller_state = (void *)npcs_pin; 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, dev_dbg(&spi->dev,
......
...@@ -223,7 +223,7 @@ static inline void gpio_free(unsigned gpio) ...@@ -223,7 +223,7 @@ static inline void gpio_free(unsigned gpio)
} }
extern int gpio_direction_input(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) static inline int gpio_get_value(unsigned gpio)
{ {
......
...@@ -113,8 +113,9 @@ static inline int gpio_direction_input(unsigned gpio) ...@@ -113,8 +113,9 @@ static inline int gpio_direction_input(unsigned gpio)
return __gpio_set_direction(gpio, 1); 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); return __gpio_set_direction(gpio, 0);
} }
......
...@@ -43,9 +43,9 @@ static inline int gpio_direction_input(unsigned gpio) ...@@ -43,9 +43,9 @@ static inline int gpio_direction_input(unsigned gpio)
return pxa_gpio_mode(gpio | GPIO_IN); 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) static inline int __gpio_get_value(unsigned gpio)
......
...@@ -44,9 +44,11 @@ static inline int gpio_direction_input(unsigned gpio) ...@@ -44,9 +44,11 @@ static inline int gpio_direction_input(unsigned gpio)
return 0; 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); s3c2410_gpio_cfgpin(gpio, S3C2410_GPIO_OUTPUT);
/* REVISIT can we write the value first, to avoid glitching? */
s3c2410_gpio_setpin(gpio, value);
return 0; return 0;
} }
......
...@@ -38,7 +38,7 @@ static inline void gpio_free(unsigned gpio) ...@@ -38,7 +38,7 @@ static inline void gpio_free(unsigned gpio)
} }
extern int gpio_direction_input(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) static inline int gpio_get_value(unsigned gpio)
......
...@@ -10,7 +10,7 @@ int __must_check gpio_request(unsigned int gpio, const char *label); ...@@ -10,7 +10,7 @@ int __must_check gpio_request(unsigned int gpio, const char *label);
void gpio_free(unsigned int gpio); void gpio_free(unsigned int gpio);
int gpio_direction_input(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); int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value); void gpio_set_value(unsigned int gpio, int value);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册