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>
This commit is contained in:
Vadim Bendebury
2018-01-02 15:40:00 -08:00
committed by chrome-bot
parent 27f92a378a
commit 5789d69257

View File

@@ -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 when needed, input is always enabled */
if (flags & GPIO_OUTPUT) {
/* Output must be enabled; input is always enabled */
if (flags & GPIO_OUTPUT)
GR_GPIO_SETDOUTEN(port) = mask;
else
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) {