Commit 394bc7e3 authored by Hauke Mehrtens's avatar Hauke Mehrtens Committed by John Crispin

ssb: add locking around gpio register accesses

The GPIOs are access through some registers in the chip common core or
over extif. We need locking around these GPIO accesses, all GPIOs are
accessed through the same registers and parallel writes will cause
problems.
Signed-off-by: default avatarHauke Mehrtens <hauke@hauke-m.de>
Patchwork: http://patchwork.linux-mips.org/patch/4590Acked-by: default avatarFlorian Fainelli <florian@openwrt.org>
parent da22f22e
...@@ -284,6 +284,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) ...@@ -284,6 +284,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
{ {
if (!cc->dev) if (!cc->dev)
return; /* We don't have a ChipCommon */ return; /* We don't have a ChipCommon */
spin_lock_init(&cc->gpio_lock);
if (cc->dev->id.revision >= 11) if (cc->dev->id.revision >= 11)
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
...@@ -418,44 +421,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask) ...@@ -418,44 +421,93 @@ u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
EXPORT_SYMBOL(ssb_chipco_gpio_control); EXPORT_SYMBOL(ssb_chipco_gpio_control);
u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
unsigned long flags;
u32 res = 0;
if (cc->dev->id.revision < 20) if (cc->dev->id.revision < 20)
return 0xffffffff; return 0xffffffff;
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value)
{ {
unsigned long flags;
u32 res = 0;
if (cc->dev->id.revision < 20) if (cc->dev->id.revision < 20)
return 0xffffffff; return 0xffffffff;
return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); spin_lock_irqsave(&cc->gpio_lock, flags);
res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value);
spin_unlock_irqrestore(&cc->gpio_lock, flags);
return res;
} }
#ifdef CONFIG_SSB_SERIAL #ifdef CONFIG_SSB_SERIAL
......
...@@ -118,6 +118,13 @@ void ssb_extif_watchdog_timer_set(struct ssb_extif *extif, ...@@ -118,6 +118,13 @@ void ssb_extif_watchdog_timer_set(struct ssb_extif *extif,
extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks); extif_write32(extif, SSB_EXTIF_WATCHDOG, ticks);
} }
void ssb_extif_init(struct ssb_extif *extif)
{
if (!extif->dev)
return; /* We don't have a Extif core */
spin_lock_init(&extif->gpio_lock);
}
u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
{ {
return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask; return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
...@@ -125,22 +132,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask) ...@@ -125,22 +132,50 @@ u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value) u32 ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
{ {
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0), unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&extif->gpio_lock, flags);
res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
mask, value); mask, value);
spin_unlock_irqrestore(&extif->gpio_lock, flags);
return res;
} }
u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value) u32 ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
{ {
return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0), unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&extif->gpio_lock, flags);
res = extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
mask, value); mask, value);
spin_unlock_irqrestore(&extif->gpio_lock, flags);
return res;
} }
u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value) u32 ssb_extif_gpio_polarity(struct ssb_extif *extif, u32 mask, u32 value)
{ {
return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&extif->gpio_lock, flags);
res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTPOL, mask, value);
spin_unlock_irqrestore(&extif->gpio_lock, flags);
return res;
} }
u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value) u32 ssb_extif_gpio_intmask(struct ssb_extif *extif, u32 mask, u32 value)
{ {
return extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value); unsigned long flags;
u32 res = 0;
spin_lock_irqsave(&extif->gpio_lock, flags);
res = extif_write32_masked(extif, SSB_EXTIF_GPIO_INTMASK, mask, value);
spin_unlock_irqrestore(&extif->gpio_lock, flags);
return res;
} }
...@@ -796,6 +796,7 @@ static int __devinit ssb_bus_register(struct ssb_bus *bus, ...@@ -796,6 +796,7 @@ static int __devinit ssb_bus_register(struct ssb_bus *bus,
if (err) if (err)
goto err_pcmcia_exit; goto err_pcmcia_exit;
ssb_chipcommon_init(&bus->chipco); ssb_chipcommon_init(&bus->chipco);
ssb_extif_init(&bus->extif);
ssb_mipscore_init(&bus->mipscore); ssb_mipscore_init(&bus->mipscore);
err = ssb_fetch_invariants(bus, get_invariants); err = ssb_fetch_invariants(bus, get_invariants);
if (err) { if (err) {
......
...@@ -211,4 +211,12 @@ static inline void b43_pci_ssb_bridge_exit(void) ...@@ -211,4 +211,12 @@ static inline void b43_pci_ssb_bridge_exit(void)
extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_cpu_clock(struct ssb_chipcommon *cc);
extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc); extern u32 ssb_pmu_get_controlclock(struct ssb_chipcommon *cc);
#ifdef CONFIG_SSB_DRIVER_EXTIF
extern void ssb_extif_init(struct ssb_extif *extif);
#else
static inline void ssb_extif_init(struct ssb_extif *extif)
{
}
#endif
#endif /* LINUX_SSB_PRIVATE_H_ */ #endif /* LINUX_SSB_PRIVATE_H_ */
...@@ -590,6 +590,7 @@ struct ssb_chipcommon { ...@@ -590,6 +590,7 @@ struct ssb_chipcommon {
u32 status; u32 status;
/* Fast Powerup Delay constant */ /* Fast Powerup Delay constant */
u16 fast_pwrup_delay; u16 fast_pwrup_delay;
spinlock_t gpio_lock;
struct ssb_chipcommon_pmu pmu; struct ssb_chipcommon_pmu pmu;
}; };
......
...@@ -158,6 +158,7 @@ ...@@ -158,6 +158,7 @@
struct ssb_extif { struct ssb_extif {
struct ssb_device *dev; struct ssb_device *dev;
spinlock_t gpio_lock;
}; };
static inline bool ssb_extif_available(struct ssb_extif *extif) static inline bool ssb_extif_available(struct ssb_extif *extif)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment