diff options
-rw-r--r-- | common/build.mk | 2 | ||||
-rw-r--r-- | common/gpio.c | 207 | ||||
-rw-r--r-- | common/gpio_commands.c | 208 | ||||
-rw-r--r-- | include/gpio.h | 19 |
4 files changed, 235 insertions, 201 deletions
diff --git a/common/build.mk b/common/build.mk index ba7c1a38b1..4995cfe6e8 100644 --- a/common/build.mk +++ b/common/build.mk @@ -33,7 +33,7 @@ common-$(CONFIG_CHARGER)+=charger.o common-$(CONFIG_CHARGER_V1)+=charge_state_v1.o common-$(CONFIG_CHARGER_V2)+=charge_state_v2.o common-$(CONFIG_CMD_I2CWEDGE)+=i2c_wedge.o -common-$(CONFIG_COMMON_GPIO)+=gpio.o +common-$(CONFIG_COMMON_GPIO)+=gpio.o gpio_commands.o common-$(CONFIG_COMMON_PANIC_OUTPUT)+=panic_output.o common-$(CONFIG_COMMON_RUNTIME)+=hooks.o main.o system.o shared_mem.o common-$(CONFIG_COMMON_TIMER)+=timer.o diff --git a/common/gpio.c b/common/gpio.c index e8652e7e9e..817662f743 100644 --- a/common/gpio.c +++ b/common/gpio.c @@ -6,59 +6,10 @@ /* GPIO common functionality for Chrome EC */ #include "common.h" -#include "console.h" #include "gpio.h" -#include "host_command.h" #include "registers.h" -#include "system.h" #include "util.h" -static uint8_t last_val[(GPIO_COUNT + 7) / 8]; - -/** - * Find a GPIO signal by name. - * - * @param name Signal name to find - * - * @return the signal index, or GPIO_COUNT if no match. - */ -static enum gpio_signal find_signal_by_name(const char *name) -{ - const struct gpio_info *g = gpio_list; - int i; - - if (!name || !*name) - return GPIO_COUNT; - - for (i = 0; i < GPIO_COUNT; i++, g++) { - if (g->mask && !strcasecmp(name, g->name)) - return i; - } - - return GPIO_COUNT; -} - -/** - * Update last_val - * - * @param i Index of last_val[] to update - * @param v New value for last_val[i] - * - * @return 1 if last_val[i] was updated, 0 if last_val[i]==v. - */ -static int last_val_changed(int i, int v) -{ - if (v && !(last_val[i / 8] & (1 << (i % 8)))) { - last_val[i / 8] |= 1 << (i % 8); - return 1; - } else if (!v && last_val[i / 8] & (1 << (i % 8))) { - last_val[i / 8] &= ~(1 << (i % 8)); - return 1; - } else { - return 0; - } -} - /* GPIO alternate function structure */ struct gpio_alt_func { /* Port base address */ @@ -162,6 +113,11 @@ void gpio_set_flags(enum gpio_signal signal, int flags) gpio_set_flags_by_mask(g->port, g->mask, flags); } +int gpio_get_default_flags(enum gpio_signal signal) +{ + return gpio_list[signal].flags; +} + void gpio_reset(enum gpio_signal signal) { const struct gpio_info *g = gpio_list + signal; @@ -175,158 +131,9 @@ const char *gpio_get_name(enum gpio_signal signal) return gpio_list[signal].name; } -/*****************************************************************************/ -/* Console commands */ - -static int command_gpio_get(int argc, char **argv) -{ - const struct gpio_info *g = gpio_list; - int changed, v, 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; - g = gpio_list + i; - v = gpio_get_level(i); - changed = last_val_changed(i, v); - ccprintf(" %d%c %s\n", v, (changed ? '*' : ' '), g->name); - - return EC_SUCCESS; - } - - /* Otherwise print them all */ - for (i = 0; i < GPIO_COUNT; i++, g++) { - if (!g->mask) - continue; /* Skip unsupported signals */ - - v = gpio_get_level(i); - changed = last_val_changed(i, v); - ccprintf(" %d%c %s\n", v, (changed ? '*' : ' '), g->name); - - /* Flush console to avoid truncating output */ - cflush(); - } - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(gpioget, command_gpio_get, - "[name]", - "Read GPIO value(s)", - NULL); - -static int command_gpio_set(int argc, char **argv) +int gpio_is_implemented(enum gpio_signal signal) { - const struct gpio_info *g; - char *e; - int v, i; - - if (argc < 3) - return EC_ERROR_PARAM_COUNT; - - i = find_signal_by_name(argv[1]); - if (i == GPIO_COUNT) - return EC_ERROR_PARAM1; - g = gpio_list + i; - - if (!g->mask) - return EC_ERROR_PARAM1; - - if (!(g->flags & GPIO_OUTPUT)) - return EC_ERROR_PARAM1; - - v = strtoi(argv[2], &e, 0); - if (*e) - return EC_ERROR_PARAM2; - - gpio_set_level(i, v); - - return EC_SUCCESS; + return !!gpio_list[signal].mask; } -DECLARE_CONSOLE_COMMAND(gpioset, command_gpio_set, - "name <0 | 1>", - "Set a GPIO", - NULL); /*****************************************************************************/ -/* Host commands */ - -static int gpio_command_get(struct host_cmd_handler_args *args) -{ - const struct gpio_info *g = gpio_list; - const struct ec_params_gpio_get_v1 *p_v1 = args->params; - struct ec_response_gpio_get_v1 *r_v1 = args->response; - int i, len; - - if (args->version == 0) { - const struct ec_params_gpio_get *p = args->params; - struct ec_response_gpio_get *r = args->response; - i = find_signal_by_name(p->name); - if (i == GPIO_COUNT) - return EC_RES_ERROR; - - r->val = gpio_get_level(i); - args->response_size = sizeof(struct ec_response_gpio_get); - return EC_RES_SUCCESS; - } - - switch (p_v1->subcmd) { - case EC_GPIO_GET_BY_NAME: - i = find_signal_by_name(p_v1->get_value_by_name.name); - if (i == GPIO_COUNT) - return EC_RES_ERROR; - - r_v1->get_value_by_name.val = gpio_get_level(i); - args->response_size = sizeof(r_v1->get_value_by_name); - break; - case EC_GPIO_GET_COUNT: - r_v1->get_count.val = GPIO_COUNT; - args->response_size = sizeof(r_v1->get_count); - break; - case EC_GPIO_GET_INFO: - if (p_v1->get_info.index >= GPIO_COUNT) - return EC_RES_ERROR; - - i = p_v1->get_info.index; - len = strlen(g[i].name); - memcpy(r_v1->get_info.name, g[i].name, len+1); - r_v1->get_info.val = gpio_get_level(i); - r_v1->get_info.flags = g[i].flags; - args->response_size = sizeof(r_v1->get_info); - break; - default: - return EC_RES_INVALID_PARAM; - } - - return EC_RES_SUCCESS; - -} -DECLARE_HOST_COMMAND(EC_CMD_GPIO_GET, gpio_command_get, - EC_VER_MASK(0) | EC_VER_MASK(1)); - -static int gpio_command_set(struct host_cmd_handler_args *args) -{ - const struct ec_params_gpio_set *p = args->params; - const struct gpio_info *g; - int i; - - if (system_is_locked()) - return EC_RES_ACCESS_DENIED; - - i = find_signal_by_name(p->name); - if (i == GPIO_COUNT) - return EC_RES_ERROR; - g = gpio_list + i; - - if (!g->mask) - return EC_RES_ERROR; - - if (!(g->flags & GPIO_OUTPUT)) - return EC_RES_ERROR; - - gpio_set_level(i, p->val); - - return EC_RES_SUCCESS; -} -DECLARE_HOST_COMMAND(EC_CMD_GPIO_SET, gpio_command_set, EC_VER_MASK(0)); diff --git a/common/gpio_commands.c b/common/gpio_commands.c new file mode 100644 index 0000000000..25185597ea --- /dev/null +++ b/common/gpio_commands.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* GPIO common functionality for Chrome EC */ + +#include "common.h" +#include "console.h" +#include "gpio.h" +#include "host_command.h" +#include "system.h" +#include "util.h" + +static uint8_t last_val[(GPIO_COUNT + 7) / 8]; + +/** + * Find a GPIO signal by name. + * + * @param name Signal name to find + * + * @return the signal index, or GPIO_COUNT if no match. + */ +static enum gpio_signal find_signal_by_name(const char *name) +{ + int i; + + if (!name || !*name) + return GPIO_COUNT; + + for (i = 0; i < GPIO_COUNT; i++) + if (gpio_is_implemented(i) && + !strcasecmp(name, gpio_get_name(i))) + return i; + + return GPIO_COUNT; +} + +/** + * Update last_val + * + * @param i Index of last_val[] to update + * @param v New value for last_val[i] + * + * @return 1 if last_val[i] was updated, 0 if last_val[i]==v. + */ +static int last_val_changed(int i, int v) +{ + if (v && !(last_val[i / 8] & (1 << (i % 8)))) { + last_val[i / 8] |= 1 << (i % 8); + return 1; + } else if (!v && last_val[i / 8] & (1 << (i % 8))) { + last_val[i / 8] &= ~(1 << (i % 8)); + return 1; + } else { + return 0; + } +} + +static enum ec_error_list set(const char *name, int value) +{ + enum gpio_signal signal = find_signal_by_name(name); + + if (signal == GPIO_COUNT) + return EC_ERROR_INVAL; + + if (!gpio_is_implemented(signal)) + return EC_ERROR_INVAL; + + if (!(gpio_get_default_flags(signal) & GPIO_OUTPUT)) + return EC_ERROR_INVAL; + + gpio_set_level(signal, value); + + return EC_SUCCESS; +} +/*****************************************************************************/ +/* Console commands */ + +static int command_gpio_get(int argc, char **argv) +{ + int changed, v, 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)); + + return EC_SUCCESS; + } + + /* Otherwise print them all */ + for (i = 0; i < GPIO_COUNT; i++) { + 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(); + } + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(gpioget, command_gpio_get, + "[name]", + "Read GPIO value(s)", + NULL); + +static int command_gpio_set(int argc, char **argv) +{ + char *e; + int v; + + if (argc < 3) + return EC_ERROR_PARAM_COUNT; + + v = strtoi(argv[2], &e, 0); + if (*e) + return EC_ERROR_PARAM2; + + if (set(argv[1], v) != EC_SUCCESS) + return EC_ERROR_PARAM1; + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(gpioset, command_gpio_set, + "name <0 | 1>", + "Set a GPIO", + NULL); + +/*****************************************************************************/ +/* Host commands */ + +static int gpio_command_get(struct host_cmd_handler_args *args) +{ + const struct ec_params_gpio_get_v1 *p_v1 = args->params; + struct ec_response_gpio_get_v1 *r_v1 = args->response; + int i, len; + + if (args->version == 0) { + const struct ec_params_gpio_get *p = args->params; + struct ec_response_gpio_get *r = args->response; + + i = find_signal_by_name(p->name); + if (i == GPIO_COUNT) + return EC_RES_ERROR; + + r->val = gpio_get_level(i); + args->response_size = sizeof(struct ec_response_gpio_get); + return EC_RES_SUCCESS; + } + + switch (p_v1->subcmd) { + case EC_GPIO_GET_BY_NAME: + i = find_signal_by_name(p_v1->get_value_by_name.name); + if (i == GPIO_COUNT) + return EC_RES_ERROR; + + r_v1->get_value_by_name.val = gpio_get_level(i); + args->response_size = sizeof(r_v1->get_value_by_name); + break; + case EC_GPIO_GET_COUNT: + r_v1->get_count.val = GPIO_COUNT; + args->response_size = sizeof(r_v1->get_count); + break; + case EC_GPIO_GET_INFO: + if (p_v1->get_info.index >= GPIO_COUNT) + return EC_RES_ERROR; + + i = p_v1->get_info.index; + len = strlen(gpio_get_name(i)); + memcpy(r_v1->get_info.name, gpio_get_name(i), len+1); + r_v1->get_info.val = gpio_get_level(i); + r_v1->get_info.flags = gpio_get_default_flags(i); + args->response_size = sizeof(r_v1->get_info); + break; + default: + return EC_RES_INVALID_PARAM; + } + + return EC_RES_SUCCESS; + +} +DECLARE_HOST_COMMAND(EC_CMD_GPIO_GET, gpio_command_get, + EC_VER_MASK(0) | EC_VER_MASK(1)); + +static int gpio_command_set(struct host_cmd_handler_args *args) +{ + const struct ec_params_gpio_set *p = args->params; + + if (system_is_locked()) + return EC_RES_ACCESS_DENIED; + + if (set(p->name, p->val) != EC_SUCCESS) + return EC_RES_ERROR; + + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_GPIO_SET, gpio_command_set, EC_VER_MASK(0)); diff --git a/include/gpio.h b/include/gpio.h index d7dcd9d3ca..7c0a4cad22 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -128,6 +128,17 @@ int gpio_get_level(enum gpio_signal signal); const char *gpio_get_name(enum gpio_signal signal); /** + * Determine if a GPIO is implemented. + * + * Some well known GPIO signal names may not be implemented on a particular + * board. This function can be used to determine if a GPIO is implemented. + * + * @param signal Signal to query + * @returns 0 if the GPIO is not implemented, 1 if it is. + */ +int gpio_is_implemented(enum gpio_signal signal); + +/** * Set the flags for a signal. * * @param signal Signal to set flags for @@ -136,6 +147,14 @@ const char *gpio_get_name(enum gpio_signal signal); void gpio_set_flags(enum gpio_signal signal, int flags); /** + * Get the default flags for a signal. + * + * @param signal Signal to set flags for + * @returns The flags that were originally defined for this signal + */ +int gpio_get_default_flags(enum gpio_signal signal); + +/** * Set the value of a signal. * * @param signal Signal to set |