From 35805c0f419505e72857be3d933eb6ee1bdb9c9e Mon Sep 17 00:00:00 2001 From: Josh-Tsai Date: Tue, 20 Dec 2022 19:31:18 +0800 Subject: shim/src/gpio: Add save/restore GPIO controller port configure function We need to save the IO expander GPIO status before the device reset, and restore the status after the device is reset completely. create the function to save and restore the port configure BRANCH=None BUG=b:260534665 TEST=zmake build winterhold TEST=IO expander GPIOs status will not clear after tcpc reset TEST=./twister -v -i --coverage -p native_posix -p unit_testing -s external/platform/ec/zephyr/test/drivers/drivers.default Change-Id: Ic35e7e412792a56fde670de252887a9bdb557b36 Signed-off-by: Josh-Tsai Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4115054 Reviewed-by: Elthan Huang Reviewed-by: Keith Short Code-Coverage: Zoss Commit-Queue: Keith Short --- include/gpio.h | 22 ++++++++++ zephyr/shim/src/gpio.c | 40 ++++++++++++++++++ zephyr/test/drivers/default/prj.conf | 1 + zephyr/test/drivers/default/src/gpio.c | 74 ++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) diff --git a/include/gpio.h b/include/gpio.h index 2c5006a8ec..5fc0b07d66 100644 --- a/include/gpio.h +++ b/include/gpio.h @@ -401,6 +401,28 @@ void gpio_reset(enum gpio_signal signal); #ifdef CONFIG_ZEPHYR +/** + * @brief Save state of a GPIO controller port + * + * This function saves all pins current state from selected port. + * + * @param port Port to save + * @param flags Buffer to hold gpio flags + */ +int gpio_save_port_config(const struct device *port, gpio_flags_t *flags, + int buff_size); + +/** + * @brief Restore state of a GPIO controller port + * + * This function restore all pins current state from selected port. + * + * @param port Port to restore + * @param flags Buffer with gpio flags saved by ioex_save_gpio_config + */ +int gpio_restore_port_config(const struct device *port, gpio_flags_t *flags, + int buff_size); + /** * @brief Reset all the GPIOs to default state * diff --git a/zephyr/shim/src/gpio.c b/zephyr/shim/src/gpio.c index a629c77a11..1f81b6203c 100644 --- a/zephyr/shim/src/gpio.c +++ b/zephyr/shim/src/gpio.c @@ -322,6 +322,46 @@ void gpio_reset(enum gpio_signal signal) configs[signal].init_flags); } +int gpio_save_port_config(const struct device *port, gpio_flags_t *flags, + int buff_size) +{ + int state_offset = 0; + + for (size_t i = 0; i < ARRAY_SIZE(configs); ++i) { + if (state_offset >= buff_size) { + LOG_ERR("%s buffer is too small", __func__); + return EC_ERROR_UNKNOWN; + } + + if (port == configs[i].spec.port) { + gpio_pin_get_config_dt(&configs[i].spec, + &flags[state_offset++]); + } + } + + return EC_SUCCESS; +} + +int gpio_restore_port_config(const struct device *port, gpio_flags_t *flags, + int buff_size) +{ + int state_offset = 0; + + for (size_t i = 0; i < ARRAY_SIZE(configs); ++i) { + if (state_offset >= buff_size) { + LOG_ERR("%s buffer is too small", __func__); + return EC_ERROR_UNKNOWN; + } + + if (port == configs[i].spec.port) { + gpio_pin_configure_dt(&configs[i].spec, + flags[state_offset++]); + } + } + + return EC_SUCCESS; +} + void gpio_reset_port(const struct device *port) { for (size_t i = 0; i < ARRAY_SIZE(configs); ++i) { diff --git a/zephyr/test/drivers/default/prj.conf b/zephyr/test/drivers/default/prj.conf index bf94510c1d..75a0556013 100644 --- a/zephyr/test/drivers/default/prj.conf +++ b/zephyr/test/drivers/default/prj.conf @@ -10,3 +10,4 @@ CONFIG_PLATFORM_EC_VOLUME_BUTTONS=y CONFIG_TASK_HOSTCMD_THREAD_MAIN=y CONFIG_SYSTEM_FAKE=y +CONFIG_GPIO_GET_CONFIG=y \ No newline at end of file diff --git a/zephyr/test/drivers/default/src/gpio.c b/zephyr/test/drivers/default/src/gpio.c index 7304324532..e9a89d9b68 100644 --- a/zephyr/test/drivers/default/src/gpio.c +++ b/zephyr/test/drivers/default/src/gpio.c @@ -381,6 +381,80 @@ ZTEST(gpio, test_gpio_reset) flags); } +ZTEST(gpio, test_gpio_save_port_config) +{ + const struct device *port = + DEVICE_DT_GET(DT_GPIO_CTLR(DT_NODELABEL(gpio_test), gpios)); + const struct gpio_dt_spec *spec; + gpio_flags_t flags[32] = { 0 }; + gpio_flags_t zephyr_flags; + gpio_flags_t flags_at_start[GPIO_COUNT]; + int index = 0; + + /* Snapshot of GPIO flags before testing */ + for (int i = 0; i < GPIO_COUNT; i++) { + flags_at_start[i] = gpio_helper_get_flags(i); + gpio_set_flags(i, GPIO_OUTPUT); + } + + /* save the current state of the port */ + gpio_save_port_config(port, flags, sizeof(flags)); + + for (int i = 0; i < GPIO_COUNT; i++) { + spec = gpio_get_dt_spec(i); + if (spec->port == port) { + gpio_pin_get_config_dt(spec, &zephyr_flags); + zassert_equal(flags[index], zephyr_flags, + "Flags get 0x%x", flags[index]); + index++; + } + } + + for (int i = 0; i < GPIO_COUNT; ++i) { + gpio_set_flags(i, flags_at_start[i]); + } +} + +ZTEST(gpio, test_gpio_restore_port_config) +{ + const struct device *port = + DEVICE_DT_GET(DT_GPIO_CTLR(DT_NODELABEL(gpio_test), gpios)); + const struct gpio_dt_spec *spec; + gpio_flags_t flags[32] = { 0 }; + gpio_flags_t zephyr_flags; + gpio_flags_t flags_at_start[GPIO_COUNT]; + int index = 0; + + /* Snapshot of GPIO flags before testing */ + for (int i = 0; i < GPIO_COUNT; i++) { + flags_at_start[i] = gpio_helper_get_flags(i); + gpio_set_flags(i, GPIO_OUTPUT); + } + + /* save the current state of the port */ + gpio_save_port_config(port, flags, sizeof(flags)); + + /* reset the port */ + gpio_reset_port(port); + + /* restore the port config and check */ + gpio_restore_port_config(port, flags, sizeof(flags)); + + for (int i = 0; i < GPIO_COUNT; i++) { + spec = gpio_get_dt_spec(i); + if (spec->port == port) { + gpio_pin_get_config_dt(spec, &zephyr_flags); + zassert_equal(flags[index], zephyr_flags, + "Flags get 0x%x", flags[index]); + index++; + } + } + + for (int i = 0; i < GPIO_COUNT; ++i) { + gpio_set_flags(i, flags_at_start[i]); + } +} + ZTEST(gpio, test_gpio_reset_port) { const struct device *port = -- cgit v1.2.1