Skip to content

Commit 03fe003

Browse files
markfeathersbrgl
authored andcommitted
gpio: ts4900: Do not set DAT and OE together
This works around an issue with the hardware where both OE and DAT are exposed in the same register. If both are updated simultaneously, the harware makes no guarantees that OE or DAT will actually change in any given order and may result in a glitch of a few ns on a GPIO pin when changing direction and value in a single write. Setting direction to input now only affects OE bit. Setting direction to output updates DAT first, then OE. Fixes: 9c66863 ("gpio: add Technologic I2C-FPGA gpio support") Signed-off-by: Mark Featherston <mark@embeddedTS.com> Signed-off-by: Kris Bahnsen <kris@embeddedTS.com> Signed-off-by: Bartosz Golaszewski <brgl@bgdev.pl>
1 parent a9a5b72 commit 03fe003

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

drivers/gpio/gpio-ts4900.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Digital I/O driver for Technologic Systems I2C FPGA Core
33
*
4-
* Copyright (C) 2015 Technologic Systems
4+
* Copyright (C) 2015, 2018 Technologic Systems
55
* Copyright (C) 2016 Savoir-Faire Linux
66
*
77
* This program is free software; you can redistribute it and/or
@@ -55,19 +55,33 @@ static int ts4900_gpio_direction_input(struct gpio_chip *chip,
5555
{
5656
struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
5757

58-
/*
59-
* This will clear the output enable bit, the other bits are
60-
* dontcare when this is cleared
58+
/* Only clear the OE bit here, requires a RMW. Prevents potential issue
59+
* with OE and data getting to the physical pin at different times.
6160
*/
62-
return regmap_write(priv->regmap, offset, 0);
61+
return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);
6362
}
6463

6564
static int ts4900_gpio_direction_output(struct gpio_chip *chip,
6665
unsigned int offset, int value)
6766
{
6867
struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
68+
unsigned int reg;
6969
int ret;
7070

71+
/* If changing from an input to an output, we need to first set the
72+
* proper data bit to what is requested and then set OE bit. This
73+
* prevents a glitch that can occur on the IO line
74+
*/
75+
regmap_read(priv->regmap, offset, &reg);
76+
if (!(reg & TS4900_GPIO_OE)) {
77+
if (value)
78+
reg = TS4900_GPIO_OUT;
79+
else
80+
reg &= ~TS4900_GPIO_OUT;
81+
82+
regmap_write(priv->regmap, offset, reg);
83+
}
84+
7185
if (value)
7286
ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
7387
TS4900_GPIO_OUT);

0 commit comments

Comments
 (0)