From 001851659354cce436b749a793f3512a53394d80 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 21 Dec 2010 13:04:42 -0800 Subject: cs5535-gpio: don't apply errata #36 to edge detect GPIOs The edge detect status GPIOs function differently from the other atomic model CS5536 GPIO registers; writing 1 to the high bits clears the GPIO, but writing 1 to the lower bits also clears the bit. This means that read-modify-write doesn't actually work for it, so don't apply the errata here. If a negative edge status gets lost after resume.. well, we tried our best! Tested-by: Daniel Drake Signed-off-by: Andres Salomon Signed-off-by: Linus Torvalds --- drivers/gpio/cs5535-gpio.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/gpio/cs5535-gpio.c') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 599f6c9e0fbf..79eb9c5a2923 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -56,15 +56,22 @@ static struct cs5535_gpio_chip { * registers, see include/linux/cs5535.h. */ -static void errata_outl(u32 val, unsigned long addr) +static void errata_outl(struct cs5535_gpio_chip *chip, u32 val, + unsigned int reg) { + unsigned long addr = chip->base + 0x80 + reg; + /* * 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. + * + * Don't apply this errata to the edge status GPIOs, as writing + * to their lower bits will clear them. */ - val |= inl(addr); + if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) + val |= inl(addr); outl(val, addr); } @@ -76,7 +83,7 @@ static void __cs5535_gpio_set(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << offset, chip->base + reg); else /* high bank register */ - errata_outl(1 << (offset - 16), chip->base + 0x80 + reg); + errata_outl(chip, 1 << (offset - 16), reg); } void cs5535_gpio_set(unsigned offset, unsigned int reg) @@ -98,7 +105,7 @@ static void __cs5535_gpio_clear(struct cs5535_gpio_chip *chip, unsigned offset, outl(1 << (offset + 16), chip->base + reg); else /* high bank register */ - errata_outl(1 << offset, chip->base + 0x80 + reg); + errata_outl(chip, 1 << offset, reg); } void cs5535_gpio_clear(unsigned offset, unsigned int reg) -- cgit v1.2.1 From 44658a11f312fb9217674cb90b1a11cbe17fd18d Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Tue, 21 Dec 2010 13:04:52 -0800 Subject: cs5535-gpio: handle GPIO regs where higher (clear) bits are set The default for non-READ_BACK GPIO regs is to have the clear bits set; this means that our original errata fix was too simplistic. This changes it to the following behavior: - when setting GPIOs, ignore the higher order bits (they're for clearing, we don't need to care about them). - when clearing GPIOs, keep all the bits, but unset (via XOR) the lower order bit that negates the clear bit that we care about. That is, if we're clearing GPIO 26 (val = 0x04000000), we first XOR what's currently in the register with 0x0400 (GPIO 26's SET bit), and then OR that with the GPIO 26's CLEAR bit. Tested-by: Daniel Drake Signed-off-by: Andres Salomon Signed-off-by: Linus Torvalds --- drivers/gpio/cs5535-gpio.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/gpio/cs5535-gpio.c') diff --git a/drivers/gpio/cs5535-gpio.c b/drivers/gpio/cs5535-gpio.c index 79eb9c5a2923..d3e55a0ae92b 100644 --- a/drivers/gpio/cs5535-gpio.c +++ b/drivers/gpio/cs5535-gpio.c @@ -70,8 +70,12 @@ static void errata_outl(struct cs5535_gpio_chip *chip, u32 val, * Don't apply this errata to the edge status GPIOs, as writing * to their lower bits will clear them. */ - if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) - val |= inl(addr); + if (reg != GPIO_POSITIVE_EDGE_STS && reg != GPIO_NEGATIVE_EDGE_STS) { + if (val & 0xffff) + val |= (inl(addr) & 0xffff); /* ignore the high bits */ + else + val |= (inl(addr) ^ (val >> 16)); + } outl(val, addr); } -- cgit v1.2.1