diff options
-rw-r--r-- | common/ioexpander.c | 49 | ||||
-rw-r--r-- | include/gpio.wrap | 5 | ||||
-rw-r--r-- | include/gpio_list.h | 34 | ||||
-rw-r--r-- | include/gpio_signal.h | 1 | ||||
-rw-r--r-- | include/ioexpander.h | 20 |
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 |