diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2012-05-01 09:10:14 -0700 |
---|---|---|
committer | Vincent Palatin <vpalatin@chromium.org> | 2012-05-01 22:59:51 +0000 |
commit | 539c397fb16460561aa451d121041ed36c13a845 (patch) | |
tree | fd31a40a7e1e373262ef04d392d5742fe584ae83 /chip/stm32/gpio.c | |
parent | 285fa08d10c2e5fce6e0db6f217a83b5a42e8004 (diff) | |
download | chrome-ec-539c397fb16460561aa451d121041ed36c13a845.tar.gz |
introducing chip variant for stm32 family [1/3]
just rename STM32L to STM32.
Most of the STM32L15x code is common with STM32F1xx.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BUG=chrome-os-partner:9057
TEST=make BOARD=daisy ; make BOARD=adv ; make BOARD=discovery
Change-Id: I819eff5fcd23deff57f5f6dedcf37e6c421b96c2
Diffstat (limited to 'chip/stm32/gpio.c')
-rw-r--r-- | chip/stm32/gpio.c | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/chip/stm32/gpio.c b/chip/stm32/gpio.c new file mode 100644 index 0000000000..55eaa22171 --- /dev/null +++ b/chip/stm32/gpio.c @@ -0,0 +1,199 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* GPIO module for Chrome EC */ + +#include "board.h" +#include "console.h" +#include "gpio.h" +#include "hooks.h" +#include "registers.h" +#include "task.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_GPIO, outstr) +#define CPRINTF(format, args...) cprintf(CC_GPIO, format, ## args) + +/* 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) +{ + const struct gpio_info *g = gpio_list; + int i; + + /* Enable all GPIOs clocks + * TODO: more fine-grained enabling for power saving + */ + STM32_RCC_AHBENR |= 0x3f; + + for (i = 0; i < GPIO_COUNT; i++, g++) { + /* bitmask for registers with 2 bits per GPIO pin */ + uint32_t mask2 = (g->mask * g->mask) | (g->mask * g->mask * 2); + uint32_t val; + + val = STM32_GPIO_PUPDR_OFF(g->port) & ~mask2; + if (g->flags & GPIO_PULL_UP) /* Pull Up = 01 */ + val |= 0x55555555 & mask2; + else if (g->flags & GPIO_PULL_DOWN) /* Pull Down = 10 */ + val |= 0xaaaaaaaa & mask2; + STM32_GPIO_PUPDR_OFF(g->port) = val; + + if (g->flags & GPIO_OPEN_DRAIN) + STM32_GPIO_OTYPER_OFF(g->port) |= g->mask; + + /* + * Set pin level after port has been set up as to avoid + * potential damage, e.g. driving an open-drain output + * high before it has been configured as such. + */ + val = STM32_GPIO_MODER_OFF(g->port) & ~mask2; + if (g->flags & GPIO_OUTPUT) { /* General purpose, MODE = 01 */ + val |= 0x55555555 & mask2; + STM32_GPIO_MODER_OFF(g->port) = val; + gpio_set_level(i, g->flags & GPIO_HIGH); + } else if (g->flags & GPIO_INPUT) { /* Input, MODE=00 */ + STM32_GPIO_MODER_OFF(g->port) = val; + } + + /* Set up interrupts if necessary */ + ASSERT(!(g->flags & GPIO_INT_LEVEL)); + if (g->flags & (GPIO_INT_RISING | GPIO_INT_BOTH)) + STM32_EXTI_RTSR |= g->mask; + if (g->flags & (GPIO_INT_FALLING | GPIO_INT_BOTH)) + STM32_EXTI_FTSR |= g->mask; + /* Interrupt is enabled by gpio_enable_interrupt() */ + } + + return EC_SUCCESS; +} + + +static int gpio_init(void) +{ + /* Enable IRQs now that pins are set up */ + task_enable_irq(STM32_IRQ_EXTI0); + task_enable_irq(STM32_IRQ_EXTI1); + task_enable_irq(STM32_IRQ_EXTI2); + task_enable_irq(STM32_IRQ_EXTI3); + task_enable_irq(STM32_IRQ_EXTI4); + task_enable_irq(STM32_IRQ_EXTI9_5); + task_enable_irq(STM32_IRQ_EXTI15_10); + + return EC_SUCCESS; +} +DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT); + + +void gpio_set_alternate_function(int port, int mask, int func) +{ + int bit; + uint8_t half; + uint32_t afr; + uint32_t moder = STM32_GPIO_MODER_OFF(port); + + /* Low half of the GPIO bank */ + half = mask & 0xff; + afr = STM32_GPIO_AFRL_OFF(port); + while (half) { + bit = 31 - __builtin_clz(half); + afr &= ~(0xf << (bit * 4)); + afr |= func << (bit * 4); + moder &= ~(0x3 << (bit * 2 + 0)); + moder |= 0x2 << (bit * 2 + 0); + half &= ~(1 << bit); + } + STM32_GPIO_AFRL_OFF(port) = afr; + + /* High half of the GPIO bank */ + half = mask >> 8; + afr = STM32_GPIO_AFRH_OFF(port); + while (half) { + bit = 31 - __builtin_clz(half); + afr &= ~(0xf << (bit * 4)); + afr |= func << (bit * 4); + moder &= ~(0x3 << (bit * 2 + 16)); + moder |= 0x2 << (bit * 2 + 16); + half &= ~(1 << bit); + } + STM32_GPIO_AFRH_OFF(port) = afr; + STM32_GPIO_MODER_OFF(port) = moder; +} + + +int gpio_get_level(enum gpio_signal signal) +{ + return !!(STM32_GPIO_IDR_OFF(gpio_list[signal].port) & + gpio_list[signal].mask); +} + + +int gpio_set_level(enum gpio_signal signal, int value) +{ + STM32_GPIO_BSRR_OFF(gpio_list[signal].port) = + gpio_list[signal].mask << (value ? 0 : 16); + + 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]) { + CPRINTF("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 - STM32_GPIOA_BASE) / 0x400; + STM32_SYSCFG_EXTICR(group) = (STM32_SYSCFG_EXTICR(group) & + ~(0xF << shift)) | (bank << shift); + STM32_EXTI_IMR |= g->mask; + + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Interrupt handler */ + +static void gpio_interrupt(void) +{ + int bit; + const struct gpio_info *g; + uint32_t pending = STM32_EXTI_PR; + + STM32_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(STM32_IRQ_EXTI0, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI1, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI2, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI3, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI4, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI9_5, gpio_interrupt, 1); +DECLARE_IRQ(STM32_IRQ_EXTI15_10, gpio_interrupt, 1); |