summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.toolchain3
-rw-r--r--board/bds/ec.tasklist2
-rw-r--r--board/link/ec.tasklist2
-rw-r--r--chip/lm4/build.mk5
-rw-r--r--chip/lm4/gpio.c234
-rw-r--r--chip/lm4/power_button.c201
-rw-r--r--common/main.c2
-rw-r--r--include/gpio.h13
-rw-r--r--include/power_button.h24
9 files changed, 272 insertions, 214 deletions
diff --git a/Makefile.toolchain b/Makefile.toolchain
index a7a961c4f8..e3d59ea15e 100644
--- a/Makefile.toolchain
+++ b/Makefile.toolchain
@@ -24,7 +24,8 @@ CFLAGS_WARN=-Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \
-Wno-pointer-sign -fno-strict-overflow -fconserve-stack
CFLAGS_DEBUG= -g
CFLAGS_INCLUDE=$(foreach i,$(includes),-I$(i) )
-CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DTASKFILE=$(PROJECT).tasklist
+CFLAGS_DEFINE=-DOUTDIR=$(out) -DCHIP=$(CHIP) -DTASKFILE=$(PROJECT).tasklist \
+ -DBOARD=$(BOARD) -DBOARD_$(BOARD)
CPPFLAGS=$(CFLAGS_DEFINE) $(CFLAGS_INCLUDE)
CFLAGS=$(CPPFLAGS) $(CFLAGS_CPU) $(CFLAGS_DEBUG) $(CFLAGS_WARN)
BUILD_CFLAGS=$(CPPFLAGS) -O3 $(CFLAGS_DEBUG) $(CFLAGS_WARN)
diff --git a/board/bds/ec.tasklist b/board/bds/ec.tasklist
index 9a1f87398e..f036105fb3 100644
--- a/board/bds/ec.tasklist
+++ b/board/bds/ec.tasklist
@@ -16,7 +16,7 @@
#define CONFIG_TASK_LIST \
TASK(BLINK, UserLedBlink, NULL) \
TASK(KEYSCAN, keyboard_scan_task, NULL) \
- TASK(GPIOISR, gpio_task, NULL) \
+ TASK(POWERBTN, power_button_task, NULL) \
TASK(CONSOLE, console_task, NULL) \
TASK(HOSTCMD, host_command_task, NULL) \
TASK(I8042CMD, i8042_command_task, NULL)
diff --git a/board/link/ec.tasklist b/board/link/ec.tasklist
index 9a1f87398e..f036105fb3 100644
--- a/board/link/ec.tasklist
+++ b/board/link/ec.tasklist
@@ -16,7 +16,7 @@
#define CONFIG_TASK_LIST \
TASK(BLINK, UserLedBlink, NULL) \
TASK(KEYSCAN, keyboard_scan_task, NULL) \
- TASK(GPIOISR, gpio_task, NULL) \
+ TASK(POWERBTN, power_button_task, NULL) \
TASK(CONSOLE, console_task, NULL) \
TASK(HOSTCMD, host_command_task, NULL) \
TASK(I8042CMD, i8042_command_task, NULL)
diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk
index 49356d2959..28f7c4da2f 100644
--- a/chip/lm4/build.mk
+++ b/chip/lm4/build.mk
@@ -1,3 +1,6 @@
+# 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.
#
# LM4 chip specific files build
#
@@ -6,5 +9,5 @@
CFLAGS_CPU=-mcpu=cortex-m4 -mthumb -Os -mno-sched-prolog
chip-objs=init.o panic.o switch.o task.o timer.o pwm.o i2c.o adc.o
-chip-objs+=clock.o gpio.o system.o lpc.o uart.o x86_power.o
+chip-objs+=clock.o gpio.o system.o lpc.o uart.o x86_power.o power_button.o
chip-objs+=flash.o watchdog.o eeprom.o keyboard_scan.o temp_sensor.o
diff --git a/chip/lm4/gpio.c b/chip/lm4/gpio.c
index 9a6e8429bf..50216106e3 100644
--- a/chip/lm4/gpio.c
+++ b/chip/lm4/gpio.c
@@ -6,147 +6,29 @@
/* GPIO module for Chrome EC */
#include "gpio.h"
+#include "power_button.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "uart.h"
+#include "util.h"
-enum debounce_isr_id
-{
- DEBOUNCE_LID,
- DEBOUNCE_PWRBTN,
- DEBOUNCE_ISR_ID_MAX
-};
-struct debounce_isr_t
-{
- /* TODO: Add a carry bit to indicate timestamp overflow */
- timestamp_t tstamp;
- int started;
- void (*callback)(void);
+struct gpio_info {
+ int port; /* Port (LM4_GPIO_*) */
+ int mask; /* Bitmask on that port (0x01 - 0x80) */
+ void (*irq_handler)(enum gpio_signal signal);
};
-struct debounce_isr_t debounce_isr[DEBOUNCE_ISR_ID_MAX];
-enum power_button_state {
- PWRBTN_STATE_STOPPED = 0,
- PWRBTN_STATE_START = 1,
- PWRBTN_STATE_T0 = 2,
- PWRBTN_STATE_T1 = 3,
- PWRBTN_STATE_T2 = 4,
- PWRBTN_STATE_STOPPING = 5,
+const struct gpio_info signal_info[EC_GPIO_COUNT] = {
+ {LM4_GPIO_A, 0x80, NULL}, /* DEBUG_LED */
+ {LM4_GPIO_C, 0x20, power_button_interrupt}, /* POWER_BUTTON */
+ {LM4_GPIO_C, 0x00, NULL}, /* POWER_BUTTON_OUT */
+ {LM4_GPIO_D, 0x01, power_button_interrupt}, /* LID_SWITCH */
+ {LM4_GPIO_D, 0x00, NULL}, /* LID_SWITCH_OUT */
};
-static enum power_button_state pwrbtn_state = PWRBTN_STATE_STOPPED;
-/* The next timestamp to move onto next state if power button is still pressed.
- */
-static timestamp_t pwrbtn_next_ts = {0};
-
-#define PWRBTN_DELAY_T0 32000 // 32ms
-#define PWRBTN_DELAY_T1 (4000000 - PWRBTN_DELAY_T0) // 4 secs - t0
-#define PWRBTN_DELAY_T2 4000000 // 4 secs
-
-
-static void lid_switch_isr(void)
-{
- /* TODO: Currently we pass through the LID_SW# pin to R_EC_LID_OUT#
- directly. Modify this if we need to consider more conditions.
- */
- uint32_t val = LM4_GPIO_DATA(LM4_GPIO_K, 0x20);
- if (val) {
- LM4_GPIO_DATA(LM4_GPIO_F, 0x1) = 0x1;
- }
- else {
- LM4_GPIO_DATA(LM4_GPIO_F, 0x1) = 0x0;
- }
-}
-
-
-/* Power button state machine.
- *
- * PWRBTN# --- ----
- * to EC |______________________|
- *
- *
- * PWRBTN# --- --------- ----
- * to PCH |__| |___________|
- * t0 t1 t2
- */
-static void set_pwrbtn_to_pch(int high)
-{
-#if defined(EVT)
- LM4_GPIO_DATA(LM4_GPIO_G, 0x80) = high ? 0x80 : 0; // PG7 - R_PBTN_OUT#
-#else
- uart_printf("[%d] set_pwrbtn_to_pch(%s)\n", get_time().le.lo, high ? "HIGH" : "LOW");
-#endif
-}
-
-static void pwrbtn_sm_start(void)
-{
- pwrbtn_state = PWRBTN_STATE_START;
- pwrbtn_next_ts = get_time(); // execute action now!
-}
-
-static void pwrbtn_sm_stop(void)
-{
- pwrbtn_state = PWRBTN_STATE_STOPPING;
- pwrbtn_next_ts = get_time(); // execute action now!
-}
-
-static void pwrbtn_sm_handle(timestamp_t current)
-{
- // Not the time to move onto next state.
- if (pwrbtn_state == PWRBTN_STATE_STOPPED ||
- current.val < pwrbtn_next_ts.val) return;
-
- switch (pwrbtn_state) {
- case PWRBTN_STATE_START:
- pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T0;
- pwrbtn_state = PWRBTN_STATE_T0;
- set_pwrbtn_to_pch(0);
- break;
- case PWRBTN_STATE_T0:
- pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T1;
- pwrbtn_state = PWRBTN_STATE_T1;
- set_pwrbtn_to_pch(1);
- break;
- case PWRBTN_STATE_T1:
- pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T2;
- pwrbtn_state = PWRBTN_STATE_T2;
- set_pwrbtn_to_pch(0);
- break;
- case PWRBTN_STATE_T2:
- /* T2 has passed */
- case PWRBTN_STATE_STOPPING:
- set_pwrbtn_to_pch(1);
- pwrbtn_state = PWRBTN_STATE_STOPPED;
- break;
- default:
- break;
- }
-}
-
-static void power_button_isr(void)
-{
-#if defined(EVT)
- uint32_t val = LM4_GPIO_DATA(LM4_GPIO_K, 0x80); // PK7
-#else
- uint32_t val = LM4_GPIO_DATA(LM4_GPIO_C, 0x20); // PC5
-#endif
- if (!val) {
- /* pressed */
- pwrbtn_sm_start();
- /* TODO: implement after chip/lm4/x86_power.c is completed. */
- // if system is in S5, power_on_system()
- // elif system is in S3, resume_system()
- // else S0 i8042_send_host(make_code);
- } else {
- /* released */
- pwrbtn_sm_stop();
- /* TODO: implement after chip/lm4/x86_power.c is completed. */
- // if system in S0, i8042_send_host(break_code);
- }
-}
int gpio_pre_init(void)
{
@@ -163,6 +45,7 @@ int gpio_pre_init(void)
LM4_GPIO_DEN(LM4_GPIO_A) |= 0x80;
LM4_GPIO_DIR(LM4_GPIO_A) |= 0x80;
+#ifdef BOARD_link
/* Set up LID switch input (block K pin 5) */
LM4_GPIO_PCTL(LM4_GPIO_K) &= ~(0xf00000);
LM4_GPIO_DIR(LM4_GPIO_K) &= ~(0x20);
@@ -183,9 +66,10 @@ int gpio_pre_init(void)
(LM4_GPIO_DATA(LM4_GPIO_K, 0x20) ? 1 : 0);
LM4_GPIO_DIR(LM4_GPIO_F) |= 0x1;
LM4_GPIO_DEN(LM4_GPIO_F) |= 0x1;
+#endif
/* Setup power button input and output pins */
-#if defined(EVT)
+#ifdef BOARD_link
/* input: PK7 */
LM4_GPIO_PCTL(LM4_GPIO_K) &= ~0xf0000000;
LM4_GPIO_DIR(LM4_GPIO_K) &= ~0x80;
@@ -212,76 +96,35 @@ int gpio_pre_init(void)
}
-int gpio_init(void)
-{
- debounce_isr[DEBOUNCE_LID].started = 0;
- debounce_isr[DEBOUNCE_LID].callback = lid_switch_isr;
- debounce_isr[DEBOUNCE_PWRBTN].started = 0;
- debounce_isr[DEBOUNCE_PWRBTN].callback = power_button_isr;
-
- return EC_SUCCESS;
-}
-
-
int gpio_get_level(enum gpio_signal signal)
{
- switch (signal) {
- case EC_GPIO_DEBUG_LED:
- return LM4_GPIO_DATA(LM4_GPIO_A, 0x80) & 0x80 ? 1 : 0;
- default:
- return 0;
- }
+ return LM4_GPIO_DATA(signal_info[signal].port,
+ signal_info[signal].mask) ? 1 : 0;
}
int gpio_set_level(enum gpio_signal signal, int value)
{
- switch (signal) {
- case EC_GPIO_DEBUG_LED:
- LM4_GPIO_DATA(LM4_GPIO_A, 0x80) = (value ? 0x80 : 0);
- return EC_SUCCESS;
- default:
- return EC_ERROR_UNKNOWN;
- }
+ /* Ok to write 0xff becuase LM4_GPIO_DATA bit-masks only the bit
+ * we care about. */
+ LM4_GPIO_DATA(signal_info[signal].port,
+ signal_info[signal].mask) = (value ? 0xff : 0);
+ return EC_SUCCESS;
}
+
static void gpio_interrupt(int port, uint32_t mis)
{
- timestamp_t timelimit;
-
- /* Set 30 ms debounce timelimit */
- timelimit = get_time();
- timelimit.val += 30000;
+ int i = 0;
+ const struct gpio_info *g = signal_info;
- /* Handle interrupts */
- if (port == LM4_GPIO_K && (mis & 0x20)) {
- debounce_isr[DEBOUNCE_LID].tstamp = timelimit;
- debounce_isr[DEBOUNCE_LID].started = 1;
- }
-
- /* Handle power button */
-#if defined(EVT)
- if (port == LM4_GPIO_K && (mis & 0x80)) { // PK7
-#else
- if (port == LM4_GPIO_C && (mis & 0x20)) { // PC5
-#endif
- debounce_isr[DEBOUNCE_PWRBTN].tstamp = timelimit;
- debounce_isr[DEBOUNCE_PWRBTN].started = 1;
+ for (i = 0; i < EC_GPIO_COUNT; i++, g++) {
+ if (port == g->port && (mis & g->mask) && g->irq_handler)
+ g->irq_handler(i);
}
}
-static void __gpio_k_interrupt(void)
-{
- uint32_t mis = LM4_GPIO_MIS(LM4_GPIO_K);
-
- /* Clear the interrupt bits we received */
- LM4_GPIO_ICR(LM4_GPIO_K) = mis;
-
- gpio_interrupt(LM4_GPIO_K, mis);
-}
-DECLARE_IRQ(LM4_IRQ_GPIOK, __gpio_k_interrupt, 1);
-#if !defined(EVT)
static void __gpio_c_interrupt(void)
{
uint32_t mis = LM4_GPIO_MIS(LM4_GPIO_C);
@@ -292,26 +135,9 @@ static void __gpio_c_interrupt(void)
gpio_interrupt(LM4_GPIO_C, mis);
}
DECLARE_IRQ(LM4_IRQ_GPIOC, __gpio_c_interrupt, 1);
-#endif
-
-int gpio_task(void)
-{
- int i;
- timestamp_t ts;
- while (1) {
- usleep(1000);
- ts = get_time();
- for (i = 0; i < DEBOUNCE_ISR_ID_MAX; ++i) {
- if (debounce_isr[i].started &&
- ts.val >= debounce_isr[i].tstamp.val) {
- debounce_isr[i].started = 0;
- debounce_isr[i].callback();
- }
- }
-
- pwrbtn_sm_handle(ts);
- }
+int gpio_init(void)
+{
return EC_SUCCESS;
}
diff --git a/chip/lm4/power_button.c b/chip/lm4/power_button.c
new file mode 100644
index 0000000000..28519b6e5f
--- /dev/null
+++ b/chip/lm4/power_button.c
@@ -0,0 +1,201 @@
+/* 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.
+ */
+
+/* Power button and lid switch module for Chrome EC */
+
+#include "gpio.h"
+#include "power_button.h"
+#include "task.h"
+#include "timer.h"
+#include "uart.h"
+
+enum debounce_isr_id {
+ DEBOUNCE_LID,
+ DEBOUNCE_PWRBTN,
+ DEBOUNCE_ISR_ID_MAX
+};
+
+struct debounce_isr_t {
+ /* TODO: Add a carry bit to indicate timestamp overflow */
+ timestamp_t tstamp;
+ int started;
+ void (*callback)(void);
+};
+
+struct debounce_isr_t debounce_isr[DEBOUNCE_ISR_ID_MAX];
+
+enum power_button_state {
+ PWRBTN_STATE_STOPPED = 0,
+ PWRBTN_STATE_START = 1,
+ PWRBTN_STATE_T0 = 2,
+ PWRBTN_STATE_T1 = 3,
+ PWRBTN_STATE_T2 = 4,
+ PWRBTN_STATE_STOPPING = 5,
+};
+static enum power_button_state pwrbtn_state = PWRBTN_STATE_STOPPED;
+/* The next timestamp to move onto next state if power button is still pressed.
+ */
+static timestamp_t pwrbtn_next_ts = {0};
+static int init_called;
+
+#define PWRBTN_DELAY_T0 32000 /* 32ms */
+#define PWRBTN_DELAY_T1 (4000000 - PWRBTN_DELAY_T0) /* 4 secs - t0 */
+#define PWRBTN_DELAY_T2 4000000 /* 4 secs */
+
+
+static void lid_switch_isr(void)
+{
+ /* TODO: Currently we pass through the LID_SW# pin to R_EC_LID_OUT#
+ * directly. Modify this if we need to consider more conditions. */
+#ifdef BOARD_bds
+ gpio_set_level(EC_GPIO_LID_SWITCH_OUT,
+ gpio_get_level(EC_GPIO_LID_SWITCH));
+#endif
+}
+
+
+/* Power button state machine.
+ *
+ * PWRBTN# --- ----
+ * to EC |______________________|
+ *
+ *
+ * PWRBTN# --- --------- ----
+ * to PCH |__| |___________|
+ * t0 t1 t2
+ */
+static void set_pwrbtn_to_pch(int high)
+{
+#ifdef BOARD_link
+ gpio_set_level(EC_GPIO_POWER_BUTTON_OUT, high);
+#else
+ uart_printf("[%d] set_pwrbtn_to_pch(%s)\n",
+ get_time().le.lo, high ? "HIGH" : "LOW");
+#endif
+}
+
+
+static void pwrbtn_sm_start(void)
+{
+ pwrbtn_state = PWRBTN_STATE_START;
+ pwrbtn_next_ts = get_time(); /* execute action now! */
+}
+
+
+static void pwrbtn_sm_stop(void)
+{
+ pwrbtn_state = PWRBTN_STATE_STOPPING;
+ pwrbtn_next_ts = get_time(); /* execute action now ! */
+}
+
+
+static void pwrbtn_sm_handle(timestamp_t current)
+{
+ /* Not the time to move onto next state */
+ if (pwrbtn_state == PWRBTN_STATE_STOPPED ||
+ current.val < pwrbtn_next_ts.val)
+ return;
+
+ switch (pwrbtn_state) {
+ case PWRBTN_STATE_START:
+ pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T0;
+ pwrbtn_state = PWRBTN_STATE_T0;
+ set_pwrbtn_to_pch(0);
+ break;
+ case PWRBTN_STATE_T0:
+ pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T1;
+ pwrbtn_state = PWRBTN_STATE_T1;
+ set_pwrbtn_to_pch(1);
+ break;
+ case PWRBTN_STATE_T1:
+ pwrbtn_next_ts.val = current.val + PWRBTN_DELAY_T2;
+ pwrbtn_state = PWRBTN_STATE_T2;
+ set_pwrbtn_to_pch(0);
+ break;
+ case PWRBTN_STATE_T2:
+ /* T2 has passed */
+ case PWRBTN_STATE_STOPPING:
+ set_pwrbtn_to_pch(1);
+ pwrbtn_state = PWRBTN_STATE_STOPPED;
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void power_button_isr(void)
+{
+ if (!gpio_get_level(EC_GPIO_POWER_BUTTON)) {
+ /* pressed */
+ pwrbtn_sm_start();
+ /* TODO: implement after chip/lm4/x86_power.c is completed. */
+ /* if system is in S5, power_on_system()
+ * elif system is in S3, resume_system()
+ * else S0 i8042_send_host(make_code); */
+ } else {
+ /* released */
+ pwrbtn_sm_stop();
+ /* TODO: implement after chip/lm4/x86_power.c is completed. */
+ /* if system in S0, i8042_send_host(break_code); */
+ }
+}
+
+
+void power_button_interrupt(enum gpio_signal signal)
+{
+ timestamp_t timelimit;
+ int d = (signal == EC_GPIO_LID_SWITCH ? DEBOUNCE_LID : DEBOUNCE_PWRBTN);
+
+ /* TODO: (crosbug.com/p/7456) there's currently a race condition where
+ * we can get an interrupt before clock_init() has been called. In
+ * this case, get_time crashes(). Work around this by checking if our
+ * init has been called and ignoring interrupts if so. */
+ if (!init_called)
+ return;
+
+ /* Set 30 ms debounce timelimit */
+ timelimit = get_time();
+ timelimit.val += 30000;
+
+ /* Handle lid switch and power button debounce */
+ debounce_isr[d].tstamp = timelimit;
+ debounce_isr[d].started = 1;
+}
+
+
+int power_button_init(void)
+{
+ debounce_isr[DEBOUNCE_LID].started = 0;
+ debounce_isr[DEBOUNCE_LID].callback = lid_switch_isr;
+ debounce_isr[DEBOUNCE_PWRBTN].started = 0;
+ debounce_isr[DEBOUNCE_PWRBTN].callback = power_button_isr;
+
+ init_called = 1;
+
+ return EC_SUCCESS;
+}
+
+
+void power_button_task(void)
+{
+ int i;
+ timestamp_t ts;
+
+ while (1) {
+ usleep(1000);
+ ts = get_time();
+ for (i = 0; i < DEBOUNCE_ISR_ID_MAX; ++i) {
+ if (debounce_isr[i].started &&
+ ts.val >= debounce_isr[i].tstamp.val) {
+ debounce_isr[i].started = 0;
+ debounce_isr[i].callback();
+ }
+ }
+
+ pwrbtn_sm_handle(ts);
+ }
+}
+
diff --git a/common/main.c b/common/main.c
index 47f3e0f0e9..c2c71fd67a 100644
--- a/common/main.c
+++ b/common/main.c
@@ -21,6 +21,7 @@
#include "lpc.h"
#include "memory_commands.h"
#include "port80.h"
+#include "power_button.h"
#include "powerdemo.h"
#include "pwm.h"
#include "pwm_commands.h"
@@ -81,6 +82,7 @@ int main(void)
i2c_init();
temp_sensor_init();
memory_commands_init();
+ power_button_init();
keyboard_init();
adc_init();
diff --git a/include/gpio.h b/include/gpio.h
index 5e4edf0593..54ea231dba 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -12,12 +12,13 @@
/* GPIO signal definitions. */
enum gpio_signal {
- /* Firmware write protect */
- EC_GPIO_WRITE_PROTECT = 0,
- /* Recovery switch */
- EC_GPIO_RECOVERY_SWITCH,
- /* Debug LED */
- EC_GPIO_DEBUG_LED
+ EC_GPIO_DEBUG_LED = 0, /* Debug LED */
+ EC_GPIO_POWER_BUTTON, /* Power button */
+ EC_GPIO_POWER_BUTTON_OUT, /* Power button output to PCH */
+ EC_GPIO_LID_SWITCH, /* Lid switch */
+ EC_GPIO_LID_SWITCH_OUT, /* Lid switch output to PCH */
+ /* Number of GPIOs; not an actual GPIO */
+ EC_GPIO_COUNT
};
diff --git a/include/power_button.h b/include/power_button.h
new file mode 100644
index 0000000000..c6cf4f4e24
--- /dev/null
+++ b/include/power_button.h
@@ -0,0 +1,24 @@
+/* Copyright (c) 2011 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.
+ */
+
+/* Power button module for Chrome EC */
+
+#ifndef __CROS_EC_POWER_BUTTON_H
+#define __CROS_EC_POWER_BUTTON_H
+
+#include "common.h"
+#include "gpio.h"
+
+/* Initializes the module. */
+int power_button_init(void);
+
+/* Interrupt handler for the power button and lid switch. Passed the signal
+ * which triggered the interrupt. */
+void power_button_interrupt(enum gpio_signal signal);
+
+/* Power button task */
+void power_button_task(void);
+
+#endif /* __CROS_EC_POWER_BUTTON_H */