summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew McRae <amcrae@google.com>2022-01-22 14:56:53 +1100
committerCommit Bot <commit-bot@chromium.org>2022-01-24 22:50:10 +0000
commitbe3e69c255fc1070634e165fad5b404d8817dde7 (patch)
treebd5954c576537e62675c3e647449e5d0dca1fc9a
parent10486bc73efbf06585f91cdc99a2f9c9070ad980 (diff)
downloadchrome-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.h14
-rw-r--r--zephyr/shim/src/CMakeLists.txt1
-rw-r--r--zephyr/shim/src/gpio.c192
-rw-r--r--zephyr/shim/src/gpio_int.c203
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);