| .. | .. |
|---|
| 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); |
|---|