diff options
-rw-r--r-- | board/servo_micro/board.h | 3 | ||||
-rw-r--r-- | chip/stm32/gpio-f0-l.c | 51 | ||||
-rw-r--r-- | common/gpio.c | 9 | ||||
-rw-r--r-- | common/gpio_commands.c | 92 | ||||
-rw-r--r-- | include/config.h | 1 | ||||
-rw-r--r-- | include/gpio.h | 20 |
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). * |