summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrover Yen <Grover_Yen@wistron.com>2014-12-26 19:45:53 +0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-07 06:09:05 +0000
commit50f1e1aa326fd947ca34be5f9f08d2937302823f (patch)
treec036b6b7eef3bef5590aa6b3d91c16d41b80cfd3
parentd93e502f016c9d824c3d90775084dd6568500450 (diff)
downloadchrome-ec-50f1e1aa326fd947ca34be5f9f08d2937302823f.tar.gz
lulu: Initial board
Copy from auron with string changes. BUG=none BRANCH=none TEST=make -j buildall, make -j tests Change-Id: Ib9c894a7a06cd3840a66c448c49c848a8abc27b2 Signed-off-by: Grover Yen <Grover_Yen@wistron.com> Reviewed-on: https://chromium-review.googlesource.com/237686 Reviewed-by: Mohammed Habibulla <moch@chromium.org>
l---------board/lulu/Makefile1
-rw-r--r--board/lulu/battery.c42
-rw-r--r--board/lulu/board.c133
-rw-r--r--board/lulu/board.h115
-rw-r--r--board/lulu/build.mk12
-rw-r--r--board/lulu/ec.tasklist27
-rw-r--r--board/lulu/gpio.inc101
-rw-r--r--board/lulu/led.c186
8 files changed, 617 insertions, 0 deletions
diff --git a/board/lulu/Makefile b/board/lulu/Makefile
new file mode 120000
index 0000000000..94aaae2c4d
--- /dev/null
+++ b/board/lulu/Makefile
@@ -0,0 +1 @@
+../../Makefile \ No newline at end of file
diff --git a/board/lulu/battery.c b/board/lulu/battery.c
new file mode 100644
index 0000000000..fbd4fb3f0a
--- /dev/null
+++ b/board/lulu/battery.c
@@ -0,0 +1,42 @@
+/* Copyright (c) 2014 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.
+ *
+ * Battery pack vendor provided charging profile
+ */
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "gpio.h"
+#include "host_command.h"
+
+#define SB_SHIP_MODE_ADDR 0x3a
+#define SB_SHIP_MODE_DATA 0xc574
+
+/* Values for 54Wh 3UPF656790-1-T1001 battery */
+static const struct battery_info info = {
+
+ .voltage_max = 12600,
+ .voltage_normal = 11100, /* Average of max & min */
+ .voltage_min = 9000,
+
+ /* Pre-charge values. */
+ .precharge_current = 392, /* mA */
+
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 60,
+ .charging_min_c = 0,
+ .charging_max_c = 60,
+ .discharging_min_c = 0,
+ .discharging_max_c = 50,
+};
+
+const struct battery_info *battery_get_info(void)
+{
+ return &info;
+}
+
+int board_cut_off_battery(void)
+{
+ return sb_write(SB_SHIP_MODE_ADDR, SB_SHIP_MODE_DATA);
+}
diff --git a/board/lulu/board.c b/board/lulu/board.c
new file mode 100644
index 0000000000..0f36360450
--- /dev/null
+++ b/board/lulu/board.c
@@ -0,0 +1,133 @@
+/* Copyright (c) 2014 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.
+ */
+/* EC for lulu board configuration */
+
+#include "adc.h"
+#include "adc_chip.h"
+#include "backlight.h"
+#include "chipset.h"
+#include "common.h"
+#include "driver/temp_sensor/g781.h"
+#include "extpower.h"
+#include "fan.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "jtag.h"
+#include "keyboard_scan.h"
+#include "lid_switch.h"
+#include "peci.h"
+#include "power.h"
+#include "power_button.h"
+#include "registers.h"
+#include "switch.h"
+#include "temp_sensor.h"
+#include "temp_sensor_chip.h"
+#include "thermal.h"
+#include "timer.h"
+#include "uart.h"
+#include "util.h"
+
+#include "gpio_list.h"
+
+/* power signal list. Must match order of enum power_signal. */
+const struct power_signal_info power_signal_list[] = {
+ {GPIO_PP5000_PGOOD, 1, "PGOOD_PP5000"},
+ {GPIO_PP1350_PGOOD, 1, "PGOOD_PP1350"},
+ {GPIO_PP1050_PGOOD, 1, "PGOOD_PP1050"},
+ {GPIO_VCORE_PGOOD, 1, "PGOOD_VCORE"},
+ {GPIO_PCH_SLP_S0_L, 1, "SLP_S0#_DEASSERTED"},
+ {GPIO_PCH_SLP_S3_L, 1, "SLP_S3#_DEASSERTED"},
+ {GPIO_PCH_SLP_S5_L, 1, "SLP_S5#_DEASSERTED"},
+ {GPIO_PCH_SLP_SUS_L, 1, "SLP_SUS#_DEASSERTED"},
+};
+BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+
+/* ADC channels. Must be in the exactly same order as in enum adc_channel. */
+const struct adc_t adc_channels[] = {
+ /* EC internal temperature is calculated by
+ * 273 + (295 - 450 * ADC_VALUE / ADC_READ_MAX) / 2
+ * = -225 * ADC_VALUE / ADC_READ_MAX + 420.5
+ */
+ {"ECTemp", LM4_ADC_SEQ0, -225, ADC_READ_MAX, 420,
+ LM4_AIN_NONE, 0x0e /* TS0 | IE0 | END0 */, 0, 0},
+
+ /* IOUT == ICMNT is on PE3/AIN0 */
+ /* We have 0.01-ohm resistors, and IOUT is 20X the differential
+ * voltage, so 1000mA ==> 200mV.
+ * ADC returns 0x000-0xFFF, which maps to 0.0-3.3V (as configured).
+ * mA = 1000 * ADC_VALUE / ADC_READ_MAX * 3300 / 200
+ */
+ {"ChargerCurrent", LM4_ADC_SEQ1, 33000, ADC_READ_MAX * 2, 0,
+ LM4_AIN(0), 0x06 /* IE0 | END0 */, LM4_GPIO_E, (1<<3)},
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* Physical fans. These are logically separate from pwm_channels. */
+const struct fan_t fans[] = {
+ {.flags = FAN_USE_RPM_MODE,
+ .rpm_min = 1000,
+ .rpm_max = 5050,
+ .ch = 2,
+ .pgood_gpio = GPIO_PP5000_PGOOD,
+ .enable_gpio = GPIO_PP5000_FAN_EN,
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(fans) == CONFIG_FANS);
+
+/* I2C ports */
+const struct i2c_port_t i2c_ports[] = {
+ {"batt_chg", 0, 100},
+ {"thermal", 5, 100},
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+/* Temperature sensors data; must be in same order as enum temp_sensor_id. */
+const struct temp_sensor_t temp_sensors[] = {
+ {"PECI", TEMP_SENSOR_TYPE_CPU, peci_temp_sensor_get_val, 0, 2},
+ {"ECInternal", TEMP_SENSOR_TYPE_BOARD, chip_temp_sensor_get_val, 0, 4},
+ {"G781Internal", TEMP_SENSOR_TYPE_BOARD, g781_get_val,
+ G781_IDX_INTERNAL, 4},
+ {"G781External", TEMP_SENSOR_TYPE_BOARD, g781_get_val,
+ G781_IDX_EXTERNAL, 4},
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/* Thermal limits for each temp sensor. All temps are in degrees K. Must be in
+ * same order as enum temp_sensor_id. To always ignore any temp, use 0.
+ */
+struct ec_thermal_config thermal_params[] = {
+ /* Only the AP affects the thermal limits and fan speed. */
+ {{C_TO_K(95), C_TO_K(97), C_TO_K(99)}, C_TO_K(55), C_TO_K(85)},
+ {{0, 0, 0}, 0, 0},
+ {{0, 0, 0}, 0, 0},
+ {{0, 0, 0}, 0, 0},
+};
+BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
+
+struct keyboard_scan_config keyscan_config = {
+ .output_settle_us = 40,
+ .debounce_down_us = 6 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 1500,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = SECOND,
+ .actual_key_mask = {
+ 0x14, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
+ 0xa4, 0xff, 0xf6, 0x55, 0xfa, 0xca /* full set */
+ },
+};
+
+/**
+ * Discharge battery when on AC power for factory test.
+ */
+int board_discharge_on_ac(int enable)
+{
+ if (enable)
+ gpio_set_level(GPIO_CHARGE_L, 1);
+ else
+ gpio_set_level(GPIO_CHARGE_L, 0);
+ return EC_SUCCESS;
+}
diff --git a/board/lulu/board.h b/board/lulu/board.h
new file mode 100644
index 0000000000..a69e9b9978
--- /dev/null
+++ b/board/lulu/board.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Configuration for lulu mainboard */
+
+#ifndef __BOARD_H
+#define __BOARD_H
+
+/* Optional features */
+#define CONFIG_BACKLIGHT_LID
+#define CONFIG_BACKLIGHT_REQ_GPIO GPIO_PCH_BKLTEN
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_PRESENT_GPIO GPIO_BAT_PRESENT_L
+#define CONFIG_BATTERY_SMART
+#define CONFIG_BOARD_VERSION
+#define CONFIG_CHARGER
+#define CONFIG_CHARGER_V1
+#define CONFIG_CHARGER_BQ24707A
+#define CONFIG_CHARGER_DISCHARGE_ON_AC
+#define CONFIG_CHIPSET_CAN_THROTTLE
+#define CONFIG_CHIPSET_HASWELL
+#define CONFIG_POWER_COMMON
+#define CONFIG_CMD_GSV
+#define CONFIG_EXTPOWER_GPIO
+#define CONFIG_FANS 1
+#define CONFIG_KEYBOARD_BOARD_CONFIG
+#define CONFIG_KEYBOARD_PROTOCOL_8042
+#define CONFIG_LED_COMMON
+#define CONFIG_LOW_POWER_IDLE
+#define CONFIG_PECI_TJMAX 100
+#define CONFIG_POWER_BUTTON
+#define CONFIG_POWER_BUTTON_X86
+#define CONFIG_SWITCH_DEDICATED_RECOVERY
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_G781
+#define CONFIG_TEMP_SENSOR_POWER_GPIO GPIO_PP3300_DX_EN
+#define CONFIG_UART_HOST 2
+#define CONFIG_USB_PORT_POWER_DUMB
+#define CONFIG_VBOOT_HASH
+#define CONFIG_WIRELESS
+
+#ifndef __ASSEMBLER__
+
+/* I2C ports */
+#define I2C_PORT_BATTERY 0
+#define I2C_PORT_CHARGER 0
+#define I2C_PORT_THERMAL 5
+
+/* 13x8 keyboard scanner uses an entire GPIO bank for row inputs */
+#define KB_SCAN_ROW_IRQ LM4_IRQ_GPIOK
+#define KB_SCAN_ROW_GPIO LM4_GPIO_K
+
+/* Host connects to keyboard controller module via LPC */
+#define HOST_KB_BUS_LPC
+
+/* USB ports */
+#define USB_PORT_COUNT 2
+
+#include "gpio_signal.h"
+
+/* power signal definitions */
+enum power_signal {
+ X86_PGOOD_PP5000 = 0,
+ X86_PGOOD_PP1350,
+ X86_PGOOD_PP1050,
+ X86_PGOOD_VCORE,
+ X86_SLP_S0_DEASSERTED,
+ X86_SLP_S3_DEASSERTED,
+ X86_SLP_S5_DEASSERTED,
+ X86_SLP_SUS_DEASSERTED,
+
+ /* Number of X86 signals */
+ POWER_SIGNAL_COUNT
+};
+
+/* Charger module */
+#define CONFIG_CHARGER_SENSE_RESISTOR 10 /* Charge sense resistor, mOhm */
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10 /* Input sensor resistor, mOhm */
+#define CONFIG_CHARGER_INPUT_CURRENT 3078 /* mA, 90% of power supply rating */
+
+enum adc_channel {
+ /* EC internal die temperature in degrees K. */
+ ADC_CH_EC_TEMP = 0,
+
+ /* Charger current in mA. */
+ ADC_CH_CHARGER_CURRENT,
+
+ ADC_CH_COUNT
+};
+
+enum temp_sensor_id {
+ /* CPU die temperature via PECI */
+ TEMP_SENSOR_CPU_PECI = 0,
+ /* EC internal temperature sensor */
+ TEMP_SENSOR_EC_INTERNAL,
+ /* G781 internal and external sensors */
+ TEMP_SENSOR_I2C_G781_INTERNAL,
+ TEMP_SENSOR_I2C_G781_EXTERNAL,
+
+ TEMP_SENSOR_COUNT
+};
+
+/* Wireless signals */
+#define WIRELESS_GPIO_WLAN GPIO_WLAN_OFF_L
+#define WIRELESS_GPIO_WWAN GPIO_PP3300_LTE_EN
+#define WIRELESS_GPIO_WLAN_POWER GPIO_PP3300_WLAN_EN
+
+/* Discharge battery when on AC power for factory test. */
+int board_discharge_on_ac(int enable);
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __BOARD_H */
diff --git a/board/lulu/build.mk b/board/lulu/build.mk
new file mode 100644
index 0000000000..887e527d1b
--- /dev/null
+++ b/board/lulu/build.mk
@@ -0,0 +1,12 @@
+# -*- makefile -*-
+# Copyright (c) 2014 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.
+#
+# Board specific files build
+#
+
+# the IC is TI Stellaris LM4
+CHIP:=lm4
+
+board-y=board.o battery.o led.o
diff --git a/board/lulu/ec.tasklist b/board/lulu/ec.tasklist
new file mode 100644
index 0000000000..ef036ad8f9
--- /dev/null
+++ b/board/lulu/ec.tasklist
@@ -0,0 +1,27 @@
+/* Copyright 2014 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.
+ */
+
+/**
+ * List of enabled tasks in the priority order
+ *
+ * The first one has the lowest priority.
+ *
+ * For each task, use the macro TASK_ALWAYS(n, r, d, s) for base tasks and
+ * TASK_NOTEST(n, r, d, s) for tasks that can be excluded in test binaries,
+ * where :
+ * 'n' is the name of the task
+ * 'r' is the main routine of the task
+ * 'd' is an opaque parameter passed to the routine at startup
+ * 's' is the stack size in bytes; must be a multiple of 8
+ */
+#define CONFIG_TASK_LIST \
+ TASK_ALWAYS(HOOKS, hook_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CHARGER, charger_task, NULL, TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE)
diff --git a/board/lulu/gpio.inc b/board/lulu/gpio.inc
new file mode 100644
index 0000000000..3e275ec397
--- /dev/null
+++ b/board/lulu/gpio.inc
@@ -0,0 +1,101 @@
+/* -*- mode:c -*-
+ *
+ * Copyright (c) 2014 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.
+ */
+
+/* Inputs with interrupt handlers are first for efficiency */
+GPIO(POWER_BUTTON_L, A, 2, GPIO_INT_BOTH_DSLEEP, power_button_interrupt) /* Power button */
+GPIO(LID_OPEN, A, 3, GPIO_INT_BOTH_DSLEEP, lid_interrupt) /* Lid switch */
+GPIO(AC_PRESENT, H, 3, GPIO_INT_BOTH_DSLEEP, extpower_interrupt) /* AC power present */
+GPIO(PCH_BKLTEN, M, 3, GPIO_INT_BOTH, backlight_interrupt) /* Backlight enable signal from PCH */
+GPIO(PCH_SLP_S0_L, G, 6, GPIO_INT_BOTH, power_signal_interrupt) /* SLP_S0# signal from PCH */
+GPIO(PCH_SLP_S3_L, G, 7, GPIO_INT_BOTH_DSLEEP, power_signal_interrupt) /* SLP_S3# signal from PCH */
+GPIO(PCH_SLP_S5_L, H, 1, GPIO_INT_BOTH_DSLEEP, power_signal_interrupt) /* SLP_S5# signal from PCH */
+GPIO(PCH_SLP_SUS_L, G, 3, GPIO_INT_BOTH, power_signal_interrupt) /* SLP_SUS# signal from PCH */
+GPIO(PP1050_PGOOD, H, 4, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 1.05V */
+GPIO(PP1350_PGOOD, H, 6, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 1.35V (DRAM) */
+GPIO(PP5000_PGOOD, N, 0, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on 5V */
+GPIO(VCORE_PGOOD, C, 6, GPIO_INT_BOTH, power_signal_interrupt) /* Power good on core VR */
+GPIO(PCH_EDP_VDD_EN, J, 1, GPIO_INT_BOTH, power_interrupt) /* PCH wants EDP enabled */
+GPIO(RECOVERY_L, A, 5, GPIO_PULL_UP | GPIO_INT_BOTH, switch_interrupt) /* Recovery signal from servo */
+GPIO(WP_L, A, 4, GPIO_INT_BOTH, switch_interrupt) /* Write protect input */
+GPIO(JTAG_TCK, C, 0, GPIO_DEFAULT, jtag_interrupt) /* JTAG clock input */
+GPIO(UART0_RX, A, 0, GPIO_PULL_UP | GPIO_INT_BOTH_DSLEEP, uart_deepsleep_interrupt) /* UART0 RX input */
+
+/* Other inputs */
+GPIO(FAN_ALERT_L, B, 0, GPIO_INPUT, NULL) /* From thermal sensor */
+GPIO(PCH_SUSWARN_L, G, 2, GPIO_INT_BOTH, NULL) /* SUSWARN# signal from PCH */
+GPIO(USB1_OC_L, E, 7, GPIO_INPUT, NULL) /* USB port overcurrent warning */
+GPIO(USB2_OC_L, E, 0, GPIO_INPUT, NULL) /* USB port overcurrent warning */
+GPIO(BOARD_VERSION1, Q, 5, GPIO_INPUT, NULL) /* Board version stuffing resistor 1 */
+GPIO(BOARD_VERSION2, Q, 6, GPIO_INPUT, NULL) /* Board version stuffing resistor 2 */
+GPIO(BOARD_VERSION3, Q, 7, GPIO_INPUT, NULL) /* Board version stuffing resistor 3 */
+GPIO(CPU_PGOOD, C, 4, GPIO_INPUT, NULL) /* Power good to the CPU */
+GPIO(BAT_PRESENT_L, B, 4, GPIO_INPUT, NULL) /* Battery present. Repurposed BAT_TEMP */
+
+/* Outputs; all unasserted by default except for reset signals */
+GPIO(CPU_PROCHOT, B, 1, GPIO_OUT_LOW, NULL) /* Force CPU to think it's overheated */
+GPIO(PP1350_EN, H, 5, GPIO_OUT_LOW, NULL) /* Enable 1.35V supply */
+GPIO(PP3300_DX_EN, J, 2, GPIO_OUT_LOW, NULL) /* Enable power to lots of peripherals */
+GPIO(PP3300_LTE_EN, D, 2, GPIO_OUT_LOW, NULL) /* Enable LTE radio */
+GPIO(PP3300_WLAN_EN, J, 0, GPIO_OUT_LOW, NULL) /* Enable WiFi power */
+GPIO(SUSP_VR_EN, C, 7, GPIO_OUT_LOW, NULL) /* Enable 1.05V regulator */
+GPIO(VCORE_EN, C, 5, GPIO_OUT_LOW, NULL) /* Stuffing option - not connected */
+GPIO(PP5000_EN, H, 7, GPIO_OUT_LOW, NULL) /* Enable 5V supply */
+GPIO(PP5000_FAN_EN, J, 3, GPIO_OUT_LOW, NULL) /* Enable fan power rail */
+GPIO(SYS_PWROK, H, 2, GPIO_OUT_LOW, NULL) /* EC thinks everything is up and ready */
+GPIO(WLAN_OFF_L, J, 4, GPIO_OUT_LOW, NULL) /* Disable WiFi radio */
+GPIO(CHARGE_L, E, 6, GPIO_OUT_LOW, NULL) /* Allow battery to charge when on AC */
+
+GPIO(ENABLE_BACKLIGHT, M, 7, GPIO_OUT_LOW, NULL) /* Enable backlight power */
+GPIO(ENABLE_TOUCHPAD, N, 1, GPIO_OUT_LOW, NULL) /* Enable touchpad power */
+GPIO(ENTERING_RW, D, 3, GPIO_OUT_LOW, NULL) /* Indicate when EC is entering RW code */
+GPIO(PCH_DPWROK, G, 0, GPIO_OUT_LOW, NULL) /* Indicate when VccDSW is good */
+
+/*
+ * HDA_SDO is technically an output, but we need to leave it as an
+ * input until we drive it high. So can't use open-drain (HI_Z).
+ */
+GPIO(PCH_HDA_SDO, G, 1, GPIO_INPUT, NULL) /* HDA_SDO signal to PCH; when high, ME ignores security descriptor */
+GPIO(PCH_WAKE_L, F, 0, GPIO_OUT_HIGH, NULL) /* Wake signal from EC to PCH */
+GPIO(PCH_NMI_L, F, 2, GPIO_OUT_HIGH, NULL) /* Non-maskable interrupt pin to PCH */
+GPIO(PCH_PWRBTN_L, H, 0, GPIO_OUT_HIGH, NULL) /* Power button output to PCH */
+GPIO(PCH_PWROK, F, 5, GPIO_OUT_LOW, NULL) /* PWROK / APWROK signals to PCH */
+
+/*
+ * PL6 is one of 4 pins on the EC which can't be used in open-drain
+ * mode. To work around this PCH_RCIN_L is set to an input. It will
+ * only be set to an output when it needs to be driven to 0.
+ */
+GPIO(PCH_RCIN_L, L, 6, GPIO_INPUT, NULL) /* RCIN# line to PCH (for 8042 emulation) */
+GPIO(PCH_RSMRST_L, F, 1, GPIO_OUT_LOW, NULL) /* Reset PCH resume power plane logic */
+GPIO(PCH_SMI_L, F, 4, GPIO_ODR_HIGH, NULL) /* System management interrupt to PCH */
+GPIO(TOUCHSCREEN_RESET_L, N, 7, GPIO_OUT_LOW, NULL) /* Reset touch screen */
+GPIO(EC_EDP_VDD_EN, J, 5, GPIO_OUT_LOW, NULL) /* Enable EDP (passthru from PCH) */
+
+GPIO(LPC_CLKRUN_L, M, 2, GPIO_ODR_HIGH, NULL) /* Dunno. Probably important, though. */
+GPIO(USB1_ENABLE, E, 4, GPIO_OUT_LOW, NULL) /* USB port 1 output power enable */
+GPIO(USB2_ENABLE, D, 5, GPIO_OUT_LOW, NULL) /* USB port 2 output power enable */
+
+GPIO(PCH_SUSACK_L, F, 3, GPIO_OUT_HIGH, NULL) /* Acknowledge PCH SUSWARN# signal */
+GPIO(PCH_RTCRST_L, F, 6, GPIO_ODR_HIGH, NULL) /* Not supposed to be here */
+GPIO(PCH_SRTCRST_L, F, 7, GPIO_ODR_HIGH, NULL) /* Not supposed to be here */
+
+GPIO(BAT_LED0_L, D, 0, GPIO_ODR_HIGH, NULL) /* Battery charging LED - blue */
+GPIO(BAT_LED1_L, N, 4, GPIO_ODR_HIGH, NULL) /* Battery charging LED - orange */
+GPIO(PWR_LED0_L, D, 1, GPIO_ODR_HIGH, NULL) /* Power LED - blue */
+GPIO(PWR_LED1_L, N, 6, GPIO_ODR_HIGH, NULL) /* Power LED - orange */
+
+ALTERNATE(A, 0x03, 1, MODULE_UART, GPIO_PULL_UP) /* UART0 */
+ALTERNATE(B, 0x04, 3, MODULE_I2C, 0) /* I2C0 SCL */
+ALTERNATE(B, 0x08, 3, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C0 SDA */
+ALTERNATE(B, 0x40, 3, MODULE_I2C, 0) /* I2C5 SCL */
+ALTERNATE(B, 0x80, 3, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C5 SDA */
+ALTERNATE(G, 0x30, 1, MODULE_UART, 0) /* UART2 */
+ALTERNATE(J, 0x40, 1, MODULE_PECI, 0) /* PECI Tx */
+ALTERNATE(J, 0x80, 0, MODULE_PECI, GPIO_ANALOG) /* PECI Rx */
+ALTERNATE(L, 0x3f, 15, MODULE_LPC, 0) /* LPC */
+ALTERNATE(M, 0x33, 15, MODULE_LPC, 0) /* LPC */
+ALTERNATE(N, 0x0c, 1, MODULE_PWM_FAN, 0) /* FAN0PWM2 */
diff --git a/board/lulu/led.c b/board/lulu/led.c
new file mode 100644
index 0000000000..cd89f1221b
--- /dev/null
+++ b/board/lulu/led.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2014 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 and battery LED control for lulu.
+ */
+
+#include "battery.h"
+#include "charge_state.h"
+#include "chipset.h"
+#include "ec_commands.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "led_common.h"
+#include "util.h"
+
+#define LED_TOTAL_TICKS 16
+#define LED_ON_TICKS 4
+
+enum led_color {
+ LED_OFF = 0,
+ LED_BLUE,
+ LED_AMBER,
+ LED_PINK,
+
+ LED_COLOR_COUNT /* Number of colors, not a color itself */
+};
+
+const enum ec_led_id supported_led_ids[] = {
+ EC_LED_ID_POWER_LED, EC_LED_ID_BATTERY_LED};
+
+const int supported_led_ids_count = ARRAY_SIZE(supported_led_ids);
+
+static int lulu_led_set_gpio(enum led_color color,
+ enum gpio_signal gpio_led_blue_l,
+ enum gpio_signal gpio_led_amber_l)
+{
+ switch (color) {
+ case LED_OFF:
+ gpio_set_level(gpio_led_blue_l, 1);
+ gpio_set_level(gpio_led_amber_l, 1);
+ break;
+ case LED_BLUE:
+ gpio_set_level(gpio_led_blue_l, 0);
+ gpio_set_level(gpio_led_amber_l, 1);
+ break;
+ case LED_AMBER:
+ gpio_set_level(gpio_led_blue_l, 1);
+ gpio_set_level(gpio_led_amber_l, 0);
+ break;
+ case LED_PINK:
+ gpio_set_level(gpio_led_blue_l, 0);
+ gpio_set_level(gpio_led_amber_l, 0);
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+ return EC_SUCCESS;
+}
+
+static int lulu_led_set_color_battery(enum led_color color)
+{
+ return lulu_led_set_gpio(color, GPIO_BAT_LED0_L, GPIO_BAT_LED1_L);
+}
+
+static int lulu_led_set_color_power(enum led_color color)
+{
+ return lulu_led_set_gpio(color, GPIO_PWR_LED0_L, GPIO_PWR_LED1_L);
+}
+
+static int lulu_led_set_color(enum ec_led_id led_id, enum led_color color)
+{
+ int rv;
+
+ led_auto_control(led_id, 0);
+ switch (led_id) {
+ case EC_LED_ID_BATTERY_LED:
+ rv = lulu_led_set_color_battery(color);
+ break;
+ case EC_LED_ID_POWER_LED:
+ rv = lulu_led_set_color_power(color);
+ break;
+ default:
+ return EC_ERROR_UNKNOWN;
+ }
+ return rv;
+}
+
+int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
+{
+ if (brightness[EC_LED_COLOR_BLUE] != 0 &&
+ brightness[EC_LED_COLOR_YELLOW] != 0)
+ lulu_led_set_color(led_id, LED_PINK);
+ else if (brightness[EC_LED_COLOR_BLUE] != 0)
+ lulu_led_set_color(led_id, LED_BLUE);
+ else if (brightness[EC_LED_COLOR_YELLOW] != 0)
+ lulu_led_set_color(led_id, LED_AMBER);
+ else
+ lulu_led_set_color(led_id, LED_OFF);
+
+ return EC_SUCCESS;
+}
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ /* Ignoring led_id as both leds support the same colors */
+ brightness_range[EC_LED_COLOR_BLUE] = 1;
+ brightness_range[EC_LED_COLOR_YELLOW] = 1;
+}
+
+static void lulu_led_set_power(void)
+{
+ static int power_ticks;
+ static int previous_state_suspend;
+
+ power_ticks++;
+
+ if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
+ /* Reset ticks if entering suspend so LED turns amber
+ * as soon as possible. */
+ if (!previous_state_suspend)
+ power_ticks = 0;
+
+ /* Blink once every four seconds. */
+ lulu_led_set_color_power(
+ (power_ticks % LED_TOTAL_TICKS < LED_ON_TICKS) ?
+ LED_AMBER : LED_OFF);
+
+ previous_state_suspend = 1;
+ return;
+ }
+
+ previous_state_suspend = 0;
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ lulu_led_set_color_power(LED_OFF);
+ else if (chipset_in_state(CHIPSET_STATE_ON))
+ lulu_led_set_color_power(LED_BLUE);
+}
+
+static void lulu_led_set_battery(void)
+{
+ static int battery_ticks;
+ uint32_t chflags = charge_get_flags();
+
+ battery_ticks++;
+
+ switch (charge_get_state()) {
+ case PWR_STATE_CHARGE:
+ lulu_led_set_color_battery(LED_AMBER);
+ break;
+ case PWR_STATE_CHARGE_NEAR_FULL:
+ lulu_led_set_color_battery(LED_BLUE);
+ break;
+ case PWR_STATE_DISCHARGE:
+ lulu_led_set_color_battery(LED_OFF);
+ break;
+ case PWR_STATE_ERROR:
+ lulu_led_set_color_battery(
+ (battery_ticks % LED_TOTAL_TICKS < LED_ON_TICKS) ?
+ LED_AMBER : LED_OFF);
+ break;
+ case PWR_STATE_IDLE: /* External power connected in IDLE. */
+ if (chflags & CHARGE_FLAG_FORCE_IDLE)
+ lulu_led_set_color_battery(
+ (battery_ticks & 0x4) ? LED_BLUE : LED_OFF);
+ else
+ lulu_led_set_color_battery(LED_BLUE);
+ break;
+ default:
+ /* Other states don't alter LED behavior */
+ break;
+ }
+}
+
+/* Called by hook task every 250mSec */
+static void led_tick(void)
+{
+ if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED))
+ lulu_led_set_power();
+
+ if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED))
+ lulu_led_set_battery();
+}
+DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);