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
This commit is contained in:
Randall Spangler
2013-03-20 13:47:35 -07:00
committed by ChromeBot
parent cdb08e1221
commit 743c05f01f
15 changed files with 436 additions and 450 deletions

View File

@@ -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},

View File

@@ -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 */

View File

@@ -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},

View File

@@ -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 */

View File

@@ -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

112
chip/lm4/keyboard_raw.c Normal file
View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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,55 +20,7 @@ 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)
{
enable_scanning = enabled;
uart_printf("%s keyboard scanning\n", enabled ? "Enable" : "Disable");
}
int lm4_get_scanning_enabled(void)
{
return enable_scanning;
}
void lm4_select_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)
{
if (selected_column >= 0)
return matrix_status[selected_column];
else
return 0;
}
void lm4_configure_keyboard_gpio(void)
void keyboard_raw_init(void)
{
/* Init matrix status to release all */
int i;
@@ -76,6 +28,27 @@ void lm4_configure_keyboard_gpio(void)
matrix_status[i] = 0xff;
}
void keyboard_raw_task_start(void)
{
}
void keyboard_raw_drive_column(int col)
{
selected_column = col;
}
int keyboard_raw_read_rows(void)
{
if (selected_column >= 0)
return matrix_status[selected_column] ^ 0xff;
else
return 0;
}
void keyboard_raw_enable_interrupt(int enable)
{
interrupt_enabled = enable;
}
static int command_mock_matrix(int argc, char **argv)
{

View File

@@ -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

135
chip/stm32/keyboard_raw.c Normal file
View File

@@ -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);
}

View File

@@ -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.
*
@@ -288,38 +209,6 @@ static void print_state(const uint8_t *state, const char *msg)
CPUTS("]\n");
}
/**
* 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.
*
@@ -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);
}
}

74
include/keyboard_raw.h Normal file
View File

@@ -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 */

View File

@@ -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 */