diff options
author | Jes B. Klinke <jbk@chromium.org> | 2023-02-13 10:36:37 -0800 |
---|---|---|
committer | Chromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-02-14 18:30:00 +0000 |
commit | b34c7aa7821d7b3e51587a8d35d3fc82fc3104ca (patch) | |
tree | 0c14639528bbdb2fd7065bfada6f70a12b462e64 | |
parent | 5b671a552726c1dbded0cbec0b33ab2da89d3e85 (diff) | |
download | chrome-ec-b34c7aa7821d7b3e51587a8d35d3fc82fc3104ca.tar.gz |
board/hyperdebug: Atomic setting of gpio mode and level
Currently, we use `opentitantool transport init` to configure all pins
according to some "standard" initial values. This involves configuring
open drain / push pull as well as setting default levels.
Unfortunately, if a pin is for instance listed as being "open drain,
high level" as default (no active drive), we currently have to make the
choice of whether to first configure the pin as open drain output, or
first configure the output to high. If we first configure the level to
become 1, we run the risk that the pin was set as push pull, and it will
be actively be driven high for a fraction of a second, before it is set
to open drain, and goes floating. If we instead first configure the
mode to become open drain, then we risk that the pin was previously in
input mode, with a "leftover" value of 0 in the output register, meaning
that switching to open drain mode will briefly drive the pin drongly
down, before the level is set to 1.
In order to avoid glitches, this CL introduces a "gpio multiset"
command, which can be used to simultaneously set the output level, pin
mode, and weak pull configuration of the pin.
BUG=b:192262089
TEST=Watch tast test work
Change-Id: Ie16771e5cb676af02a0dabe454e4173721629b30
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4245899
Tested-by: Jes Klinke <jbk@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
Commit-Queue: Jes Klinke <jbk@chromium.org>
-rw-r--r-- | board/hyperdebug/gpio.c | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/board/hyperdebug/gpio.c b/board/hyperdebug/gpio.c index 0b136bc59d..7dbc063237 100644 --- a/board/hyperdebug/gpio.c +++ b/board/hyperdebug/gpio.c @@ -338,6 +338,65 @@ DECLARE_CONSOLE_COMMAND_FLAGS(gpiopullmode, command_gpio_pull_mode, "name <none | up | down>", "Set a GPIO weak pull mode", CMD_FLAG_RESTRICTED); +/* + * Set multiple aspects of a GPIO pin simultaneously, that is, can switch output + * level, opendrain/pushpull, and pullup simultaneously, eliminating the risk of + * glitches. + */ +static int command_gpio_multiset(int argc, const char **argv) +{ + int gpio; + int flags; + + if (argc < 4) + return EC_ERROR_PARAM_COUNT; + + gpio = find_signal_by_name(argv[2]); + if (gpio == GPIO_COUNT) + return EC_ERROR_PARAM2; + flags = gpio_get_flags(gpio); + + if (argc > 3 && strcasecmp(argv[3], "-") != 0) { + flags = flags & ~(GPIO_LOW | GPIO_HIGH); + if (strcasecmp(argv[3], "0") == 0) + flags |= GPIO_LOW; + else if (strcasecmp(argv[3], "1") == 0) + flags |= GPIO_HIGH; + else + return EC_ERROR_PARAM3; + } + + if (argc > 4 && strcasecmp(argv[4], "-") != 0) { + flags = flags & ~(GPIO_INPUT | GPIO_OUTPUT | GPIO_OPEN_DRAIN); + if (strcasecmp(argv[4], "input") == 0) + flags |= GPIO_INPUT; + else if (strcasecmp(argv[4], "opendrain") == 0) + flags |= GPIO_OUTPUT | GPIO_OPEN_DRAIN; + else if (strcasecmp(argv[4], "pushpull") == 0) + flags |= GPIO_OUTPUT; + else if (strcasecmp(argv[4], "alternate") == 0) + flags |= GPIO_ALTERNATE; + else + return EC_ERROR_PARAM4; + } + + if (argc > 5 && strcasecmp(argv[5], "-") != 0) { + flags = flags & ~(GPIO_PULL_UP | GPIO_PULL_DOWN); + if (strcasecmp(argv[5], "none") == 0) + ; + else if (strcasecmp(argv[5], "up") == 0) + flags |= GPIO_PULL_UP; + else if (strcasecmp(argv[5], "down") == 0) + flags |= GPIO_PULL_DOWN; + else + return EC_ERROR_PARAM5; + } + + /* Update GPIO flags. */ + gpio_set_flags(gpio, flags); + return EC_SUCCESS; +} + static int command_gpio_monitoring_start(int argc, const char **argv) { BUILD_ASSERT(STM32_IRQ_EXTI15 < 32); @@ -668,10 +727,13 @@ static int command_gpio(int argc, const char **argv) return EC_ERROR_PARAM_COUNT; if (!strcasecmp(argv[1], "monitoring")) return command_gpio_monitoring(argc, argv); + if (!strcasecmp(argv[1], "multiset")) + return command_gpio_multiset(argc, argv); return EC_ERROR_PARAM1; } DECLARE_CONSOLE_COMMAND_FLAGS(gpio, command_gpio, - "monitoring start PIN" + "multiset PIN [level] [mode] [pullmode]" + "\nmonitoring start PIN" "\nmonitoring read PIN" "\nmonitoring stop PIN", "GPIO manipulation", CMD_FLAG_RESTRICTED); |