diff options
author | Gerrit <chrome-bot@google.com> | 2012-02-15 16:06:36 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@gerrit.golo.chromium.org> | 2012-02-15 16:06:36 -0800 |
commit | 9e50c75cdbef825696072871cb439917cf15c2c8 (patch) | |
tree | 4be883755f55812af52a3d231ec02dceea8e5881 | |
parent | 274cbf3cc0c6015b699ecca6ca9ec6281b7c4c17 (diff) | |
parent | 9a242f6840e3844d9b79630de59d8304cbc2c74d (diff) | |
download | chrome-ec-9e50c75cdbef825696072871cb439917cf15c2c8.tar.gz |
Merge "stm32l: add external interrupt support for GPIOs"
-rw-r--r-- | chip/stm32l/gpio.c | 77 | ||||
-rw-r--r-- | chip/stm32l/registers.h | 11 |
2 files changed, 87 insertions, 1 deletions
diff --git a/chip/stm32l/gpio.c b/chip/stm32l/gpio.c index 56d22abf62..f581868104 100644 --- a/chip/stm32l/gpio.c +++ b/chip/stm32l/gpio.c @@ -9,10 +9,14 @@ #include "gpio.h" #include "registers.h" #include "task.h" +#include "uart.h" +#include "util.h" /* Signal information from board.c. Must match order from enum gpio_signal. */ extern const struct gpio_info gpio_list[GPIO_COUNT]; +/* For each EXTI bit, record which GPIO entry is using it */ +static const struct gpio_info *exti_events[16]; int gpio_pre_init(void) { @@ -47,8 +51,25 @@ int gpio_pre_init(void) 0xaaaaaaaa & mask2; } } + + /* Set up interrupts if necessary */ + ASSERT(!(g->flags & GPIO_INT_LEVEL)); + if (g->flags & (GPIO_INT_RISING | GPIO_INT_BOTH)) + STM32L_EXTI_RTSR |= g->mask; + if (g->flags & (GPIO_INT_FALLING | GPIO_INT_BOTH)) + STM32L_EXTI_FTSR |= g->mask; + /* Interrupt is enabled by gpio_enable_interrupt() */ } + /* Enable IRQs now that pins are set up */ + task_enable_irq(STM32L_IRQ_EXTI0); + task_enable_irq(STM32L_IRQ_EXTI1); + task_enable_irq(STM32L_IRQ_EXTI2); + task_enable_irq(STM32L_IRQ_EXTI3); + task_enable_irq(STM32L_IRQ_EXTI4); + task_enable_irq(STM32L_IRQ_EXTI9_5); + task_enable_irq(STM32L_IRQ_EXTI15_10); + return EC_SUCCESS; } @@ -67,3 +88,59 @@ int gpio_set_level(enum gpio_signal signal, int value) return EC_SUCCESS; } + +int gpio_enable_interrupt(enum gpio_signal signal) +{ + const struct gpio_info *g = gpio_list + signal; + uint32_t bit, group, shift, bank; + + /* Fail if not implemented or no interrupt handler */ + if (!g->mask || !g->irq_handler) + return EC_ERROR_INVAL; + + bit = 31 - __builtin_clz(g->mask); + +#ifdef CONFIG_DEBUG + if (exti_events[bit]) { + uart_printf("Overriding %s with %s on EXTI%d\n", + exti_events[bit]->name, g->name, bit); + } +#endif + exti_events[bit] = g; + + group = bit / 4; + shift = (bit % 4) * 4; + bank = (g->port - STM32L_GPIOA_BASE) / 0x400; + STM32L_SYSCFG_EXTICR(group) = (STM32L_SYSCFG_EXTICR(group) & + ~(0xF << shift)) | (bank << shift); + STM32L_EXTI_IMR |= g->mask; + + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Interrupt handler */ + +static void gpio_interrupt(void) +{ + int bit; + const struct gpio_info *g; + uint32_t pending = STM32L_EXTI_PR; + + STM32L_EXTI_PR = pending; + + while (pending) { + bit = 31 - __builtin_clz(pending); + g = exti_events[bit]; + if (g && g->irq_handler) + g->irq_handler(g - gpio_list); + pending &= ~(1 << bit); + } +} +DECLARE_IRQ(STM32L_IRQ_EXTI0, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI1, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI2, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI3, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI4, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI9_5, gpio_interrupt, 1); +DECLARE_IRQ(STM32L_IRQ_EXTI15_10, gpio_interrupt, 1); diff --git a/chip/stm32l/registers.h b/chip/stm32l/registers.h index 23bad85a44..d9c24a4d6d 100644 --- a/chip/stm32l/registers.h +++ b/chip/stm32l/registers.h @@ -254,10 +254,19 @@ #define STM32L_FLASH_ACR REG32(STM32L_FLASH_REGS_BASE + 0x00) +/* --- External Interrupts --- */ +#define STM32L_EXTI_BASE 0x40010400 + +#define STM32L_EXTI_IMR REG32(STM32L_EXTI_BASE + 0x00) +#define STM32L_EXTI_EMR REG32(STM32L_EXTI_BASE + 0x04) +#define STM32L_EXTI_RTSR REG32(STM32L_EXTI_BASE + 0x08) +#define STM32L_EXTI_FTSR REG32(STM32L_EXTI_BASE + 0x0c) +#define STM32L_EXTI_SWIER REG32(STM32L_EXTI_BASE + 0x10) +#define STM32L_EXTI_PR REG32(STM32L_EXTI_BASE + 0x14) + /* --- MISC --- */ #define STM32L_RI_BASE 0x40007C04 -#define STM32L_EXTI_BASE 0x40010400 #define STM32L_ADC1_BASE 0x40012400 #define STM32L_ADC_BASE 0x40012700 #define STM32L_COMP_BASE 0x40007C00 |