Skip to content

Commit 0c9a947

Browse files
markfeathersgregkh
authored andcommitted
gpio: ts4900: Do not set DAT and OE together
[ Upstream commit 03fe003 ] 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 <[email protected]> Signed-off-by: Kris Bahnsen <[email protected]> Signed-off-by: Bartosz Golaszewski <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 205c4ec commit 0c9a947

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
@@ -52,19 +52,33 @@ static int ts4900_gpio_direction_input(struct gpio_chip *chip,
5252
{
5353
struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
5454

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

6261
static int ts4900_gpio_direction_output(struct gpio_chip *chip,
6362
unsigned int offset, int value)
6463
{
6564
struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
65+
unsigned int reg;
6666
int ret;
6767

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

0 commit comments

Comments
 (0)