summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJes B. Klinke <jbk@chromium.org>2023-02-13 10:36:37 -0800
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-02-14 18:30:00 +0000
commitb34c7aa7821d7b3e51587a8d35d3fc82fc3104ca (patch)
tree0c14639528bbdb2fd7065bfada6f70a12b462e64
parent5b671a552726c1dbded0cbec0b33ab2da89d3e85 (diff)
downloadchrome-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.c64
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);