Handle all GPIO IRQs. Interrupts no longer enabled by default.

Signed-off-by: Randall Spangler <rspangler@chromium.org>

BUG=chrome-os-partner:7456
TEST=if it runs, it works

Change-Id: Ib82afab7d53203af31eefc9887feb98679266ac1
This commit is contained in:
Randall Spangler
2012-01-17 14:25:20 -08:00
parent 002bc4278b
commit 37dcc1ab56
11 changed files with 134 additions and 69 deletions

View File

@@ -53,6 +53,11 @@
#define I2C_SPEED_CHARGER 100
#define I2C_SPEED_THERMAL 400 /* TODO: TMP007 supports 3.4Mbps
operation; use faster speed? */
/* Keyboard scanner uses an entire GPIO bank for row inputs */
#define KB_SCAN_ROW_IRQ LM4_IRQ_GPIOH
#define KB_SCAN_ROW_GPIO LM4_GPIO_H
/* GPIO signal list */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */

View File

@@ -54,6 +54,10 @@
#define I2C_SPEED_THERMAL 400 /* TODO: TMP007 supports 3.4Mbps
operation; use faster speed? */
/* Keyboard scanner uses an entire GPIO bank for row inputs */
#define KB_SCAN_ROW_IRQ LM4_IRQ_GPION
#define KB_SCAN_ROW_GPIO LM4_GPIO_N
/* GPIO signal definitions. */
enum gpio_signal {
/* Inputs with interrupt handlers are first for efficiency */

View File

@@ -116,6 +116,27 @@ int gpio_pre_init(void)
/* Interrupt is enabled by gpio_enable_interrupt() */
}
/* Enable IRQs now that pins are set up */
task_enable_irq(LM4_IRQ_GPIOA);
task_enable_irq(LM4_IRQ_GPIOB);
task_enable_irq(LM4_IRQ_GPIOC);
task_enable_irq(LM4_IRQ_GPIOD);
task_enable_irq(LM4_IRQ_GPIOE);
task_enable_irq(LM4_IRQ_GPIOF);
task_enable_irq(LM4_IRQ_GPIOG);
#if (KB_SCAN_ROW_IRQ != LM4_IRQ_GPIOH)
task_enable_irq(LM4_IRQ_GPIOH);
#endif
task_enable_irq(LM4_IRQ_GPIOJ);
task_enable_irq(LM4_IRQ_GPIOK);
task_enable_irq(LM4_IRQ_GPIOL);
task_enable_irq(LM4_IRQ_GPIOM);
#if (KB_SCAN_ROW_IRQ != LM4_IRQ_GPION)
task_enable_irq(LM4_IRQ_GPION);
#endif
task_enable_irq(LM4_IRQ_GPIOP);
task_enable_irq(LM4_IRQ_GPIOQ);
return EC_SUCCESS;
}
@@ -203,24 +224,58 @@ static void gpio_interrupt(int port, uint32_t mis)
/* Handlers for each GPIO port. These read and clear the interrupt bits for
* the port, then call the master handler above. */
#define GPIO_IRQ_FUNC(irqfunc, gpiobase) \
static void irqfunc(void) \
{ \
uint32_t mis = LM4_GPIO_MIS(gpiobase); \
LM4_GPIO_ICR(gpiobase) = mis; \
gpio_interrupt(gpiobase, mis); \
}
static void __gpio_c_interrupt(void)
{
/* Read and clear the interrupt status */
uint32_t mis = LM4_GPIO_MIS(LM4_GPIO_C);
LM4_GPIO_ICR(LM4_GPIO_C) = mis;
gpio_interrupt(LM4_GPIO_C, mis);
}
GPIO_IRQ_FUNC(__gpio_a_interrupt, LM4_GPIO_A);
GPIO_IRQ_FUNC(__gpio_b_interrupt, LM4_GPIO_B);
GPIO_IRQ_FUNC(__gpio_c_interrupt, LM4_GPIO_C);
GPIO_IRQ_FUNC(__gpio_d_interrupt, LM4_GPIO_D);
GPIO_IRQ_FUNC(__gpio_e_interrupt, LM4_GPIO_E);
GPIO_IRQ_FUNC(__gpio_f_interrupt, LM4_GPIO_F);
GPIO_IRQ_FUNC(__gpio_g_interrupt, LM4_GPIO_G);
#if (KB_SCAN_ROW_GPIO != LM4_GPIO_H)
GPIO_IRQ_FUNC(__gpio_h_interrupt, LM4_GPIO_H);
#endif
GPIO_IRQ_FUNC(__gpio_j_interrupt, LM4_GPIO_J);
GPIO_IRQ_FUNC(__gpio_k_interrupt, LM4_GPIO_K);
GPIO_IRQ_FUNC(__gpio_l_interrupt, LM4_GPIO_L);
GPIO_IRQ_FUNC(__gpio_m_interrupt, LM4_GPIO_M);
#if (KB_SCAN_ROW_GPIO != LM4_GPIO_N)
GPIO_IRQ_FUNC(__gpio_n_interrupt, LM4_GPIO_N);
#endif
GPIO_IRQ_FUNC(__gpio_p_interrupt, LM4_GPIO_P);
GPIO_IRQ_FUNC(__gpio_q_interrupt, LM4_GPIO_Q);
#undef GPIO_IRQ_FUNC
/* Declare IRQs */
/* TODO: nesting this macro inside the GPIO_IRQ_FUNC macro works poorly because
* DECLARE_IRQ() stringizes its inputs. */
DECLARE_IRQ(LM4_IRQ_GPIOA, __gpio_a_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOB, __gpio_b_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOC, __gpio_c_interrupt, 1);
static void __gpio_k_interrupt(void)
{
/* Read and clear the interrupt status */
uint32_t mis = LM4_GPIO_MIS(LM4_GPIO_K);
LM4_GPIO_ICR(LM4_GPIO_K) = mis;
gpio_interrupt(LM4_GPIO_K, mis);
}
DECLARE_IRQ(LM4_IRQ_GPIOD, __gpio_d_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOE, __gpio_e_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOF, __gpio_f_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOG, __gpio_g_interrupt, 1);
#if (KB_SCAN_ROW_IRQ != LM4_IRQ_GPIOH)
DECLARE_IRQ(LM4_IRQ_GPIOH, __gpio_h_interrupt, 1);
#endif
DECLARE_IRQ(LM4_IRQ_GPIOJ, __gpio_j_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOK, __gpio_k_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOL, __gpio_l_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOM, __gpio_m_interrupt, 1);
#if (KB_SCAN_ROW_IRQ != LM4_IRQ_GPION)
DECLARE_IRQ(LM4_IRQ_GPION, __gpio_n_interrupt, 1);
#endif
DECLARE_IRQ(LM4_IRQ_GPIOP, __gpio_p_interrupt, 1);
DECLARE_IRQ(LM4_IRQ_GPIOQ, __gpio_q_interrupt, 1);
/*****************************************************************************/
/* Console commands */

