summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Sanders <nsanders@chromium.org>2016-04-13 22:15:02 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-04-27 14:04:07 -0700
commit4e52ae607c569e9d240e3ce3363659c840f1aa87 (patch)
tree6824faac11c4b35ebce8599f41e39c28351eb816
parentd18cb0e81f2ba3c71349d17c7d84e7e10066711e (diff)
downloadchrome-ec-4e52ae607c569e9d240e3ce3363659c840f1aa87.tar.gz
servo_micro: add gpio mode get and set
GPIO console commands currently only show input voltage level, and can only set level on predefined outputs. This change allows GPIOs to be cycled between output, input, and alternate function, as well as displaying the mode and asserted level (if any) in gpioget. This change creates CONFIG_CMD_GPIO_EXTENDED as the internal gpio interface needs to be changed to support this, and I can't test the other architectures. It may be worthwhile to add this for all, or not. This change is also necessary also for servo micro JTAG and PD UART support, as several pins are tied together on the flex and stm32 outputs need to be variously active or in high-z depending on mode. BUG=chromium:571477 TEST=gpioget <0|1|IN|A|ALT>; gpioget; BRANCH=None Change-Id: Iba32992db6244ee1e654db840d1c9c11dd2a0993 Signed-off-by: Nick Sanders <nsanders@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/338885 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--board/servo_micro/board.h3
-rw-r--r--chip/stm32/gpio-f0-l.c51
-rw-r--r--common/gpio.c9
-rw-r--r--common/gpio_commands.c92
-rw-r--r--include/config.h1
-rw-r--r--include/gpio.h20
6 files changed, 163 insertions, 13 deletions
diff --git a/board/servo_micro/board.h b/board/servo_micro/board.h
index 810fecb60a..48f9368436 100644
--- a/board/servo_micro/board.h
+++ b/board/servo_micro/board.h
@@ -56,6 +56,9 @@
/* Enable control of GPIOs over USB */
#define CONFIG_USB_GPIO
+/* Enable console recasting of GPIO type. */
+#define CONFIG_CMD_GPIO_EXTENDED
+
/* Enable control of SPI over USB */
#define CONFIG_USB_SPI
#define CONFIG_SPI_MASTER
diff --git a/chip/stm32/gpio-f0-l.c b/chip/stm32/gpio-f0-l.c
index df45c15aa5..4c026cc767 100644
--- a/chip/stm32/gpio-f0-l.c
+++ b/chip/stm32/gpio-f0-l.c
@@ -24,6 +24,53 @@ static uint32_t expand_to_2bit_mask(uint32_t mask)
return mask_out;
}
+int gpio_get_flags_by_mask(uint32_t port, uint32_t mask)
+{
+ uint32_t flags = 0;
+ uint32_t val = 0;
+ const uint32_t mask2 = expand_to_2bit_mask(mask);
+
+ /* Only one bit must be set. */
+ if ((mask != (mask & -mask)) || (mask == 0))
+ return 0;
+
+ /* Check output type. */
+ val = STM32_GPIO_PUPDR(port) & mask2;
+ if (val == (0x55555555 & mask2))
+ flags |= GPIO_PULL_UP;
+ if (val == (0xaaaaaaaa & mask2))
+ flags |= GPIO_PULL_DOWN;
+
+ if (STM32_GPIO_OTYPER(port) & mask)
+ flags |= GPIO_OPEN_DRAIN;
+
+ /* Check mode. */
+ val = STM32_GPIO_MODER(port) & mask2;
+ if (val == (0x55555555 & mask2))
+ flags |= GPIO_OUTPUT;
+ if (val == (0xFFFFFFFF & mask2))
+ flags |= GPIO_ANALOG;
+ if (val == (0x0 & mask2))
+ flags |= GPIO_INPUT;
+ if (val == (0xaaaaaaaa & mask2))
+ flags |= GPIO_ALTERNATE;
+
+ if (flags & GPIO_OUTPUT) {
+ if (STM32_GPIO_ODR(port) & mask)
+ flags |= GPIO_HIGH;
+ else
+ flags |= GPIO_LOW;
+ }
+
+
+ if (STM32_EXTI_RTSR & mask)
+ flags |= GPIO_INT_F_RISING;
+ if (STM32_EXTI_RTSR & mask)
+ flags |= GPIO_INT_F_RISING;
+
+ return flags;
+}
+
void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
{
/* Bitmask for registers with 2 bits per GPIO pin */
@@ -70,6 +117,10 @@ void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags)
} else if (flags & GPIO_INPUT) {
/* Input, MODE=00 */
STM32_GPIO_MODER(port) = val;
+ } else if (flags & GPIO_ALTERNATE) {
+ /* Alternate, MODE=10 */
+ val |= 0xaaaaaaaa & mask2;
+ STM32_GPIO_MODER(port) = val;
}
/* Set up interrupts if necessary */
diff --git a/common/gpio.c b/common/gpio.c
index 817662f743..f4e3cfe2b8 100644
--- a/common/gpio.c
+++ b/common/gpio.c
@@ -113,6 +113,15 @@ void gpio_set_flags(enum gpio_signal signal, int flags)
gpio_set_flags_by_mask(g->port, g->mask, flags);
}
+#ifdef CONFIG_CMD_GPIO_EXTENDED
+int gpio_get_flags(enum gpio_signal signal)
+{
+ const struct gpio_info *g = gpio_list + signal;
+
+ return gpio_get_flags_by_mask(g->port, g->mask);
+}
+#endif
+
int gpio_get_default_flags(enum gpio_signal signal)
{
return gpio_list[signal].flags;
diff --git a/common/gpio_commands.c b/common/gpio_commands.c
index 25185597ea..e3ce1d046d 100644
--- a/common/gpio_commands.c
+++ b/common/gpio_commands.c
@@ -77,19 +77,47 @@ static enum ec_error_list set(const char *name, int value)
/*****************************************************************************/
/* Console commands */
+static void print_gpio_info(int gpio)
+{
+ int changed, v, flags;
+
+ if (!gpio_is_implemented(gpio))
+ return; /* Skip unsupported signals */
+
+ v = gpio_get_level(gpio);
+#ifdef CONFIG_CMD_GPIO_EXTENDED
+ flags = gpio_get_flags(gpio);
+#else
+ flags = 0;
+#endif
+ changed = last_val_changed(gpio, v);
+
+ ccprintf(" %d%c %s%s%s%s%s%s%s%s%s%s\n", v, (changed ? '*' : ' '),
+ (flags & GPIO_INPUT ? "I " : ""),
+ (flags & GPIO_OUTPUT ? "O " : ""),
+ (flags & GPIO_LOW ? "L " : ""),
+ (flags & GPIO_HIGH ? "H " : ""),
+ (flags & GPIO_ANALOG ? "A " : ""),
+ (flags & GPIO_OPEN_DRAIN ? "ODR " : ""),
+ (flags & GPIO_PULL_UP ? "PU " : ""),
+ (flags & GPIO_PULL_DOWN ? "PD " : ""),
+ (flags & GPIO_ALTERNATE ? "ALT " : ""),
+ gpio_get_name(gpio));
+
+ /* Flush console to avoid truncating output */
+ cflush();
+}
+
static int command_gpio_get(int argc, char **argv)
{
- int changed, v, i;
+ int i;
/* If a signal is specified, print only that one */
if (argc == 2) {
i = find_signal_by_name(argv[1]);
if (i == GPIO_COUNT)
return EC_ERROR_PARAM1;
- v = gpio_get_level(i);
- changed = last_val_changed(i, v);
- ccprintf(" %d%c %s\n", v, (changed ? '*' : ' '),
- gpio_get_name(i));
+ print_gpio_info(i);
return EC_SUCCESS;
}
@@ -99,13 +127,7 @@ static int command_gpio_get(int argc, char **argv)
if (!gpio_is_implemented(i))
continue; /* Skip unsupported signals */
- v = gpio_get_level(i);
- changed = last_val_changed(i, v);
- ccprintf(" %d%c %s\n", v, (changed ? '*' : ' '),
- gpio_get_name(i));
-
- /* Flush console to avoid truncating output */
- cflush();
+ print_gpio_info(i);
}
return EC_SUCCESS;
@@ -117,6 +139,46 @@ DECLARE_CONSOLE_COMMAND(gpioget, command_gpio_get,
static int command_gpio_set(int argc, char **argv)
{
+#ifdef CONFIG_CMD_GPIO_EXTENDED
+ int gpio;
+ int flags = 0;
+ int af = -1;
+ char *e;
+
+ if (argc < 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ gpio = find_signal_by_name(argv[1]);
+ if (gpio == GPIO_COUNT)
+ return EC_ERROR_PARAM1;
+
+ if (strcasecmp(argv[2], "IN") == 0)
+ flags = GPIO_INPUT;
+ else if (strcasecmp(argv[2], "1") == 0)
+ flags = GPIO_OUT_HIGH;
+ else if (strcasecmp(argv[2], "0") == 0)
+ flags = GPIO_OUT_LOW;
+ else if (strcasecmp(argv[2], "A") == 0)
+ flags = GPIO_ANALOG;
+ else if (strcasecmp(argv[2], "ALT") == 0) {
+ if (argc >= 4) {
+ af = strtoi(argv[3], &e, 0);
+ if (*e || af < 0 || af > 5)
+ return EC_ERROR_PARAM2;
+ }
+ flags = GPIO_ALTERNATE;
+ } else
+ return EC_ERROR_PARAM2;
+
+ /* Update alt function if requested. */
+ if (af >= 0) {
+ const struct gpio_info *g = gpio_list + gpio;
+
+ gpio_set_alternate_function(g->port, g->mask, af);
+ }
+ /* Update GPIO flags. */
+ gpio_set_flags(gpio, flags);
+#else
char *e;
int v;
@@ -129,11 +191,15 @@ static int command_gpio_set(int argc, char **argv)
if (set(argv[1], v) != EC_SUCCESS)
return EC_ERROR_PARAM1;
-
+#endif
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(gpioset, command_gpio_set,
+#ifdef CONFIG_CMD_GPIO_EXTENDED
+ "name <0 | 1 | IN | A | ALT [func]>",
+#else
"name <0 | 1>",
+#endif
"Set a GPIO",
NULL);
diff --git a/include/config.h b/include/config.h
index 63096c843c..9db99d5ddc 100644
--- a/include/config.h
+++ b/include/config.h
@@ -533,6 +533,7 @@
#undef CONFIG_CMD_FLASH
#undef CONFIG_CMD_FORCETIME
#undef CONFIG_CMD_GSV
+#undef CONFIG_CMD_GPIO_EXTENDED
#define CONFIG_CMD_HASH
#define CONFIG_CMD_HCDEBUG
#undef CONFIG_CMD_HOSTCMD
diff --git a/include/gpio.h b/include/gpio.h
index 52638e4222..b588659a88 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -30,6 +30,7 @@
#define GPIO_INT_DSLEEP (1 << 14) /* Interrupt in deep sleep */
#define GPIO_INT_SHARED (1 << 15) /* Shared among multiple pins */
#define GPIO_SEL_1P8V (1 << 16) /* Support 1.8v */
+#define GPIO_ALTERNATE (1 << 17) /* GPIO used for alternate function. */
/* Common flag combinations */
#define GPIO_OUT_LOW (GPIO_OUTPUT | GPIO_LOW)
@@ -146,6 +147,24 @@ int gpio_is_implemented(enum gpio_signal signal);
*/
void gpio_set_flags(enum gpio_signal signal, int flags);
+#ifdef CONFIG_CMD_GPIO_EXTENDED
+/**
+ * Get the current flags for a signal.
+ *
+ * @param signal Signal to get flags for
+ * @returns The flags that are currently defined for this signal
+ */
+int gpio_get_flags(enum gpio_signal signal);
+
+/**
+ * Get flags for GPIO by port and mask.
+ *
+ * @param port GPIO port to set (GPIO_*)
+ * @param mask Bitmask of pins on that port to check: one only.
+ */
+int gpio_get_flags_by_mask(uint32_t port, uint32_t mask);
+#endif
+
/**
* Get the default flags for a signal.
*
@@ -211,6 +230,7 @@ int gpio_disable_interrupt(enum gpio_signal signal);
*/
void gpio_set_flags_by_mask(uint32_t port, uint32_t mask, uint32_t flags);
+
/**
* Set alternate function for GPIO(s).
*