diff options
Diffstat (limited to 'chip/stm32/keyboard_raw.c')
-rw-r--r-- | chip/stm32/keyboard_raw.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/chip/stm32/keyboard_raw.c b/chip/stm32/keyboard_raw.c new file mode 100644 index 0000000000..e6a3dc65eb --- /dev/null +++ b/chip/stm32/keyboard_raw.c @@ -0,0 +1,135 @@ +/* Copyright (c) 2013 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. + * + * Raw keyboard I/O layer for STM32 + * + * To make this code portable, we rely heavily on looping over the keyboard + * input and output entries in the board's gpio_list[]. Each set of inputs or + * outputs must be listed in consecutive, increasing order so that scan loops + * can iterate beginning at KB_IN00 or KB_OUT00 for however many GPIOs are + * utilized (KB_INPUTS or KB_OUTPUTS). + */ + +#include "gpio.h" +#include "keyboard_raw.h" +#include "keyboard_scan.h" +#include "registers.h" +#include "task.h" +#include "util.h" + +/* Mask of external interrupts on input lines */ +static unsigned int irq_mask; + +static const uint32_t kb_out_ports[] = { KB_OUT_PORT_LIST }; + +static void set_irq_mask(void) +{ + int i; + + for (i = GPIO_KB_IN00; i < GPIO_KB_IN00 + KB_INPUTS; i++) + irq_mask |= gpio_list[i].mask; +} + +void keyboard_raw_init(void) +{ + /* Determine EXTI_PR mask to use for the board */ + set_irq_mask(); + + /* Ensure interrupts are disabled in EXTI_PR */ + keyboard_raw_enable_interrupt(0); +} + +void keyboard_raw_task_start(void) +{ + /* Enable interrupts for keyboard matrix inputs */ + gpio_enable_interrupt(GPIO_KB_IN00); + gpio_enable_interrupt(GPIO_KB_IN01); + gpio_enable_interrupt(GPIO_KB_IN02); + gpio_enable_interrupt(GPIO_KB_IN03); + gpio_enable_interrupt(GPIO_KB_IN04); + gpio_enable_interrupt(GPIO_KB_IN05); + gpio_enable_interrupt(GPIO_KB_IN06); + gpio_enable_interrupt(GPIO_KB_IN07); +} + +void keyboard_raw_drive_column(int out) +{ + int i, done = 0; + + for (i = 0; i < ARRAY_SIZE(kb_out_ports); i++) { + uint32_t bsrr = 0; + int j; + + for (j = GPIO_KB_OUT00; j <= GPIO_KB_OUT12; j++) { + if (gpio_list[j].port != kb_out_ports[i]) + continue; + + if (out == KEYBOARD_COLUMN_ALL) { + /* drive low (clear bit) */ + bsrr |= gpio_list[j].mask << 16; + } else if (out == KEYBOARD_COLUMN_NONE) { + /* put output in hi-Z state (set bit) */ + bsrr |= gpio_list[j].mask; + } else if (j - GPIO_KB_OUT00 == out) { + /* + * Drive specified output low, others => hi-Z. + * + * To avoid conflict, tri-state all outputs + * first, then assert specified output. + */ + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); + bsrr |= gpio_list[j].mask << 16; + done = 1; + break; + } + } + + if (bsrr) + STM32_GPIO_BSRR_OFF(kb_out_ports[i]) = bsrr; + + if (done) + break; + } +} + +int keyboard_raw_read_rows(void) +{ + int i; + unsigned int port, prev_port = 0; + int state = 0; + uint16_t port_val = 0; + + for (i = 0; i < KB_INPUTS; i++) { + port = gpio_list[GPIO_KB_IN00 + i].port; + if (port != prev_port) { + port_val = STM32_GPIO_IDR_OFF(port); + prev_port = port; + } + + if (port_val & gpio_list[GPIO_KB_IN00 + i].mask) + state |= 1 << i; + } + + /* Invert it so 0=not pressed, 1=pressed */ + return state ^ 0xff; +} + +void keyboard_raw_enable_interrupt(int enable) +{ + if (enable) { + /* + * Assert all outputs would trigger un-wanted interrupts. + * Clear them before enable interrupt. + */ + STM32_EXTI_PR |= irq_mask; + STM32_EXTI_IMR |= irq_mask; /* 1: unmask interrupt */ + } else { + STM32_EXTI_IMR &= ~irq_mask; /* 0: mask interrupts */ + } +} + +void keyboard_raw_gpio_interrupt(enum gpio_signal signal) +{ + task_wake(TASK_ID_KEYSCAN); +} |