diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-03-20 13:47:35 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-03-22 11:24:28 -0700 |
commit | 743c05f01f8f2b19dbf565bee645076fff75c42d (patch) | |
tree | cbad9ab036c32b3b4d47ad2ad4ded17f18fb02b6 | |
parent | cdb08e12217367f0ac8c6ce0dc1df2e27f80563e (diff) | |
download | chrome-ec-743c05f01f8f2b19dbf565bee645076fff75c42d.tar.gz |
Add keyboard_raw interface
This is the low-level platform-dependent interface to drive keyboard
columns, read rows, and handle keyboard interrupts.
Both lm4 and stm32 had something like this before, but the interfaces
weren't fully explicit or compatible.
BUG=chrome-os-partner:18360
BRANCH=none
TEST=manual
- Build all platforms.
- Boot system and test typing on keyboard.
- Hold power+refresh+esc to test boot key detection; should go to recovery.
Change-Id: Ie3bcc1d066a4da5204f0e236daeb52c4064a6213
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/46156
-rw-r--r-- | board/daisy/board.c | 18 | ||||
-rw-r--r-- | board/mccroskey/board.c | 18 | ||||
-rw-r--r-- | board/snow/board.c | 18 | ||||
-rw-r--r-- | board/spring/board.c | 18 | ||||
-rw-r--r-- | chip/lm4/build.mk | 2 | ||||
-rw-r--r-- | chip/lm4/keyboard_raw.c | 112 | ||||
-rw-r--r-- | chip/lm4/keyboard_scan.c | 63 | ||||
-rw-r--r-- | chip/lm4/keyboard_scan_stub.c | 115 | ||||
-rw-r--r-- | chip/lm4/keyboard_scan_stub.h | 43 | ||||
-rw-r--r-- | chip/lm4/mock_keyboard_scan_stub.c | 55 | ||||
-rw-r--r-- | chip/stm32/build.mk | 2 | ||||
-rw-r--r-- | chip/stm32/keyboard_raw.c | 135 | ||||
-rw-r--r-- | chip/stm32/keyboard_scan.c | 179 | ||||
-rw-r--r-- | include/keyboard_raw.h | 74 | ||||
-rw-r--r-- | include/keyboard_scan.h | 12 |
15 files changed, 425 insertions, 439 deletions
diff --git a/board/daisy/board.c b/board/daisy/board.c index 0a7b4bf54e..7052ec68fc 100644 --- a/board/daisy/board.c +++ b/board/daisy/board.c @@ -10,7 +10,7 @@ #include "gaia_power.h" #include "gpio.h" #include "i2c.h" -#include "keyboard_scan.h" +#include "keyboard_raw.h" #include "pmu_tpschrome.h" #include "registers.h" #include "spi.h" @@ -44,21 +44,21 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"LID_OPEN", GPIO_C, (1<<13), GPIO_INT_RISING, gaia_lid_event}, {"SUSPEND_L", GPIO_A, (1<<7), GPIO_INT_BOTH, gaia_suspend_event}, {"KB_IN00", GPIO_C, (1<<8), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN01", GPIO_C, (1<<9), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN02", GPIO_C, (1<<10), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN03", GPIO_C, (1<<11), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN04", GPIO_C, (1<<12), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN05", GPIO_C, (1<<14), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN06", GPIO_C, (1<<15), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN07", GPIO_D, (1<<2), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, /* Other inputs */ {"AC_PWRBTN_L", GPIO_A, (1<<0), GPIO_INT_BOTH, NULL}, {"SPI1_NSS", GPIO_A, (1<<4), GPIO_PULL_UP, NULL}, diff --git a/board/mccroskey/board.c b/board/mccroskey/board.c index 1e4d9cfa76..ba18740b24 100644 --- a/board/mccroskey/board.c +++ b/board/mccroskey/board.c @@ -11,7 +11,7 @@ #include "gpio.h" #include "hooks.h" #include "i2c.h" -#include "keyboard_scan.h" +#include "keyboard_raw.h" #include "registers.h" #include "spi.h" #include "task.h" @@ -30,21 +30,21 @@ static void kbd_power_on(enum gpio_signal signal); const struct gpio_info gpio_list[GPIO_COUNT] = { /* Inputs with interrupt handlers are first for efficiency */ {"KB_IN00", GPIO_B, (1<<8), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN01", GPIO_B, (1<<9), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN02", GPIO_B, (1<<10), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN03", GPIO_B, (1<<11), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN04", GPIO_B, (1<<12), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN05", GPIO_B, (1<<13), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN06", GPIO_B, (1<<14), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN07", GPIO_B, (1<<15), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KBD_PWR_BUTTON", GPIO_B, (1<<2), GPIO_INPUT, kbd_power_on}, {"OMZO_RDY_L", GPIO_A, (1<<0), GPIO_INPUT, NULL}, /* PA0_WKUP */ diff --git a/board/snow/board.c b/board/snow/board.c index cebdcab1fe..a70a112b79 100644 --- a/board/snow/board.c +++ b/board/snow/board.c @@ -13,7 +13,7 @@ #include "gpio.h" #include "hooks.h" #include "i2c.h" -#include "keyboard_scan.h" +#include "keyboard_raw.h" #include "pmu_tpschrome.h" #include "power_led.h" #include "registers.h" @@ -41,21 +41,21 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"SUSPEND_L", GPIO_A, (1<<7), INT_BOTH_FLOATING, gaia_suspend_event}, {"WP_L", GPIO_B, (1<<4), GPIO_INPUT, NULL}, {"KB_IN00", GPIO_C, (1<<8), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN01", GPIO_C, (1<<9), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN02", GPIO_C, (1<<10), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN03", GPIO_C, (1<<11), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN04", GPIO_C, (1<<12), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN05", GPIO_C, (1<<14), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN06", GPIO_C, (1<<15), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN07", GPIO_D, (1<<2), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, /* Other inputs */ {"AC_PWRBTN_L", GPIO_A, (1<<0), GPIO_INT_BOTH, NULL}, {"SPI1_NSS", GPIO_A, (1<<4), GPIO_DEFAULT, spi_event}, diff --git a/board/spring/board.c b/board/spring/board.c index e4d361a8ae..dd597a1a08 100644 --- a/board/spring/board.c +++ b/board/spring/board.c @@ -15,7 +15,7 @@ #include "hooks.h" #include "host_command.h" #include "i2c.h" -#include "keyboard_scan.h" +#include "keyboard_raw.h" #include "pmu_tpschrome.h" #include "registers.h" #include "stm32_adc.h" @@ -43,21 +43,21 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"SUSPEND_L", GPIO_A, (1<<7), INT_BOTH_FLOATING, gaia_suspend_event}, {"WP_L", GPIO_A, (1<<13), GPIO_INPUT, NULL}, {"KB_IN00", GPIO_C, (1<<8), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN01", GPIO_C, (1<<9), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN02", GPIO_C, (1<<10), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN03", GPIO_C, (1<<11), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN04", GPIO_C, (1<<12), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN05", GPIO_C, (1<<14), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN06", GPIO_C, (1<<15), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"KB_IN07", GPIO_D, (1<<2), GPIO_KB_INPUT, - keyboard_scan_interrupt}, + keyboard_raw_gpio_interrupt}, {"USB_CHG_INT", GPIO_A, (1<<6), GPIO_INT_FALLING, usb_charge_interrupt}, /* Other inputs */ diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk index 83a97b3ba5..c3ab2bafa5 100644 --- a/chip/lm4/build.mk +++ b/chip/lm4/build.mk @@ -22,6 +22,6 @@ chip-$(CONFIG_ONEWIRE)+=onewire.o chip-$(CONFIG_PECI)+=peci.o chip-$(CONFIG_PWM)+=pwm.o chip-$(CONFIG_SPI)+=spi.o -chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o keyboard_scan_stub.o +chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o keyboard_raw.o chip-$(CONFIG_TASK_SWITCH)+=switch.o chip-$(CONFIG_WATCHDOG)+=watchdog.o diff --git a/chip/lm4/keyboard_raw.c b/chip/lm4/keyboard_raw.c new file mode 100644 index 0000000000..0db2766773 --- /dev/null +++ b/chip/lm4/keyboard_raw.c @@ -0,0 +1,112 @@ +/* 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. + */ + +/* Functions needed by keyboard scanner module for Chrome EC */ + +#include "common.h" +#include "keyboard_raw.h" +#include "keyboard_scan.h" +#include "registers.h" +#include "task.h" + +void keyboard_raw_init(void) +{ + /* Ensure top-level interrupt is disabled */ + keyboard_raw_enable_interrupt(0); + + /* + * Set column outputs as open-drain; we either pull them low or let + * them float high. + */ + LM4_GPIO_AFSEL(LM4_GPIO_P) = 0; /* KSO[7:0] */ + LM4_GPIO_AFSEL(LM4_GPIO_Q) &= ~0x1f; /* KSO[12:8] */ + LM4_GPIO_DEN(LM4_GPIO_P) = 0xff; + LM4_GPIO_DEN(LM4_GPIO_Q) |= 0x1f; + LM4_GPIO_DIR(LM4_GPIO_P) = 0xff; + LM4_GPIO_DIR(LM4_GPIO_Q) |= 0x1f; + LM4_GPIO_ODR(LM4_GPIO_P) = 0xff; + LM4_GPIO_ODR(LM4_GPIO_Q) |= 0x1f; + + /* Set row inputs with pull-up */ + LM4_GPIO_AFSEL(KB_SCAN_ROW_GPIO) &= 0xff; + LM4_GPIO_DEN(KB_SCAN_ROW_GPIO) |= 0xff; + LM4_GPIO_DIR(KB_SCAN_ROW_GPIO) = 0; + LM4_GPIO_PUR(KB_SCAN_ROW_GPIO) = 0xff; + + /* Edge-sensitive on both edges. */ + LM4_GPIO_IS(KB_SCAN_ROW_GPIO) = 0; + LM4_GPIO_IBE(KB_SCAN_ROW_GPIO) = 0xff; + + /* + * Enable interrupts for the inputs. The top-level interrupt is still + * masked off, so this won't trigger interrupts yet. + */ + LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; +} + +void keyboard_raw_task_start(void) +{ + task_enable_irq(KB_SCAN_ROW_IRQ); +} + +void keyboard_raw_drive_column(int col) +{ + if (col == KEYBOARD_COLUMN_NONE) { + /* Tri-state all outputs */ + LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0xff; + LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0x1f; + } else if (col == KEYBOARD_COLUMN_ALL) { + /* Assert all outputs */ + LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0; + LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0; + } else { + /* Assert a single output */ + LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0xff; + LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0x1f; + if (col < 8) + LM4_GPIO_DATA(LM4_GPIO_P, 1 << col) = 0; + else + LM4_GPIO_DATA(LM4_GPIO_Q, 1 << (col - 8)) = 0; + } +} + +int keyboard_raw_read_rows(void) +{ + /* Bits are active-low, so invert returned levels */ + return LM4_GPIO_DATA(KB_SCAN_ROW_GPIO, 0xff) ^ 0xff; +} + +void keyboard_raw_enable_interrupt(int enable) +{ + if (enable) { + /* + * Clear pending interrupts before enabling them, because the + * raw interrupt status may have been tripped by keyboard + * scanning or, if a key is already pressed, by driving all the + * outputs. + * + * We won't lose keyboard events because the scanning task will + * explicitly check the raw row state before waiting for an + * interrupt. If a key is pressed, the task won't wait. + */ + LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = 0xff; + LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; + } else { + LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0; + } +} + +/** + * Interrupt handler for the entire GPIO bank of keyboard rows. + */ +static void keyboard_raw_interrupt(void) +{ + /* Clear all pending keyboard interrupts */ + LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = 0xff; + + /* Wake the scan task */ + task_wake(TASK_ID_KEYSCAN); +} +DECLARE_IRQ(KB_SCAN_ROW_IRQ, keyboard_raw_interrupt, 3); diff --git a/chip/lm4/keyboard_scan.c b/chip/lm4/keyboard_scan.c index fd2f6486b9..0c56738a05 100644 --- a/chip/lm4/keyboard_scan.c +++ b/chip/lm4/keyboard_scan.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* 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. */ @@ -10,9 +10,8 @@ #include "console.h" #include "host_command.h" #include "keyboard.h" +#include "keyboard_raw.h" #include "keyboard_scan.h" -#include "keyboard_scan_stub.h" -#include "registers.h" #include "switch.h" #include "system.h" #include "task.h" @@ -83,29 +82,29 @@ static int print_state_changes; #define MASK_INDEX_KEY_H 6 #define MASK_VALUE_KEY_H 0x02 +static int enable_scanning = 1; /* Must init to 1 for scanning at boot */ + static void enable_interrupt(void) { CPRINTF("[%T KB wait]\n"); - /* Assert all outputs would trigger un-wanted interrupts. - * Clear them before enable interrupt. */ - lm4_select_column(COLUMN_ASSERT_ALL); - lm4_clear_matrix_interrupt_status(); + if (enable_scanning) + keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL); - lm4_enable_matrix_interrupt(); + keyboard_raw_enable_interrupt(1); } static void enter_polling_mode(void) { CPRINTF("[%T KB poll]\n"); - lm4_disable_matrix_interrupt(); - lm4_select_column(COLUMN_TRI_STATE_ALL); + keyboard_raw_enable_interrupt(0); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); } static int is_scanning_enabled(void) { /* Scan only if enabled AND lid is open. */ - return lm4_get_scanning_enabled() && switch_get_lid_open(); + return enable_scanning && switch_get_lid_open(); } /** @@ -125,14 +124,16 @@ static int read_matrix(uint8_t *state) int pressed = 0; for (c = 0; c < KB_COLS; c++) { + /* Stop if scanning becomes disabled */ + if (!enable_scanning) + break; + /* Select column, then wait a bit for it to settle */ - lm4_select_column(c); + keyboard_raw_drive_column(c); udelay(COLUMN_CHARGE_US); /* Read the row state */ - r = lm4_read_raw_row_state(); - /* Invert it so 0=not pressed, 1=pressed */ - r ^= 0xff; + r = keyboard_raw_read_rows(); /* Mask off keys that don't exist so they never show * as pressed */ r &= actual_key_mask[c]; @@ -141,7 +142,7 @@ static int read_matrix(uint8_t *state) pressed |= r; } - lm4_select_column(COLUMN_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); return pressed ? 1 : 0; } @@ -413,10 +414,10 @@ enum boot_key keyboard_scan_get_boot_key(void) void keyboard_scan_init(void) { /* Configure GPIO */ - lm4_configure_keyboard_gpio(); + keyboard_raw_init(); /* Tri-state the columns */ - lm4_select_column(COLUMN_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); /* Initialize raw state */ read_matrix(debounced_state); @@ -436,8 +437,7 @@ void keyboard_scan_task(void) print_state(debounced_state, "init state"); - /* Enable interrupts */ - task_enable_irq(KB_SCAN_ROW_IRQ); + keyboard_raw_task_start(); while (1) { /* Enable all outputs */ @@ -451,8 +451,7 @@ void keyboard_scan_task(void) * user pressing a key and enable_interrupt() * starting to pay attention to edges. */ - if ((lm4_read_raw_row_state() == 0xff) || - !is_scanning_enabled()) + if (!keyboard_raw_read_rows() || !is_scanning_enabled()) task_wait_event(-1); } while (!is_scanning_enabled()); @@ -475,22 +474,10 @@ void keyboard_scan_task(void) } } -static void matrix_interrupt(void) -{ - uint32_t ris = lm4_clear_matrix_interrupt_status(); - - if (ris) - task_wake(TASK_ID_KEYSCAN); -} -DECLARE_IRQ(KB_SCAN_ROW_IRQ, matrix_interrupt, 3); - -/* - * The actual implementation is controlling the enable_scanning variable, then - * that controls whether lm4_select_column() can pull-down columns or not. - */ void keyboard_enable_scanning(int enable) { - lm4_set_scanning_enabled(enable); + enable_scanning = enable; + if (enable) { /* * A power button press had tri-stated all columns (see the @@ -499,13 +486,13 @@ void keyboard_enable_scanning(int enable) */ task_wake(TASK_ID_KEYSCAN); } else { - lm4_select_column(COLUMN_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); keyboard_clear_underlying_buffer(); } } /*****************************************************************************/ -/* Console commands*/ +/* Console commands */ static int command_ksstate(int argc, char **argv) { diff --git a/chip/lm4/keyboard_scan_stub.c b/chip/lm4/keyboard_scan_stub.c deleted file mode 100644 index 01d1aca8e2..0000000000 --- a/chip/lm4/keyboard_scan_stub.c +++ /dev/null @@ -1,115 +0,0 @@ -/* 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. - */ - -/* Functions needed by keyboard scanner module for Chrome EC */ - -#include "board.h" -#include "keyboard_scan.h" -#include "keyboard_scan_stub.h" -#include "registers.h" - - -/* Notes: - * - * Link proto0 board: - * - * Columns (outputs): - * KSO0 - KSO7 = PP0:7 - * KSO8 - KSO12 = PQ0:4 - * - * Rows (inputs): - * KSI0 - KSI7 = PN0:7 - * - * Other: - * PWR_BTN# = PK7 (handled by gpio module) - */ - - -static int enable_scanning = 1; /* Must init to 1 for scanning at boot */ - - -void lm4_set_scanning_enabled(int enabled) -{ - enable_scanning = enabled; -} - - -int lm4_get_scanning_enabled(void) -{ - return enable_scanning; -} - - -void lm4_select_column(int col) -{ - if (col == COLUMN_TRI_STATE_ALL || !enable_scanning) { - /* Tri-state all outputs */ - LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0xff; - LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0x1f; - } else if (col == COLUMN_ASSERT_ALL) { - /* Assert all outputs */ - LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0; - LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0; - } else { - /* Assert a single output */ - LM4_GPIO_DATA(LM4_GPIO_P, 0xff) = 0xff; - LM4_GPIO_DATA(LM4_GPIO_Q, 0x1f) = 0x1f; - if (col < 8) - LM4_GPIO_DATA(LM4_GPIO_P, 1 << col) = 0; - else - LM4_GPIO_DATA(LM4_GPIO_Q, 1 << (col - 8)) = 0; - } -} - - -uint32_t lm4_clear_matrix_interrupt_status(void) -{ - uint32_t ris = LM4_GPIO_RIS(KB_SCAN_ROW_GPIO); - LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = ris; - - return ris; -} - - -void lm4_enable_matrix_interrupt(void) -{ - LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; /* 1: enable interrupt */ -} - - -void lm4_disable_matrix_interrupt(void) -{ - LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0; /* 0: disable interrupt */ -} - - -int lm4_read_raw_row_state(void) -{ - return LM4_GPIO_DATA(KB_SCAN_ROW_GPIO, 0xff); -} - - -void lm4_configure_keyboard_gpio(void) -{ - /* Set column outputs as open-drain; we either pull them low or let - * them float high. */ - LM4_GPIO_AFSEL(LM4_GPIO_P) = 0; /* KSO[7:0] */ - LM4_GPIO_AFSEL(LM4_GPIO_Q) &= ~0x1f; /* KSO[12:8] */ - LM4_GPIO_DEN(LM4_GPIO_P) = 0xff; - LM4_GPIO_DEN(LM4_GPIO_Q) |= 0x1f; - LM4_GPIO_DIR(LM4_GPIO_P) = 0xff; - LM4_GPIO_DIR(LM4_GPIO_Q) |= 0x1f; - LM4_GPIO_ODR(LM4_GPIO_P) = 0xff; - LM4_GPIO_ODR(LM4_GPIO_Q) |= 0x1f; - - /* Set row inputs with pull-up */ - LM4_GPIO_AFSEL(KB_SCAN_ROW_GPIO) &= 0xff; - LM4_GPIO_DEN(KB_SCAN_ROW_GPIO) |= 0xff; - LM4_GPIO_DIR(KB_SCAN_ROW_GPIO) = 0; - LM4_GPIO_PUR(KB_SCAN_ROW_GPIO) = 0xff; - /* Edge-sensitive on both edges. Don't enable interrupts yet. */ - LM4_GPIO_IS(KB_SCAN_ROW_GPIO) = 0; - LM4_GPIO_IBE(KB_SCAN_ROW_GPIO) = 0xff; -} diff --git a/chip/lm4/keyboard_scan_stub.h b/chip/lm4/keyboard_scan_stub.h deleted file mode 100644 index 54ab598180..0000000000 --- a/chip/lm4/keyboard_scan_stub.h +++ /dev/null @@ -1,43 +0,0 @@ -/* 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. - * - * Funcitons needed by keyboard scanner module. - * Abstracted from keyboard_scan.c for stub. - */ - -#ifndef __CROS_EC_KEYBOARD_SCAN_STUB_H -#define __CROS_EC_KEYBOARD_SCAN_STUB_H - -/* used for select_column() */ -enum COLUMN_INDEX { - COLUMN_ASSERT_ALL = -2, - COLUMN_TRI_STATE_ALL = -1, - /* 0 ~ 12 for the corresponding column */ -}; - -/* Set keyboard scanning to enabled/disabled */ -void lm4_set_scanning_enabled(int enabled); - -/* Get keyboard scanning enabled/disabled */ -int lm4_get_scanning_enabled(void); - -/* Drive the specified column low; other columns are tristated */ -void lm4_select_column(int col); - -/* Clear current interrupt status */ -uint32_t lm4_clear_matrix_interrupt_status(void); - -/* Enable interrupt from keyboard matrix */ -void lm4_enable_matrix_interrupt(void); - -/* Disable interrupt from keyboard matrix */ -void lm4_disable_matrix_interrupt(void); - -/* Read raw row state */ -int lm4_read_raw_row_state(void); - -/* Configure keyboard matrix GPIO */ -void lm4_configure_keyboard_gpio(void); - -#endif /* __CROS_EC_KEYBOARD_SCAN_STUB_H */ diff --git a/chip/lm4/mock_keyboard_scan_stub.c b/chip/lm4/mock_keyboard_scan_stub.c index 743c20aef4..0c9ecff2f5 100644 --- a/chip/lm4/mock_keyboard_scan_stub.c +++ b/chip/lm4/mock_keyboard_scan_stub.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* 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. */ /* Mock functions for keyboard scanner module for Chrome EC */ -#include "board.h" +#include "common.h" #include "console.h" +#include "keyboard_raw.h" #include "keyboard_scan.h" -#include "keyboard_scan_stub.h" #include "task.h" #include "uart.h" #include "util.h" @@ -20,63 +20,36 @@ static int selected_column = -1; static int interrupt_enabled = 0; static uint8_t matrix_status[MOCK_COLUMN_COUNT]; - -void lm4_set_scanning_enabled(int enabled) +void keyboard_raw_init(void) { - enable_scanning = enabled; - uart_printf("%s keyboard scanning\n", enabled ? "Enable" : "Disable"); + /* Init matrix status to release all */ + int i; + for (i = 0; i < MOCK_COLUMN_COUNT; ++i) + matrix_status[i] = 0xff; } - -int lm4_get_scanning_enabled(void) +void keyboard_raw_task_start(void) { - return enable_scanning; } - -void lm4_select_column(int col) +void keyboard_raw_drive_column(int col) { selected_column = col; } - -uint32_t lm4_clear_matrix_interrupt_status(void) -{ - /* Not implemented */ - return 0; -} - - -void lm4_enable_matrix_interrupt(void) -{ - interrupt_enabled = 1; -} - - -void lm4_disable_matrix_interrupt(void) -{ - interrupt_enabled = 0; -} - - -int lm4_read_raw_row_state(void) +int keyboard_raw_read_rows(void) { if (selected_column >= 0) - return matrix_status[selected_column]; + return matrix_status[selected_column] ^ 0xff; else return 0; } - -void lm4_configure_keyboard_gpio(void) +void keyboard_raw_enable_interrupt(int enable) { - /* Init matrix status to release all */ - int i; - for (i = 0; i < MOCK_COLUMN_COUNT; ++i) - matrix_status[i] = 0xff; + interrupt_enabled = enable; } - static int command_mock_matrix(int argc, char **argv) { int r, c, p; diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk index 36496ba411..0125554a72 100644 --- a/chip/stm32/build.mk +++ b/chip/stm32/build.mk @@ -14,7 +14,7 @@ chip-y+=jtag-$(CHIP_VARIANT).o clock-$(CHIP_VARIANT).o gpio-$(CHIP_VARIANT).o chip-$(CONFIG_SPI)+=spi.o chip-$(CONFIG_I2C)+=i2c.o chip-$(CONFIG_WATCHDOG)+=watchdog.o -chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o +chip-$(CONFIG_TASK_KEYSCAN)+=keyboard_scan.o keyboard_raw.o chip-$(CONFIG_TASK_POWERLED)+=power_led.o chip-$(CONFIG_FLASH)+=flash-$(CHIP_VARIANT).o chip-$(CONFIG_ADC)+=adc.o 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); +} diff --git a/chip/stm32/keyboard_scan.c b/chip/stm32/keyboard_scan.c index c8ca6b0698..7839a5d1d7 100644 --- a/chip/stm32/keyboard_scan.c +++ b/chip/stm32/keyboard_scan.c @@ -1,16 +1,8 @@ -/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +/* 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. - */ - -/* - * Keyboard scanner module for Chrome EC * - * 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). + * Keyboard scanner module for Chrome EC STM32 */ #include "atomic.h" @@ -19,9 +11,9 @@ #include "gpio.h" #include "host_command.h" #include "keyboard.h" +#include "keyboard_raw.h" #include "keyboard_scan.h" #include "keyboard_test.h" -#include "registers.h" #include "system.h" #include "task.h" #include "timer.h" @@ -31,16 +23,6 @@ #define CPUTS(outstr) cputs(CC_KEYSCAN, outstr) #define CPRINTF(format, args...) cprintf(CC_KEYSCAN, format, ## args) -/* used for assert_output() */ -enum { - OUTPUT_ASSERT_ALL = -2, - OUTPUT_TRI_STATE_ALL = -1, - /* 0 ~ 12 for the corresponding output */ -}; - -/* Mask of external interrupts on input lines */ -static unsigned int irq_mask; - #define SCAN_TIME_COUNT 32 static struct mutex scanning_enabled; @@ -69,7 +51,7 @@ static uint8_t scan_edge_index[KB_OUTPUTS][KB_INPUTS]; #define MASK_INDEX_LEFT_ALT 10 #define MASK_VALUE_LEFT_ALT 0x40 -static const uint32_t kb_out_ports[] = { KB_OUT_PORT_LIST }; +/*****************************************************************************/ /* Provide a default function in case the board doesn't have one */ void __board_keyboard_suppress_noise(void) @@ -171,45 +153,6 @@ static int kb_fifo_remove(uint8_t *buffp) return EC_SUCCESS; } -static void assert_output(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 == OUTPUT_ASSERT_ALL) { - /* drive low (clear bit) */ - bsrr |= gpio_list[j].mask << 16; - } else if (out == OUTPUT_TRI_STATE_ALL) { - /* put output in hi-Z state (set bit) */ - bsrr |= gpio_list[j].mask; - } else { - /* drive specified output low, others => hi-Z */ - if (j - GPIO_KB_OUT00 == out) { - /* to avoid conflict, tri-state all - * outputs first, then assert output */ - assert_output(OUTPUT_TRI_STATE_ALL); - bsrr |= gpio_list[j].mask << 16; - done = 1; - break; - } - } - } - - if (bsrr) - STM32_GPIO_BSRR_OFF(kb_out_ports[i]) = bsrr; - - if (done) - break; - } -} - /** * Assert host keyboard interrupt line. */ @@ -219,28 +162,6 @@ static void set_host_interrupt(int active) gpio_set_level(GPIO_EC_INT, !active); } -/* Set up outputs so that we will get an interrupt when any key changed */ -void setup_interrupts(void) -{ - uint32_t pr_before, pr_after; - - /* Assert all outputs would trigger un-wanted interrupts. - * Clear them before enable interrupt. */ - pr_before = STM32_EXTI_PR; - assert_output(OUTPUT_ASSERT_ALL); - pr_after = STM32_EXTI_PR; - STM32_EXTI_PR |= ((pr_after & ~pr_before) & irq_mask); - - STM32_EXTI_IMR |= irq_mask; /* 1: unmask interrupt */ -} - - -void enter_polling_mode(void) -{ - STM32_EXTI_IMR &= ~irq_mask; /* 0: mask interrupts */ - assert_output(OUTPUT_TRI_STATE_ALL); -} - /** * Check special runtime key combinations. * @@ -289,38 +210,6 @@ static void print_state(const uint8_t *state, const char *msg) } /** - * Read the raw input state for the currently selected output - * - * It is assumed that the output is already selected by the scanning - * hardware. The output number is only used by test code. - * - * @return input state, one bit for each input - */ -static uint8_t read_raw_input_state(void) -{ - int i; - unsigned int port, prev_port = 0; - uint8_t 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 */ - state ^= 0xff; - - return state; -} - -/** * Read the raw keyboard matrix state. * * Used in pre-init, so must not make task-switching-dependent calls; udelay() @@ -338,10 +227,10 @@ static int read_matrix(uint8_t *state) for (c = 0; c < KB_OUTPUTS; c++) { /* Assert output, then wait a bit for it to settle */ - assert_output(c); + keyboard_raw_drive_column(c); udelay(config.output_settle_us); - r = read_raw_input_state(); + r = keyboard_raw_read_rows(); #ifdef CONFIG_KEYBOARD_TEST /* Use simulated keyscan sequence instead if testing active */ @@ -357,7 +246,7 @@ static int read_matrix(uint8_t *state) state[c] = r; pressed |= r; } - assert_output(OUTPUT_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); return pressed ? 1 : 0; } @@ -499,11 +388,12 @@ static int check_recovery_key(const uint8_t *state) return 1; } - void keyboard_scan_init(void) { + keyboard_raw_init(); + /* Tri-state (put into Hi-Z) the outputs */ - assert_output(OUTPUT_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); /* Initialize raw state */ read_matrix(debounced_state); @@ -520,7 +410,8 @@ static void scan_keyboard(void) int keys_changed = 1; mutex_lock(&scanning_enabled); - setup_interrupts(); + keyboard_raw_drive_column(KEYBOARD_COLUMN_ALL); + keyboard_raw_enable_interrupt(1); mutex_unlock(&scanning_enabled); /* @@ -528,7 +419,7 @@ static void scan_keyboard(void) * re-start immediatly polling instead of waiting * for the next interrupt. */ - if (!read_raw_input_state()) { + if (!keyboard_raw_read_rows()) { #ifdef CONFIG_KEYBOARD_TEST task_wait_event(keyscan_seq_next_event_delay()); #else @@ -536,7 +427,8 @@ static void scan_keyboard(void) #endif } - enter_polling_mode(); + keyboard_raw_enable_interrupt(0); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); /* Busy polling keyboard state. */ while (1) { @@ -566,47 +458,22 @@ static void scan_keyboard(void) } } -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_scan_task(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); - - /* Determine EXTI_PR mask to use for the board */ - set_irq_mask(); - print_state(debounced_state, "init state"); + keyboard_raw_task_start(); + while (1) { if (config.flags & EC_MKBP_FLAGS_ENABLE) { scan_keyboard(); } else { - assert_output(OUTPUT_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); task_wait_event(-1); } } } - -void keyboard_scan_interrupt(enum gpio_signal signal) -{ - task_wake(TASK_ID_KEYSCAN); -} - int keyboard_has_char(void) { /* TODO: needs to be implemented */ @@ -660,8 +527,16 @@ void keyboard_enable_scanning(int enable) mutex_unlock(&scanning_enabled); task_wake(TASK_ID_KEYSCAN); } else { + /* + * TODO: using a mutex to control scanning isn't very + * responsive. If we just started scanning the matrix, the + * mutex will already be locked, and we'll finish the entire + * matrix scan before we stop driving columns. We should + * instead do something like link, where disabling scanning + * immediately stops driving the columns. + */ mutex_lock(&scanning_enabled); - assert_output(OUTPUT_TRI_STATE_ALL); + keyboard_raw_drive_column(KEYBOARD_COLUMN_NONE); } } diff --git a/include/keyboard_raw.h b/include/keyboard_raw.h new file mode 100644 index 0000000000..6432335a52 --- /dev/null +++ b/include/keyboard_raw.h @@ -0,0 +1,74 @@ +/* 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 access to keyboard GPIOs. + * + * The keyboard matrix is read by driving output signals on the column lines + * and reading the row lines. + */ + +#ifndef __CROS_EC_KEYBOARD_RAW_H +#define __CROS_EC_KEYBOARD_RAW_H + +#include "common.h" +#include "gpio.h" + +/* used for select_column() */ +enum keyboard_column_index { + KEYBOARD_COLUMN_ALL = -2, /* Drive all columns */ + KEYBOARD_COLUMN_NONE = -1, /* Drive no columns (tri-state all) */ + /* 0 ~ 12 for the corresponding column */ +}; + +/** + * Initialize the raw keyboard interface. + * + * Must be called before any other functions in this interface. + */ +void keyboard_raw_init(void); + +/** + * Finish intitialization after task scheduling has started. + * + * Call from the keyboard scan task. + */ +void keyboard_raw_task_start(void); + +/** + * Drive the specified column low. + * + * Other columns are tristated. See enum keyboard_column_index for special + * values for <col>. + */ +void keyboard_raw_drive_column(int col); + +/** + * Read raw row state. + * + * Bits are 1 if signal is present, 0 if not present. + */ +int keyboard_raw_read_rows(void); + +/** + * Enable or disable keyboard interrupts. + * + * Enabling interrupts will clear any pending interrupt bits. To avoid missing + * any interrupts that occur between the end of scanning and then, you should + * call keyboard_raw_read_rows() after this. If it returns non-zero, disable + * interrupts and go back to polling mode instead of waiting for an interrupt. + */ +void keyboard_raw_enable_interrupt(int enable); + +#ifdef CONFIG_TASK_KEYSCAN + +/** + * GPIO interrupt for raw keyboard input + */ +void keyboard_raw_gpio_interrupt(enum gpio_signal signal); + +#else +#define keyboard_raw_gpio_interrupt NULL +#endif + +#endif /* __CROS_EC_KEYBOARD_RAW_H */ diff --git a/include/keyboard_scan.h b/include/keyboard_scan.h index 54e7259c21..e0f883375a 100644 --- a/include/keyboard_scan.h +++ b/include/keyboard_scan.h @@ -9,7 +9,6 @@ #define __CROS_EC_KEYBOARD_SCAN_H #include "common.h" -#include "gpio.h" /** * Initializes the module. @@ -52,15 +51,4 @@ void keyboard_enable_scanning(int enable); */ void keyboard_send_battery_key(void); -#ifdef CONFIG_TASK_KEYSCAN - -/** - * Keyboard scan GPIO interrupt. - */ -void keyboard_scan_interrupt(enum gpio_signal signal); - -#else -#define keyboard_scan_interrupt NULL -#endif - #endif /* __CROS_EC_KEYBOARD_SCAN_H */ |