diff options
author | Jett Rink <jettrink@chromium.org> | 2020-10-23 10:02:32 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-10-23 21:10:41 +0000 |
commit | 3702a6b09d7778b833cc29a8383f2002bbaee94c (patch) | |
tree | 2ccf965041bab70ee32afcfe5a91c1806caee8bd | |
parent | 8c8078f69339a2fbb15d9bc11f72ea459b18e021 (diff) | |
download | chrome-ec-3702a6b09d7778b833cc29a8383f2002bbaee94c.tar.gz |
zephyr: add gpio interrupts to shim
Allow each zephyr project to define the EC_CROS_GPIO_INTERRUPTS item in
their gpio_map.h file to register existing platform/ec gpio irq
handlers.
Unfortunately this cannot go in the device tree file since the device
tree does not support function pointers as a data type.
BRANCH=none
BUG=b:169935802
TEST=hooked up power button GPIO to platform/ec-based gpio irq
Signed-off-by: Jett Rink <jettrink@chromium.org>
Change-Id: I65d03fed413b270aeae502ad4267b1091582bd91
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2494725
Reviewed-by: Jack Rosenthal <jrosenth@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r-- | zephyr/shim/src/gpio.c | 80 |
1 files changed, 78 insertions, 2 deletions
diff --git a/zephyr/shim/src/gpio.c b/zephyr/shim/src/gpio.c index 642210710f..181b9d71a8 100644 --- a/zephyr/shim/src/gpio.c +++ b/zephyr/shim/src/gpio.c @@ -52,6 +52,46 @@ static struct gpio_data data[] = { #endif }; +/* Maps platform/ec gpio callbacks to zephyr gpio callbacks */ +struct gpio_signal_callback { + /* The platform/ec gpio_signal */ + const enum gpio_signal signal; + /* Zephyr callback */ + struct gpio_callback callback; + /* IRQ handler from platform/ec code */ + void (*const irq_handler)(enum gpio_signal signal); + /* Interrupt-related gpio flags */ + const gpio_flags_t flags; +}; + +/* 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) +{ + const struct gpio_signal_callback *const gpio = + CONTAINER_OF(cb, struct gpio_signal_callback, callback); + + /* Call the platform/ec gpio interrupt handler */ + gpio->irq_handler(gpio->signal); +} + +/* + * Each zephyr project should define EC_CROS_GPIO_INTERRUPTS in their gpio_map.h + * file if there are any interrupts that should be registered. + * + * EC_CROS_GPIO_INTERRUPTS is a space-separated list of GPIO_INT items. + */ +#define GPIO_INT(sig, f, cb) \ + { \ + .signal = sig, \ + .flags = f, \ + .irq_handler = cb, \ + }, +struct gpio_signal_callback gpio_interrupts[] = { +#ifdef EC_CROS_GPIO_INTERRUPTS + EC_CROS_GPIO_INTERRUPTS +#endif +}; int gpio_is_implemented(enum gpio_signal signal) { @@ -116,20 +156,56 @@ static int init_gpios(const struct device *unused) { ARG_UNUSED(unused); + /* Loop through all GPIOs in device tree to set initial configuration */ for (size_t i = 0; i < ARRAY_SIZE(configs); ++i) { data[i].dev = device_get_binding(configs[i].dev_name); + int rv; if (data[i].dev == NULL) { LOG_ERR("Not found (%s)", configs[i].name); } - const int rv = gpio_pin_configure(data[i].dev, configs[i].pin, - configs[i].init_flags); + rv = gpio_pin_configure(data[i].dev, configs[i].pin, + configs[i].init_flags); if (rv < 0) { LOG_ERR("Config failed %s (%d)", configs[i].name, rv); } } + + /* + * Loop through all interrupt pins and set their callback and interrupt- + * related gpio flags. + */ + for (size_t i = 0; i < ARRAY_SIZE(gpio_interrupts); ++i) { + const enum gpio_signal signal = gpio_interrupts[i].signal; + int rv; + + gpio_init_callback(&gpio_interrupts[i].callback, + gpio_handler_shim, BIT(configs[signal].pin)); + rv = gpio_add_callback(data[signal].dev, + &gpio_interrupts[i].callback); + + if (rv < 0) { + LOG_ERR("Callback reg failed %s (%d)", + configs[signal].name, rv); + continue; + } + + /* + * Reconfigure the GPIO pin with the original device tree + * flags (e.g. INPUT, PULL-UP) combined with the interrupts + * flags (e.g. INT_EDGE_BOTH). + */ + rv = gpio_pin_configure(data[signal].dev, configs[signal].pin, + (configs[signal].init_flags | + gpio_interrupts[i].flags)); + if (rv < 0) { + LOG_ERR("Int config failed %s (%d)", + configs[signal].name, rv); + } + } + return 0; } SYS_INIT(init_gpios, PRE_KERNEL_1, 50); |