diff options
author | Andrew McRae <amcrae@google.com> | 2022-01-22 14:56:53 +1100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-01-24 22:50:10 +0000 |
commit | be3e69c255fc1070634e165fad5b404d8817dde7 (patch) | |
tree | bd5954c576537e62675c3e647449e5d0dca1fc9a | |
parent | 10486bc73efbf06585f91cdc99a2f9c9070ad980 (diff) | |
download | chrome-ec-be3e69c255fc1070634e165fad5b404d8817dde7.tar.gz |
zephyr: Relocate GPIO interrupt handling to separate file
Move GPIO interrupt handling to separate file from gpio.c
BUG=b:214608987
TEST=zmake testall
BRANCH=none
Signed-off-by: Andrew McRae <amcrae@google.com>
Change-Id: Ibb1ea36da218ecd8f75a1e48e650f79adc259049
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3406472
Reviewed-by: Keith Short <keithshort@chromium.org>
-rw-r--r-- | zephyr/shim/include/gpio/gpio.h | 14 | ||||
-rw-r--r-- | zephyr/shim/src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | zephyr/shim/src/gpio.c | 192 | ||||
-rw-r--r-- | zephyr/shim/src/gpio_int.c | 203 |
4 files changed, 232 insertions, 178 deletions
diff --git a/zephyr/shim/include/gpio/gpio.h b/zephyr/shim/include/gpio/gpio.h index dabf1d375e..9b3ff14c37 100644 --- a/zephyr/shim/include/gpio/gpio.h +++ b/zephyr/shim/include/gpio/gpio.h @@ -48,6 +48,20 @@ struct unused_pin_config { */ int gpio_config_unused_pins(void) __attribute__((weak)); +/** + * @brief Obtain the pin number of the GPIO + * + * @return pin number of GPIO + */ +int gpio_get_pin(enum gpio_signal signal); + +/** + * @brief Obtain the Zephyr device of the GPIO + * + * @return device of the GPIO + */ +const struct device *gpio_get_dev(enum gpio_signal signal); + #if DT_NODE_EXISTS(DT_PATH(unused_pins)) /** * @brief Get a node from path '/unused-pins' which has a prop 'unused-gpios'. diff --git a/zephyr/shim/src/CMakeLists.txt b/zephyr/shim/src/CMakeLists.txt index 5347d1c41f..90b2570e7c 100644 --- a/zephyr/shim/src/CMakeLists.txt +++ b/zephyr/shim/src/CMakeLists.txt @@ -6,6 +6,7 @@ zephyr_library_sources(console.c) zephyr_library_sources(crc.c) zephyr_library_sources(gpio.c) zephyr_library_sources(gpio_id.c) +zephyr_library_sources(gpio_int.c) zephyr_library_sources(power.c) if (DEFINED CONFIG_ARCH_POSIX) diff --git a/zephyr/shim/src/gpio.c b/zephyr/shim/src/gpio.c index 506e51b3d5..99c7d819a9 100644 --- a/zephyr/shim/src/gpio.c +++ b/zephyr/shim/src/gpio.c @@ -46,118 +46,6 @@ static const struct gpio_config configs[] = { #endif }; -/* Maps platform/ec gpio callback information */ -struct gpio_signal_callback { - /* The platform/ec gpio_signal */ - const enum gpio_signal signal; - /* IRQ handler from platform/ec code */ - void (*const irq_handler)(enum gpio_signal signal); - /* Interrupt-related gpio flags */ - const gpio_flags_t flags; -}; - -/* - * Each zephyr project should define EC_CROS_GPIO_INTERRUPTS in their gpio_map.h - * file if there are any interrupts that should be registered. The - * corresponding handler will be declared here, which will prevent - * needing to include headers with complex dependencies in gpio_map.h. - * - * EC_CROS_GPIO_INTERRUPTS is a space-separated list of GPIO_INT items. - */ - -/* - * Validate interrupt flags are valid for the Zephyr GPIO driver. - */ -#define GPIO_INT(sig, f, cb) \ - BUILD_ASSERT(VALID_GPIO_INTERRUPT_FLAG(f), \ - STRINGIFY(sig) " is not using Zephyr interrupt flags"); -#ifdef EC_CROS_GPIO_INTERRUPTS -EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - -/* - * Create unique enum values for each GPIO_INT entry, which also sets - * the ZEPHYR_GPIO_INT_COUNT value. - */ -#define ZEPHYR_GPIO_INT_ID(sig) INT_##sig -#define GPIO_INT(sig, f, cb) ZEPHYR_GPIO_INT_ID(sig), -enum zephyr_gpio_int_id { -#ifdef EC_CROS_GPIO_INTERRUPTS - EC_CROS_GPIO_INTERRUPTS -#endif - ZEPHYR_GPIO_INT_COUNT, -}; -#undef GPIO_INT - -/* Create prototypes for each GPIO IRQ handler */ -#define GPIO_INT(sig, f, cb) void cb(enum gpio_signal signal); -#ifdef EC_CROS_GPIO_INTERRUPTS -EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - -/* - * The Zephyr gpio_callback data needs to be updated at runtime, so allocate - * into uninitialized data (BSS). The constant data pulled from - * EC_CROS_GPIO_INTERRUPTS is stored separately in the gpio_interrupts[] array. - */ -static struct gpio_callback zephyr_gpio_callbacks[ZEPHYR_GPIO_INT_COUNT]; - -#define ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb) \ - (int)(((int)(cb) - (int)&zephyr_gpio_callbacks) / \ - sizeof(struct gpio_callback)) - -#define GPIO_INT(sig, f, cb) \ - { \ - .signal = sig, \ - .flags = f, \ - .irq_handler = cb, \ - }, -const static struct gpio_signal_callback - gpio_interrupts[ZEPHYR_GPIO_INT_COUNT] = { -#ifdef EC_CROS_GPIO_INTERRUPTS - EC_CROS_GPIO_INTERRUPTS -#endif -#undef GPIO_INT - }; - -/* The single zephyr gpio handler that routes to appropriate platform/ec cb */ -static void gpio_handler_shim(const struct device *port, - struct gpio_callback *cb, gpio_port_pins_t pins) -{ - int callback_index = ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb); - const struct gpio_signal_callback *const gpio = - &gpio_interrupts[callback_index]; - - /* Call the platform/ec gpio interrupt handler */ - gpio->irq_handler(gpio->signal); -} - -/** - * get_interrupt_from_signal() - Translate a gpio_signal to the - * corresponding gpio_signal_callback - * - * @signal The signal to convert. - * - * Return: A pointer to the corresponding entry in gpio_interrupts, or - * NULL if one does not exist. - */ -const static struct gpio_signal_callback * -get_interrupt_from_signal(enum gpio_signal signal) -{ - if (!gpio_is_implemented(signal)) - return NULL; - - for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); i++) { - if (gpio_interrupts[i].signal == signal) - return &gpio_interrupts[i]; - } - - LOG_ERR("No interrupt defined for GPIO %s", configs[signal].name); - return NULL; -} - int gpio_is_implemented(enum gpio_signal signal) { return signal >= 0 && signal < ARRAY_SIZE(configs); @@ -178,6 +66,20 @@ int gpio_get_level(enum gpio_signal signal) return l; } +int gpio_get_pin(enum gpio_signal signal) +{ + if (!gpio_is_implemented(signal)) + return 0; + return configs[signal].pin; +} + +const struct device *gpio_get_dev(enum gpio_signal signal) +{ + if (!gpio_is_implemented(signal)) + return 0; + return configs[signal].dev; +} + int gpio_get_ternary(enum gpio_signal signal) { int pd, pu; @@ -363,28 +265,6 @@ static int init_gpios(const struct device *unused) } } - /* - * Loop through all interrupt pins and set their callback. - */ - for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); ++i) { - const enum gpio_signal signal = gpio_interrupts[i].signal; - int rv; - - if (signal == GPIO_UNIMPLEMENTED) - continue; - - gpio_init_callback(&zephyr_gpio_callbacks[i], gpio_handler_shim, - BIT(configs[signal].pin)); - rv = gpio_add_callback(configs[signal].dev, - &zephyr_gpio_callbacks[i]); - - if (rv < 0) { - LOG_ERR("Callback reg failed %s (%d)", - configs[signal].name, rv); - continue; - } - } - /* Configure unused pins in chip driver for better power consumption */ if (gpio_config_unused_pins) { int rv; @@ -402,50 +282,6 @@ static int init_gpios(const struct device *unused) #endif SYS_INIT(init_gpios, POST_KERNEL, CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY); -int gpio_enable_interrupt(enum gpio_signal signal) -{ - int rv; - const struct gpio_signal_callback *interrupt; - - interrupt = get_interrupt_from_signal(signal); - - if (!interrupt) - return -1; - - /* - * Config interrupt flags (e.g. INT_EDGE_BOTH) & enable interrupt - * together. - */ - rv = gpio_pin_interrupt_configure(configs[signal].dev, - configs[signal].pin, - (interrupt->flags | GPIO_INT_ENABLE) & - ~GPIO_INT_DISABLE); - if (rv < 0) { - LOG_ERR("Failed to enable interrupt on %s (%d)", - configs[signal].name, rv); - } - - return rv; -} - -int gpio_disable_interrupt(enum gpio_signal signal) -{ - int rv; - - if (!gpio_is_implemented(signal)) - return -1; - - rv = gpio_pin_interrupt_configure(configs[signal].dev, - configs[signal].pin, - GPIO_INT_DISABLE); - if (rv < 0) { - LOG_ERR("Failed to disable interrupt on %s (%d)", - configs[signal].name, rv); - } - - return rv; -} - void gpio_reset(enum gpio_signal signal) { if (!gpio_is_implemented(signal)) diff --git a/zephyr/shim/src/gpio_int.c b/zephyr/shim/src/gpio_int.c new file mode 100644 index 0000000000..abbef044b5 --- /dev/null +++ b/zephyr/shim/src/gpio_int.c @@ -0,0 +1,203 @@ +/* Copyright 2022 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. + */ + +#include <device.h> +#include <init.h> +#include <kernel.h> +#include <logging/log.h> + +#include "gpio.h" +#include "gpio/gpio.h" +#include "cros_version.h" + +LOG_MODULE_REGISTER(gpio_int, LOG_LEVEL_ERR); + +/* Maps platform/ec gpio callback information */ +struct gpio_signal_callback { + /* The platform/ec gpio_signal */ + const enum gpio_signal signal; + /* IRQ handler from platform/ec code */ + void (*const irq_handler)(enum gpio_signal signal); + /* Interrupt-related gpio flags */ + const gpio_flags_t flags; +}; + +/* + * Each zephyr project should define EC_CROS_GPIO_INTERRUPTS in their gpio_map.h + * file if there are any interrupts that should be registered. The + * corresponding handler will be declared here, which will prevent + * needing to include headers with complex dependencies in gpio_map.h. + * + * EC_CROS_GPIO_INTERRUPTS is a space-separated list of GPIO_INT items. + */ + +/* + * Validate interrupt flags are valid for the Zephyr GPIO driver. + */ +#define GPIO_INT(sig, f, cb) \ + BUILD_ASSERT(VALID_GPIO_INTERRUPT_FLAG(f), \ + STRINGIFY(sig) " is not using Zephyr interrupt flags"); +#ifdef EC_CROS_GPIO_INTERRUPTS + EC_CROS_GPIO_INTERRUPTS +#endif +#undef GPIO_INT + +/* + * Create unique enum values for each GPIO_INT entry, which also sets + * the ZEPHYR_GPIO_INT_COUNT value. + */ +#define ZEPHYR_GPIO_INT_ID(sig) INT_##sig +#define GPIO_INT(sig, f, cb) ZEPHYR_GPIO_INT_ID(sig), +enum zephyr_gpio_int_id { +#ifdef EC_CROS_GPIO_INTERRUPTS + EC_CROS_GPIO_INTERRUPTS +#endif + ZEPHYR_GPIO_INT_COUNT, +}; +#undef GPIO_INT + +/* Create prototypes for each GPIO IRQ handler */ +#define GPIO_INT(sig, f, cb) void cb(enum gpio_signal signal); +#ifdef EC_CROS_GPIO_INTERRUPTS +EC_CROS_GPIO_INTERRUPTS +#endif +#undef GPIO_INT + +/* + * The Zephyr gpio_callback data needs to be updated at runtime, so allocate + * into uninitialized data (BSS). The constant data pulled from + * EC_CROS_GPIO_INTERRUPTS is stored separately in the gpio_interrupts[] array. + */ +static struct gpio_callback zephyr_gpio_callbacks[ZEPHYR_GPIO_INT_COUNT]; + +#define ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb) \ + (int)(((int)(cb) - (int)&zephyr_gpio_callbacks) / \ + sizeof(struct gpio_callback)) + +#define GPIO_INT(sig, f, cb) \ + { \ + .signal = sig, \ + .flags = f, \ + .irq_handler = cb, \ + }, +const static struct gpio_signal_callback + gpio_interrupts[ZEPHYR_GPIO_INT_COUNT] = { +#ifdef EC_CROS_GPIO_INTERRUPTS + EC_CROS_GPIO_INTERRUPTS +#endif +#undef GPIO_INT + }; + +/* The single zephyr gpio handler that routes to appropriate platform/ec cb */ +static void gpio_handler_shim(const struct device *port, + struct gpio_callback *cb, gpio_port_pins_t pins) +{ + int callback_index = ZEPHYR_GPIO_CALLBACK_TO_INDEX(cb); + const struct gpio_signal_callback *const gpio = + &gpio_interrupts[callback_index]; + + /* Call the platform/ec gpio interrupt handler */ + gpio->irq_handler(gpio->signal); +} + +/** + * get_interrupt_from_signal() - Translate a gpio_signal to the + * corresponding gpio_signal_callback + * + * @signal The signal to convert. + * + * Return: A pointer to the corresponding entry in gpio_interrupts, or + * NULL if one does not exist. + */ +const static struct gpio_signal_callback * +get_interrupt_from_signal(enum gpio_signal signal) +{ + if (!gpio_is_implemented(signal)) + return NULL; + + for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); i++) { + if (gpio_interrupts[i].signal == signal) + return &gpio_interrupts[i]; + } + + LOG_ERR("No interrupt defined for GPIO %s", gpio_get_name(signal)); + return NULL; +} + +int gpio_enable_interrupt(enum gpio_signal signal) +{ + int rv; + const struct gpio_signal_callback *interrupt; + + interrupt = get_interrupt_from_signal(signal); + + if (!interrupt) + return -1; + + /* + * Config interrupt flags (e.g. INT_EDGE_BOTH) & enable interrupt + * together. + */ + rv = gpio_pin_interrupt_configure(gpio_get_dev(signal), + gpio_get_pin(signal), + (interrupt->flags | GPIO_INT_ENABLE) & + ~GPIO_INT_DISABLE); + if (rv < 0) { + LOG_ERR("Failed to enable interrupt on %s (%d)", + gpio_get_name(signal), rv); + } + + return rv; +} + +int gpio_disable_interrupt(enum gpio_signal signal) +{ + int rv; + + if (!gpio_is_implemented(signal)) + return -1; + + rv = gpio_pin_interrupt_configure(gpio_get_dev(signal), + gpio_get_pin(signal), + GPIO_INT_DISABLE); + if (rv < 0) { + LOG_ERR("Failed to disable interrupt on %s (%d)", + gpio_get_name(signal), rv); + } + + return rv; +} + +static int init_gpio_ints(const struct device *unused) +{ + ARG_UNUSED(unused); + + /* + * Loop through all interrupt pins and set their callback. + */ + for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); ++i) { + const enum gpio_signal signal = gpio_interrupts[i].signal; + int rv; + + if (signal == GPIO_UNIMPLEMENTED) + continue; + + gpio_init_callback(&zephyr_gpio_callbacks[i], gpio_handler_shim, + BIT(gpio_get_pin(signal))); + rv = gpio_add_callback(gpio_get_dev(signal), + &zephyr_gpio_callbacks[i]); + + if (rv < 0) { + LOG_ERR("Callback reg failed %s (%d)", + gpio_get_name(signal), rv); + continue; + } + } + return 0; +} +#if CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY <= CONFIG_KERNEL_INIT_PRIORITY_DEFAULT +#error "GPIO interrupts must initialize after the kernel default initialization" +#endif +SYS_INIT(init_gpio_ints, POST_KERNEL, CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY); |