View File

@@ -258,6 +258,14 @@ int i2c_init(void)
LM4_I2C_MTPR(I2C_PORT_CHARGER) =
(CPU_CLOCK / (I2C_SPEED_CHARGER * 10 * 2)) - 1;
/* Enable irqs */
task_enable_irq(LM4_IRQ_I2C0);
task_enable_irq(LM4_IRQ_I2C1);
task_enable_irq(LM4_IRQ_I2C2);
task_enable_irq(LM4_IRQ_I2C3);
task_enable_irq(LM4_IRQ_I2C4);
task_enable_irq(LM4_IRQ_I2C5);
console_register_commands(&command_group);
return EC_SUCCESS;
}

View File

@@ -5,6 +5,7 @@
/* Keyboard scanner module for Chrome EC */
#include "board.h"
#include "console.h"
#include "keyboard.h"
#include "keyboard_scan.h"
@@ -17,7 +18,7 @@
/* Notes:
*
* EVT board:
* Link proto0 board:
*
* Columns (outputs):
* KSO0 - KSO7 = PP0:7
@@ -30,7 +31,7 @@
* PWR_BTN# = PK7
*
*
* Hacked board:
* BDS board:
*
* Columns (outputs):
* KSO0 - KSO7 = PQ0:7
@@ -53,8 +54,6 @@ enum COLUMN_INDEX {
#define POLLING_MODE_TIMEOUT 1000000 /* 1 sec */
#define SCAN_LOOP_DELAY 10000 /* 10 ms */
#undef EVT /* FIXME: define this for EVT board. */
#define KB_COLS 13
static uint8_t raw_state[KB_COLS];
@@ -76,7 +75,7 @@ static const uint8_t actual_key_masks[4][KB_COLS] = {
/* Drives the specified column low; other columns are tri-stated */
static void select_column(int col)
{
#if defined(EVT)
#ifdef BOARD_link
if (col == COLUMN_ASSERT_ALL) {
LM4_GPIO_DIR(LM4_GPIO_P) = 0xff;
LM4_GPIO_DIR(LM4_GPIO_Q) |= 0x1f;
@@ -142,7 +141,7 @@ int keyboard_scan_init(void)
int i;
/* Enable GPIOs */
#if defined(EVT)
#ifdef BOARD_link
/* Enable clock to GPIO modules C,H,K,N,P,Q */
LM4_SYSTEM_RCGCGPIO |= 0x7284;
#else
@@ -155,7 +154,7 @@ int keyboard_scan_init(void)
* PK0:3, PN2, PQ0:7. */
LM4_GPIO_AFSEL(LM4_GPIO_C) &= ~0x20;
LM4_GPIO_DEN(LM4_GPIO_C) |= 0x20;
#if defined(EVT)
#ifdef BOARD_link
LM4_GPIO_AFSEL(LM4_GPIO_N) &= 0xff; /* KSI[7:0] */
LM4_GPIO_DEN(LM4_GPIO_N) |= 0xff;
LM4_GPIO_AFSEL(LM4_GPIO_P) &= 0xff; /* KSO[7:0] */
@@ -173,15 +172,9 @@ int keyboard_scan_init(void)
LM4_GPIO_DEN(LM4_GPIO_Q) = 0xff;
#endif
#if defined(EVT)
/* Set PN0:7 as inputs with pull-up */
LM4_GPIO_DIR(LM4_GPIO_N) = 0;
LM4_GPIO_PUR(LM4_GPIO_N) = 0xff;
#else
/* Set PH0:7 as inputs with pull-up */
LM4_GPIO_DIR(LM4_GPIO_H) = 0;
LM4_GPIO_PUR(LM4_GPIO_H) = 0xff;
#endif
/* Set row inputs with pull-up */
LM4_GPIO_DIR(KB_SCAN_ROW_GPIO) = 0;
LM4_GPIO_PUR(KB_SCAN_ROW_GPIO) = 0xff;
/* Set PC5 as input with pull-up. */
/* TODO: no need for pull-up on real circuit, since it'll be
@@ -200,18 +193,16 @@ int keyboard_scan_init(void)
* key mask properly */
actual_key_mask = actual_key_masks[0];
/* Enable interrupts, now that we're set up */
task_enable_irq(KB_SCAN_ROW_IRQ);
return EC_SUCCESS;
}
static uint32_t clear_matrix_interrupt_status(void) {
#if defined(EVT)
uint32_t port = LM4_GPIO_N;
#else
uint32_t port = LM4_GPIO_H;
#endif
uint32_t ris = LM4_GPIO_RIS(port);
LM4_GPIO_ICR(port) = ris;
uint32_t ris = LM4_GPIO_RIS(KB_SCAN_ROW_GPIO);
LM4_GPIO_ICR(KB_SCAN_ROW_GPIO) = ris;
return ris;
}
@@ -219,33 +210,23 @@ static uint32_t clear_matrix_interrupt_status(void) {
void wait_for_interrupt(void)
{
uart_printf("Enter %s() ...\n", __func__);
uart_printf("[kbscan %s()]\n", __func__);
/* Assert all outputs would trigger un-wanted interrupts.
* Clear them before enable interrupt. */
select_column(COLUMN_ASSERT_ALL);
clear_matrix_interrupt_status();
#if defined(EVT)
LM4_GPIO_IS(LM4_GPIO_N) = 0; /* 0: edge-sensitive */
LM4_GPIO_IBE(LM4_GPIO_N) = 0xff; /* 1: both edge */
LM4_GPIO_IM(LM4_GPIO_N) = 0xff; /* 1: enable interrupt */
#else
LM4_GPIO_IS(LM4_GPIO_H) = 0; /* 0: edge-sensitive */
LM4_GPIO_IBE(LM4_GPIO_H) = 0xff; /* 1: both edge */
LM4_GPIO_IM(LM4_GPIO_H) = 0xff; /* 1: enable interrupt */
#endif
LM4_GPIO_IS(KB_SCAN_ROW_GPIO) = 0; /* 0: edge-sensitive */
LM4_GPIO_IBE(KB_SCAN_ROW_GPIO) = 0xff; /* 1: both edge */
LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0xff; /* 1: enable interrupt */
}
void enter_polling_mode(void)
{
uart_printf("Enter %s() ...\n", __func__);
#if defined(EVT)
LM4_GPIO_IM(LM4_GPIO_N) = 0; /* 0: disable interrupt */
#else
LM4_GPIO_IM(LM4_GPIO_H) = 0; /* 0: disable interrupt */
#endif
uart_printf("[kbscan %s()]\n", __func__);
LM4_GPIO_IM(KB_SCAN_ROW_GPIO) = 0; /* 0: disable interrupt */
select_column(COLUMN_TRI_STATE_ALL);
}
@@ -263,11 +244,7 @@ static int check_keys_changed(void)
select_column(c);
usleep(20);
/* Read the row state */
#if defined(EVT)
r = LM4_GPIO_DATA(LM4_GPIO_N, 0xff);
#else
r = LM4_GPIO_DATA(LM4_GPIO_H, 0xff);
#endif
r = LM4_GPIO_DATA(KB_SCAN_ROW_GPIO, 0xff);
/* Invert it so 0=not pressed, 1=pressed */
r ^= 0xff;
/* Mask off keys that don't exist so they never show
@@ -361,8 +338,14 @@ static void matrix_interrupt(void)
}
}
#if defined(EVT)
/* TODO: DECLARE_IRQ stringizing plays poorly with other macros, so need this
* ugly workaround */
#if (KB_SCAN_ROW_IRQ == LM4_IRQ_GPIOH)
DECLARE_IRQ(LM4_IRQ_GPIOH, matrix_interrupt, 3);
#elif (KB_SCAN_ROW_IRQ == LM4_IRQ_GPION)
DECLARE_IRQ(LM4_IRQ_GPION, matrix_interrupt, 3);
#else
DECLARE_IRQ(LM4_IRQ_GPIOH, matrix_interrupt, 3);
#error "Unsupported KB_SCAN_ROW_IRQ"
/* If you add a board with different GPIO, also make sure supporting code in
* gpio.c is changed so the interrupts don't fight... */
#endif

View File

@@ -115,6 +115,9 @@ int lpc_init(void)
(1 << LPC_CH_USER) |
(1 << LPC_CH_COMX);
/* Enable LPC interrupt */
task_enable_irq(LM4_IRQ_LPC);
return EC_SUCCESS;
}

View File

@@ -289,10 +289,6 @@ static void __nvic_init_irqs(void)
(LM4_NVIC_PRI(irq / 4) &
~(0x7 << prio_shift)) |
(prio << prio_shift);
/* TODO: enabling all interrupts here causes a race condition
between an interrupt and setting up the handler for it. */
task_enable_irq(irq);
}
}

