summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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).
*