From 9a242f6840e3844d9b79630de59d8304cbc2c74d Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Wed, 15 Feb 2012 17:28:23 +0000 Subject: [PATCH] stm32l: add external interrupt support for GPIOs Allow to setup edge triggered interrupts on the GPIOs. Signed-off-by: Vincent Palatin BUG=None TEST=add a adhoc handler for the USER button and check its trace. Change-Id: I11a280c412c1d333bab4a74f869221edf59fcf8e --- chip/stm32l/gpio.c | 77 +++++++++++++++++++++++++++++++++++++++++ chip/stm32l/registers.h | 11 +++++- 2 files changed, 87 insertions(+), 1 deletion(-) 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