diff options
author | Baruch Siach <baruch@tkos.co.il> | 2010-07-06 07:03:22 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-07-28 03:22:51 -0400 |
commit | 14cb0deb66fcfca8fdbef75da8c84b5405a8c767 (patch) | |
tree | 56f48e64c92f694c75a126a4bac0dee64d8f6b60 /arch | |
parent | ef93f1443c014e0d6dd7a5b1e592a02aa266f001 (diff) |
arm/imx/gpio: add spinlock protection
The GPIO registers need protection from concurrent access for operations that
are not atomic.
Cc: stable@kernel.org
Cc: Juergen Beisert <j.beisert@pengutronix.de>
Cc: Daniel Mack <daniel@caiaq.de>
Reported-by: rpkamiak@rockwellcollins.com
Signed-off-by: Baruch Siach <baruch@tkos.co.il>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/plat-mxc/gpio.c | 8 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/gpio.h | 1 |
2 files changed, 9 insertions, 0 deletions
diff --git a/arch/arm/plat-mxc/gpio.c b/arch/arm/plat-mxc/gpio.c index 11dc06190b5d..57ec4a896a5d 100644 --- a/arch/arm/plat-mxc/gpio.c +++ b/arch/arm/plat-mxc/gpio.c | |||
@@ -214,13 +214,16 @@ static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset, | |||
214 | struct mxc_gpio_port *port = | 214 | struct mxc_gpio_port *port = |
215 | container_of(chip, struct mxc_gpio_port, chip); | 215 | container_of(chip, struct mxc_gpio_port, chip); |
216 | u32 l; | 216 | u32 l; |
217 | unsigned long flags; | ||
217 | 218 | ||
219 | spin_lock_irqsave(&port->lock, flags); | ||
218 | l = __raw_readl(port->base + GPIO_GDIR); | 220 | l = __raw_readl(port->base + GPIO_GDIR); |
219 | if (dir) | 221 | if (dir) |
220 | l |= 1 << offset; | 222 | l |= 1 << offset; |
221 | else | 223 | else |
222 | l &= ~(1 << offset); | 224 | l &= ~(1 << offset); |
223 | __raw_writel(l, port->base + GPIO_GDIR); | 225 | __raw_writel(l, port->base + GPIO_GDIR); |
226 | spin_unlock_irqrestore(&port->lock, flags); | ||
224 | } | 227 | } |
225 | 228 | ||
226 | static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | 229 | static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
@@ -229,9 +232,12 @@ static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
229 | container_of(chip, struct mxc_gpio_port, chip); | 232 | container_of(chip, struct mxc_gpio_port, chip); |
230 | void __iomem *reg = port->base + GPIO_DR; | 233 | void __iomem *reg = port->base + GPIO_DR; |
231 | u32 l; | 234 | u32 l; |
235 | unsigned long flags; | ||
232 | 236 | ||
237 | spin_lock_irqsave(&port->lock, flags); | ||
233 | l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset); | 238 | l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset); |
234 | __raw_writel(l, reg); | 239 | __raw_writel(l, reg); |
240 | spin_unlock_irqrestore(&port->lock, flags); | ||
235 | } | 241 | } |
236 | 242 | ||
237 | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) | 243 | static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset) |
@@ -285,6 +291,8 @@ int __init mxc_gpio_init(struct mxc_gpio_port *port, int cnt) | |||
285 | port[i].chip.base = i * 32; | 291 | port[i].chip.base = i * 32; |
286 | port[i].chip.ngpio = 32; | 292 | port[i].chip.ngpio = 32; |
287 | 293 | ||
294 | spin_lock_init(&port[i].lock); | ||
295 | |||
288 | /* its a serious configuration bug when it fails */ | 296 | /* its a serious configuration bug when it fails */ |
289 | BUG_ON( gpiochip_add(&port[i].chip) < 0 ); | 297 | BUG_ON( gpiochip_add(&port[i].chip) < 0 ); |
290 | 298 | ||
diff --git a/arch/arm/plat-mxc/include/mach/gpio.h b/arch/arm/plat-mxc/include/mach/gpio.h index 9541ecbfd22c..661fbc605759 100644 --- a/arch/arm/plat-mxc/include/mach/gpio.h +++ b/arch/arm/plat-mxc/include/mach/gpio.h | |||
@@ -37,6 +37,7 @@ struct mxc_gpio_port { | |||
37 | int virtual_irq_start; | 37 | int virtual_irq_start; |
38 | struct gpio_chip chip; | 38 | struct gpio_chip chip; |
39 | u32 both_edges; | 39 | u32 both_edges; |
40 | spinlock_t lock; | ||
40 | }; | 41 | }; |
41 | 42 | ||
42 | int mxc_gpio_init(struct mxc_gpio_port*, int); | 43 | int mxc_gpio_init(struct mxc_gpio_port*, int); |