.. | .. |
---|
1 | 1 | /* |
---|
2 | 2 | * Digital I/O driver for Technologic Systems I2C FPGA Core |
---|
3 | 3 | * |
---|
4 | | - * Copyright (C) 2015 Technologic Systems |
---|
| 4 | + * Copyright (C) 2015, 2018 Technologic Systems |
---|
5 | 5 | * Copyright (C) 2016 Savoir-Faire Linux |
---|
6 | 6 | * |
---|
7 | 7 | * This program is free software; you can redistribute it and/or |
---|
.. | .. |
---|
44 | 44 | |
---|
45 | 45 | regmap_read(priv->regmap, offset, ®); |
---|
46 | 46 | |
---|
47 | | - return !(reg & TS4900_GPIO_OE); |
---|
| 47 | + if (reg & TS4900_GPIO_OE) |
---|
| 48 | + return GPIO_LINE_DIRECTION_OUT; |
---|
| 49 | + |
---|
| 50 | + return GPIO_LINE_DIRECTION_IN; |
---|
48 | 51 | } |
---|
49 | 52 | |
---|
50 | 53 | static int ts4900_gpio_direction_input(struct gpio_chip *chip, |
---|
.. | .. |
---|
52 | 55 | { |
---|
53 | 56 | struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); |
---|
54 | 57 | |
---|
55 | | - /* |
---|
56 | | - * This will clear the output enable bit, the other bits are |
---|
57 | | - * 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. |
---|
58 | 60 | */ |
---|
59 | | - return regmap_write(priv->regmap, offset, 0); |
---|
| 61 | + return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0); |
---|
60 | 62 | } |
---|
61 | 63 | |
---|
62 | 64 | static int ts4900_gpio_direction_output(struct gpio_chip *chip, |
---|
63 | 65 | unsigned int offset, int value) |
---|
64 | 66 | { |
---|
65 | 67 | struct ts4900_gpio_priv *priv = gpiochip_get_data(chip); |
---|
| 68 | + unsigned int reg; |
---|
66 | 69 | int ret; |
---|
67 | 70 | |
---|
| 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, ®); |
---|
| 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 | + |
---|
68 | 85 | if (value) |
---|
69 | 86 | ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE | |
---|
70 | 87 | TS4900_GPIO_OUT); |
---|