View File

@@ -125,7 +125,8 @@ static void __hw_clock_source_init(void)
{
volatile uint32_t scratch __attribute__((unused));
/* use WTIMER0 configured as a free running counter with 1us period */
/* Use WTIMER0 (timer 6) configured as a free running counter with 1 us
* period */
/* Enable WTIMER0 clock */
LM4_SYSTEM_RCGCWTIMER |= 1;
@@ -146,6 +147,9 @@ static void __hw_clock_source_init(void)
LM4_TIMER_TAILR(6) = 0xffffffff;
/* Starts counting in timer A */
LM4_TIMER_CTL(6) |= 0x1;
/* Enable interrupt */
task_enable_irq(LM4_IRQ_TIMERW0A);
}

View File

@@ -205,6 +205,10 @@ int uart_init(void)
LM4_UART_CTL(ch) |= 0x0001;
}
/* Enable interrupts */
task_enable_irq(LM4_IRQ_UART0);
task_enable_irq(LM4_IRQ_UART1);
/* Print hello on UART1 for debugging */
/* TODO: remove in production */
{

View File

@@ -130,5 +130,8 @@ int watchdog_init(int period_ms)
/* lock watchdog registers against unintended accesses */
LM4_WATCHDOG_LOCK(0) = 0xdeaddead;
/* Enable watchdog interrupt */
task_enable_irq(LM4_IRQ_WATCHDOG);
return EC_SUCCESS;
}

View File

@@ -92,9 +92,9 @@ struct irq_priority {
* ensures it is enabled in the interrupt controller with the right priority.
*
* Note that you MUST pass irq using a LM4_IRQ_* constant from register.h, not
* as a number, because it's stringized and matched up with a weak reference
* from init.S. (This is still better than passing it as a raw number, because
* that's more typo-prone.)
* as a number, and not as some other #defined constant, because it's
* stringized and matched up with a weak reference from init.S. (This is still
* better than passing it as a raw number, because that's more typo-prone.)
*/
#define DECLARE_IRQ(irq, routine, priority) \
void irq_##irq##_handler(void) \