summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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