summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHLin <CHLIN56@nuvoton.com>2019-08-05 15:02:19 +0800
committerCommit Bot <commit-bot@chromium.org>2019-08-20 18:12:14 +0000
commit5040fdcc897188ad674b0503bf31d5c26f9f76d4 (patch)
tree646e5033fcf570b1a4d3267280ba2ee31813e747
parent8aaeb9fd05ab185a7807f3650e491d2c3042637a (diff)
downloadchrome-ec-5040fdcc897188ad674b0503bf31d5c26f9f76d4.tar.gz
IO Expander: add the interrupt support to IOEX framework
This CL creates interfaces which bring the IOEX framework to support interrupt feature. To declare an IOEX IO which supports the interrupt function, file its declaration in gpio.inc with the format: IOEX_INT(name, expin, flags, signal) Note: like GPIO, all IOEX IOs with interrupt handlers must be declared at the top of the IOEX's declaration in the gpio.inc The following two APIs are added to enable/disable each IOEX IO's interrupt function: 1. ioex_enable_interrupt 2. ioex_disable_interrupt BRANCH=none BUG=none TEST=No error for "make buildall" TEST=Apply this and related CLs, manually test each IO pins; make sure each pin's interrupt handler is correctly executed. Change-Id: Icbf54c09120e37b68c647c884cd6aa28d9313167 Signed-off-by: CHLin <CHLIN56@nuvoton.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1734947 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org> Tested-by: CH Lin <chlin56@nuvoton.com> Commit-Queue: Edward Hill <ecgh@chromium.org>
-rw-r--r--common/ioexpander.c49
-rw-r--r--include/gpio.wrap5
-rw-r--r--include/gpio_list.h34
-rw-r--r--include/gpio_signal.h1
-rw-r--r--include/ioexpander.h20
5 files changed, 107 insertions, 2 deletions
diff --git a/common/ioexpander.c b/common/ioexpander.c
index 8e00f9337a..796673a668 100644
--- a/common/ioexpander.c
+++ b/common/ioexpander.c
@@ -29,6 +29,55 @@ static int last_val_changed(int i, int v)
}
}
+static int ioex_is_valid_interrupt_signal(enum ioex_signal signal)
+{
+ const struct ioexpander_drv *drv;
+ const struct ioex_info *g = ioex_list + signal;
+
+ /* Fail if no interrupt handler */
+ if (signal >= ioex_ih_count)
+ return EC_ERROR_PARAM1;
+
+ drv = ioex_config[g->ioex].drv;
+ /*
+ * Not every IOEX chip can support interrupt, check it before enabling
+ * the interrupt function
+ */
+ if (drv->enable_interrupt == NULL) {
+ CPRINTS("IOEX chip port %d doesn't support INT", g->ioex);
+ return EC_ERROR_UNIMPLEMENTED;
+ }
+
+ return EC_SUCCESS;
+}
+int ioex_enable_interrupt(enum ioex_signal signal)
+{
+ int rv;
+ const struct ioex_info *g = ioex_list + signal;
+ const struct ioexpander_drv *drv;
+
+ rv = ioex_is_valid_interrupt_signal(signal);
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ drv = ioex_config[g->ioex].drv;
+ return drv->enable_interrupt(g->ioex, g->port, g->mask, 1);
+}
+
+int ioex_disable_interrupt(enum ioex_signal signal)
+{
+ int rv;
+ const struct ioexpander_drv *drv;
+ const struct ioex_info *g = ioex_list + signal;
+
+ rv = ioex_is_valid_interrupt_signal(signal);
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ drv = ioex_config[g->ioex].drv;
+ return drv->enable_interrupt(g->ioex, g->port, g->mask, 0);
+}
+
int ioex_get_flags_by_mask(int ioex, int port, int mask, int *flags)
{
return ioex_config[ioex].drv->get_flags_by_mask(ioex, port, mask,
diff --git a/include/gpio.wrap b/include/gpio.wrap
index b68621d49c..bc0b47f989 100644
--- a/include/gpio.wrap
+++ b/include/gpio.wrap
@@ -136,6 +136,10 @@
#define IOEX(name, expin, flags)
#endif
+#ifndef IOEX_INT
+#define IOEX_INT(name, expin, flags, signal)
+#endif
+
#include "gpio.inc"
/*
@@ -155,3 +159,4 @@
#undef UNIMPLEMENTED_RW
#undef IOEX
+#undef IOEX_INT
diff --git a/include/gpio_list.h b/include/gpio_list.h
index 4fed0d60d6..180841bb9b 100644
--- a/include/gpio_list.h
+++ b/include/gpio_list.h
@@ -54,6 +54,8 @@ const int gpio_ih_count = ARRAY_SIZE(gpio_irq_handlers);
#include "gpio.wrap"
#include "ioexpander.h"
+#define IOEX_EXPIN(ioex, port, index) (ioex), (port), BIT(index)
+
/*
* Define the IO expander IO in gpio.inc by the format:
* IOEX(name, EXPIN(ioex_port, port, offset), flags)
@@ -66,9 +68,21 @@ const int gpio_ih_count = ARRAY_SIZE(gpio_irq_handlers);
* - flags: the same as the flags of GPIO.
*
*/
-#define IOEX_EXPIN(ioex, port, index) (ioex), (port), BIT(index)
-
#define IOEX(name, expin, flags) {#name, IOEX_##expin, flags},
+/*
+ * Define the IO expander IO which supports interrupt in gpio.inc by
+ * the format:
+ * IOEX_INT(name, EXPIN(ioex_port, port, offset), flags, handler)
+ * - name: the name of this IO pin
+ * - EXPIN(ioex, port, offset)
+ * - ioex: the IO expander port (defined in board.c) this IO
+ * pin belongs to.
+ * - port: the port number in the IO expander chip.
+ * - offset: the bit offset in the port above.
+ * - flags: the same as the flags of GPIO.
+ * - handler: the IOEX IO's interrupt handler.
+ */
+#define IOEX_INT(name, expin, flags, handler) IOEX(name, expin, flags)
/* IO expander signal list. */
const struct ioex_info ioex_list[] = {
@@ -76,7 +90,23 @@ const struct ioex_info ioex_list[] = {
};
BUILD_ASSERT(ARRAY_SIZE(ioex_list) == IOEX_COUNT);
+/* IO Expander Interrupt Handlers */
+#define IOEX_INT(name, expin, flags, handler) handler,
+void (* const ioex_irq_handlers[])(enum ioex_signal signal) = {
+ #include "gpio.wrap"
+};
+const int ioex_ih_count = ARRAY_SIZE(ioex_irq_handlers);
+/*
+ * All IOEX IOs with interrupt handlers must be declared at the top of the
+ * IOEX's declaration in the gpio.inc
+ * file.
+ */
+#define IOEX_INT(name, expin, flags, handler) \
+ BUILD_ASSERT(IOEX_##name < ARRAY_SIZE(ioex_irq_handlers));
+#include "gpio.wrap"
+
#define IOEX(name, expin, flags) expin
+#define IOEX_INT(name, expin, flags, handler) expin
/* The compiler will complain if we use the same name twice or the controller
* number declared is greater or equal to CONFIG_IO_EXPANDER_PORT_COUNT.
diff --git a/include/gpio_signal.h b/include/gpio_signal.h
index da34f07b33..e863b7c415 100644
--- a/include/gpio_signal.h
+++ b/include/gpio_signal.h
@@ -16,6 +16,7 @@ enum gpio_signal {
};
#define IOEX(name, expin, flags) IOEX_##name,
+#define IOEX_INT(name, expin, flags, signal) IOEX_##name,
enum ioex_signal {
#include "gpio.wrap"
diff --git a/include/ioexpander.h b/include/ioexpander.h
index 2a31eb6aaa..e8f76d9fbc 100644
--- a/include/ioexpander.h
+++ b/include/ioexpander.h
@@ -27,6 +27,8 @@ struct ioex_info {
/* Signal information from board.c. Must match order from enum ioex_signal. */
extern const struct ioex_info ioex_list[];
+extern void (* const ioex_irq_handlers[])(enum ioex_signal signal);
+extern const int ioex_ih_count;
struct ioexpander_drv {
/* Initialize IO expander chip/driver */
@@ -39,6 +41,8 @@ struct ioexpander_drv {
int (*get_flags_by_mask)(int ioex, int port, int mask, int *flags);
/* Set flags for the IOEX pin */
int (*set_flags_by_mask)(int ioex, int port, int mask, int flags);
+ /* Enable/disable interrupt for the IOEX pin */
+ int (*enable_interrupt)(int ioex, int port, int mask, int enable);
};
struct ioexpander_config_t {
@@ -61,6 +65,22 @@ struct ioexpander_config_t {
extern struct ioexpander_config_t ioex_config[];
/*
+ * Enable the interrupt for the IOEX signal
+ *
+ * @param signal IOEX signal to enable the interrupt
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int ioex_enable_interrupt(enum ioex_signal signal);
+
+/*
+ * Disable the interrupt for the IOEX signal
+ *
+ * @param signal IOEX signal to disable the interrupt
+ * @return EC_SUCCESS if successful, non-zero if error.
+ */
+int ioex_disable_interrupt(enum ioex_signal signal);
+
+/*
* Get flags for the IOEX pin by mask
*
* @param ioex IO expander chip's port number