Skip to content

Commit

Permalink
cs5535-gpio: apply CS5536 errata workaround for GPIOs
Browse files Browse the repository at this point in the history
The AMD Geode CS5536 Companion Device Silicon Revision B1 Specification
Update mentions the follow as issue #36:

 "Atomic write transactions to the atomic GPIO High Bank Feature Bit
  registers should only affect the bits selected [...]"

 "after Suspend, an atomic write transaction [...] will clear all
  non-selected bits of the accessed register."

In other words, writing to the high bank for a single GPIO bit will
clear every other GPIO bit (but only sometimes after a suspend).

The workaround described is obvious and simple; do a read-modify-write.
This patch does that, and documents why we're doing it.

Signed-off-by: Andres Salomon <dilinger@queued.net>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
  • Loading branch information
Andres Salomon authored and Linus Torvalds committed Dec 2, 2010
1 parent 238af87 commit 853ff88
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions drivers/gpio/cs5535-gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ static struct cs5535_gpio_chip {
* registers, see include/linux/cs5535.h.
*/

static void errata_outl(u32 val, unsigned long addr)
{
/*
* According to the CS5536 errata (#36), after suspend
* a write to the high bank GPIO register will clear all
* non-selected bits; the recommended workaround is a
* read-modify-write operation.
*/
val |= inl(addr);
outl(val, addr);
}

static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
unsigned int reg)
{
Expand All @@ -64,7 +76,7 @@ static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset,
outl(1 << offset, chip->base + reg);
else
/* high bank register */
outl(1 << (offset - 16), chip->base + 0x80 + reg);
errata_outl(1 << (offset - 16), chip->base + 0x80 + reg);
}

void cs5535_gpio_set(unsigned offset, unsigned int reg)
Expand All @@ -86,7 +98,7 @@ static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset,
outl(1 << (offset + 16), chip->base + reg);
else
/* high bank register */
outl(1 << offset, chip->base + 0x80 + reg);
errata_outl(1 << offset, chip->base + 0x80 + reg);
}

void cs5535_gpio_clear(unsigned offset, unsigned int reg)
Expand Down

0 comments on commit 853ff88

Please sign in to comment.