summaryrefslogtreecommitdiff
path: root/chip/stm32/gpio.c
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-05-01 09:10:14 -0700
committerVincent Palatin <vpalatin@chromium.org>2012-05-01 22:59:51 +0000
commit539c397fb16460561aa451d121041ed36c13a845 (patch)
treefd31a40a7e1e373262ef04d392d5742fe584ae83 /chip/stm32/gpio.c
parent285fa08d10c2e5fce6e0db6f217a83b5a42e8004 (diff)
downloadchrome-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.c199
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);