diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2018-01-02 15:40:00 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-03 16:54:35 -0800 |
commit | 5789d6925777d82db30d80cd2eef62f57e5c9ca7 (patch) | |
tree | 34cf8440fd8b2b1ecaec83711bfae5097d95a76a /chip/g | |
parent | 27f92a378aad37bac9f2de1a311f78012eac574b (diff) | |
download | chrome-ec-5789d6925777d82db30d80cd2eef62f57e5c9ca7.tar.gz |
g: simulate open drain GPIO behavior
Some upcoming designs based on the g chip require GPIOs connected to
open drain circuits.
Even though the chip explicitly provides only two open drain GPIOs,
the desired behavior of the rest of the pins when configured as 'open
drain' could be simulated by software if when 'high' is required the
output is disabled instead of driving the pin value.
To make sure there is no fallout from RO driving the pins, also add an
explicit 'disable output' initialization in case a GPIO is configured
for open drain and the initial output value is 'high'.
BRANCH=cr50
BUG=none
TEST=verified that Cr50 booted successfully, also confirmed that on
the test board that GPIOs defined as Open Drain allow we set
output to 1 only if pulled up.
Change-Id: Id2daa19b992bab7fb01148b6fa7b57fd0728b33d
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/848152
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/g')
-rw-r--r-- | chip/g/gpio.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/chip/g/gpio.c b/chip/g/gpio.c index c8399f01ce..432608beea 100644 --- a/chip/g/gpio.c +++ b/chip/g/gpio.c @@ -38,6 +38,16 @@ static void set_one_gpio_bit(uint32_t port, uint16_t mask, int value) void gpio_set_level(enum gpio_signal signal, int value) { const struct gpio_info *g = gpio_list + signal; + + if (g->flags & GPIO_OPEN_DRAIN) { + if (value) { + GR_GPIO_CLRDOUTEN(g->port) = g->mask; + /* Don't ever set ODR output to HIGH. */ + return; + } + GR_GPIO_SETDOUTEN(g->port) = g->mask; + } + set_one_gpio_bit(g->port, g->mask, value); } @@ -68,17 +78,30 @@ int gpio_get_flags_by_mask(uint32_t port, uint32_t mask) void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags) { - /* Only matters for outputs */ - if (flags & GPIO_LOW) - set_one_gpio_bit(port, mask, 0); - else if (flags & GPIO_HIGH) - set_one_gpio_bit(port, mask, 1); - - /* Output must be enabled; input is always enabled */ - if (flags & GPIO_OUTPUT) - GR_GPIO_SETDOUTEN(port) = mask; - else + /* Output must be enabled when needed, input is always enabled */ + if (flags & GPIO_OUTPUT) { + + if (flags & GPIO_LOW) + set_one_gpio_bit(port, mask, 0); + else if ((flags & GPIO_HIGH) && !(flags & GPIO_OPEN_DRAIN)) + /* Set to HIGH only if not open drain. */ + set_one_gpio_bit(port, mask, 1); + + if (!(flags & GPIO_OPEN_DRAIN) || (flags & GPIO_LOW)) + /* + * Enable output for push-pull (high or low), or + * open-drain low. + */ + GR_GPIO_SETDOUTEN(port) = mask; + else if (flags & GPIO_OPEN_DRAIN) + /* + * Disable output for other open-drain cases to get a + * high-Z pin. + */ + GR_GPIO_CLRDOUTEN(port) = mask; + } else { GR_GPIO_CLRDOUTEN(port) = mask; + } /* Interrupt types */ if (flags & GPIO_INT_F_LOW) { |