mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
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:
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 */
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) \
|
||||
|
||||
Reference in New Issue
Block a user