diff options
author | Hauke Mehrtens <hauke@hauke-m.de> | 2012-11-20 17:24:32 -0500 |
---|---|---|
committer | John Crispin <blogic@openwrt.org> | 2012-11-21 15:55:52 -0500 |
commit | 394bc7e38be79987ed15de203920c3cddb724cc1 (patch) | |
tree | 64cb52592aab0fb2f392560fb99d8d61caa81f4a /drivers/ssb/driver_chipcommon.c | |
parent | da22f22e91f0d14d996c7258101575a5a06ddf85 (diff) |
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: Hauke Mehrtens <hauke@hauke-m.de>
Patchwork: http://patchwork.linux-mips.org/patch/4590
Acked-by: Florian Fainelli <florian@openwrt.org>
Diffstat (limited to 'drivers/ssb/driver_chipcommon.c')
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 66 |
1 files changed, 59 insertions, 7 deletions
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 4df492665565..24e02bb2ecd8 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c | |||
@@ -284,6 +284,9 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) | |||
284 | { | 284 | { |
285 | if (!cc->dev) | 285 | if (!cc->dev) |
286 | return; /* We don't have a ChipCommon */ | 286 | return; /* We don't have a ChipCommon */ |
287 | |||
288 | spin_lock_init(&cc->gpio_lock); | ||
289 | |||
287 | if (cc->dev->id.revision >= 11) | 290 | if (cc->dev->id.revision >= 11) |
288 | cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); | 291 | cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT); |
289 | ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status); | 292 | 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 | 421 | ||
419 | u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) | 422 | u32 ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value) |
420 | { | 423 | { |
421 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); | 424 | unsigned long flags; |
425 | u32 res = 0; | ||
426 | |||
427 | spin_lock_irqsave(&cc->gpio_lock, flags); | ||
428 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value); | ||
429 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
430 | |||
431 | return res; | ||
422 | } | 432 | } |
423 | 433 | ||
424 | u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) | 434 | u32 ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value) |
425 | { | 435 | { |
426 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); | 436 | unsigned long flags; |
437 | u32 res = 0; | ||
438 | |||
439 | spin_lock_irqsave(&cc->gpio_lock, flags); | ||
440 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value); | ||
441 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
442 | |||
443 | return res; | ||
427 | } | 444 | } |
428 | 445 | ||
429 | u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) | 446 | u32 ssb_chipco_gpio_control(struct ssb_chipcommon *cc, u32 mask, u32 value) |
430 | { | 447 | { |
431 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); | 448 | unsigned long flags; |
449 | u32 res = 0; | ||
450 | |||
451 | spin_lock_irqsave(&cc->gpio_lock, flags); | ||
452 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOCTL, mask, value); | ||
453 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
454 | |||
455 | return res; | ||
432 | } | 456 | } |
433 | EXPORT_SYMBOL(ssb_chipco_gpio_control); | 457 | EXPORT_SYMBOL(ssb_chipco_gpio_control); |
434 | 458 | ||
435 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) | 459 | u32 ssb_chipco_gpio_intmask(struct ssb_chipcommon *cc, u32 mask, u32 value) |
436 | { | 460 | { |
437 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); | 461 | unsigned long flags; |
462 | u32 res = 0; | ||
463 | |||
464 | spin_lock_irqsave(&cc->gpio_lock, flags); | ||
465 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOIRQ, mask, value); | ||
466 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
467 | |||
468 | return res; | ||
438 | } | 469 | } |
439 | 470 | ||
440 | u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) | 471 | u32 ssb_chipco_gpio_polarity(struct ssb_chipcommon *cc, u32 mask, u32 value) |
441 | { | 472 | { |
442 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); | 473 | unsigned long flags; |
474 | u32 res = 0; | ||
475 | |||
476 | spin_lock_irqsave(&cc->gpio_lock, flags); | ||
477 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPOL, mask, value); | ||
478 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
479 | |||
480 | return res; | ||
443 | } | 481 | } |
444 | 482 | ||
445 | u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) | 483 | u32 ssb_chipco_gpio_pullup(struct ssb_chipcommon *cc, u32 mask, u32 value) |
446 | { | 484 | { |
485 | unsigned long flags; | ||
486 | u32 res = 0; | ||
487 | |||
447 | if (cc->dev->id.revision < 20) | 488 | if (cc->dev->id.revision < 20) |
448 | return 0xffffffff; | 489 | return 0xffffffff; |
449 | 490 | ||
450 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); | 491 | spin_lock_irqsave(&cc->gpio_lock, flags); |
492 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLUP, mask, value); | ||
493 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
494 | |||
495 | return res; | ||
451 | } | 496 | } |
452 | 497 | ||
453 | u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) | 498 | u32 ssb_chipco_gpio_pulldown(struct ssb_chipcommon *cc, u32 mask, u32 value) |
454 | { | 499 | { |
500 | unsigned long flags; | ||
501 | u32 res = 0; | ||
502 | |||
455 | if (cc->dev->id.revision < 20) | 503 | if (cc->dev->id.revision < 20) |
456 | return 0xffffffff; | 504 | return 0xffffffff; |
457 | 505 | ||
458 | return chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); | 506 | spin_lock_irqsave(&cc->gpio_lock, flags); |
507 | res = chipco_write32_masked(cc, SSB_CHIPCO_GPIOPULLDOWN, mask, value); | ||
508 | spin_unlock_irqrestore(&cc->gpio_lock, flags); | ||
509 | |||
510 | return res; | ||
459 | } | 511 | } |
460 | 512 | ||
461 | #ifdef CONFIG_SSB_SERIAL | 513 | #ifdef CONFIG_SSB_SERIAL |