summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYH Lin <yueherngl@google.com>2017-04-21 14:46:23 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2017-04-22 00:57:52 +0000
commit547b8de07745392dbfc47645769fa6cf03ed4a38 (patch)
treece7b82cd3b794c26ad6701d35769f3eb381c449a
parent7052b22aeae1227a8c268fcd81dca201e9ca3bee (diff)
downloadchrome-ec-547b8de07745392dbfc47645769fa6cf03ed4a38.tar.gz
strago: fix builder errors
The builders for firmware-cyan-7287.57.B branch (pre-flight and strago) have failed due to the removal of board/strago directory (CL:359322). Therefore restoring this directory and adding gyro_l3gd20h files from firmware-strago-7287.B:5399a6245d2dc21c2234f0d908032ab7fa6ac6e7 to get the builders working again. BRANCH=firmware-cyan-7287.57.B BUG=None TEST=./cbuildbot --local strago-pre-flight-branch TEST=./cbuildbot --local strago-firmware Change-Id: I495a10e4150775fbb2942a73a1eabb19d47ae968 Signed-off-by: YH Lin <yueherngl@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/484744
l---------board/strago/Makefile1
-rw-r--r--board/strago/battery.c43
-rw-r--r--board/strago/board.c227
-rw-r--r--board/strago/board.h165
-rw-r--r--board/strago/build.mk14
-rw-r--r--board/strago/ec.tasklist29
-rw-r--r--board/strago/gpio.inc150
-rw-r--r--board/strago/led.c210
-rw-r--r--board/strago/lfw/gpio.inc16
-rw-r--r--driver/gyro_l3gd20h.c439
-rw-r--r--driver/gyro_l3gd20h.h102
11 files changed, 1396 insertions, 0 deletions
diff --git a/board/strago/Makefile b/board/strago/Makefile
new file mode 120000
index 0000000000..94aaae2c4d
--- /dev/null
+++ b/board/strago/Makefile
@@ -0,0 +1 @@
+../../Makefile \ No newline at end of file
diff --git a/board/strago/battery.c b/board/strago/battery.c
new file mode 100644
index 0000000000..43fa956ced
--- /dev/null
+++ b/board/strago/battery.c
@@ -0,0 +1,43 @@
+/* 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.
+ *
+ * Battery pack vendor provided charging profile
+ */
+
+#include "battery.h"
+#include "battery_smart.h"
+
+/* Shutdown mode parameter to write to manufacturer access register */
+#define SB_SHUTDOWN_DATA 0x0010
+
+static const struct battery_info info = {
+ .voltage_max = 8700,/* mV */
+ .voltage_normal = 7600,
+ .voltage_min = 6000,
+ .precharge_current = 150,/* mA */
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 45,
+ .charging_min_c = 0,
+ .charging_max_c = 45,
+ .discharging_min_c = -20,
+ .discharging_max_c = 60,
+};
+
+const struct battery_info *battery_get_info(void)
+{
+ return &info;
+}
+
+int board_cut_off_battery(void)
+{
+ int rv;
+
+ /* Ship mode command must be sent twice to take effect */
+ rv = sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+
+ if (rv != EC_SUCCESS)
+ return rv;
+
+ return sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+}
diff --git a/board/strago/board.c b/board/strago/board.c
new file mode 100644
index 0000000000..c749d809ac
--- /dev/null
+++ b/board/strago/board.c
@@ -0,0 +1,227 @@
+/* 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.
+ */
+/* Strago board-specific configuration */
+
+#include "adc.h"
+#include "als.h"
+#include "button.h"
+#include "charger.h"
+#include "charge_state.h"
+#include "driver/accel_kionix.h"
+#include "driver/als_isl29035.h"
+#include "driver/gyro_l3gd20h.h"
+#include "driver/temp_sensor/tmp432.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "lid_switch.h"
+#include "math_util.h"
+#include "motion_lid.h"
+#include "motion_sense.h"
+#include "power.h"
+#include "power_button.h"
+#include "pwm.h"
+#include "pwm_chip.h"
+#include "registers.h"
+#include "temp_sensor.h"
+#include "temp_sensor_chip.h"
+#include "thermal.h"
+#include "uart.h"
+#include "util.h"
+
+#define GPIO_KB_INPUT (GPIO_INPUT | GPIO_PULL_UP)
+#define GPIO_KB_OUTPUT (GPIO_ODR_HIGH)
+#define GPIO_KB_OUTPUT_COL2 (GPIO_OUT_LOW)
+
+#include "gpio_list.h"
+
+/* PWM channels. Must be in the exactly same order as in enum pwm_channel. */
+const struct pwm_t pwm_channels[] = {
+ {0, PWM_CONFIG_ACTIVE_LOW},
+ {1, PWM_CONFIG_ACTIVE_LOW},
+ {3, PWM_CONFIG_ACTIVE_LOW},
+};
+
+BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
+
+/* power signal list. Must match order of enum power_signal. */
+const struct power_signal_info power_signal_list[] = {
+ {GPIO_ALL_SYS_PGOOD, 1, "ALL_SYS_PWRGD"},
+ {GPIO_RSMRST_L_PGOOD, 1, "RSMRST_N_PWRGD"},
+ {GPIO_PCH_SLP_S3_L, 1, "SLP_S3#_DEASSERTED"},
+ {GPIO_PCH_SLP_S4_L, 1, "SLP_S4#_DEASSERTED"},
+};
+BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+
+const struct i2c_port_t i2c_ports[] = {
+ {"batt_chg", MEC1322_I2C0_0, 100,
+ GPIO_I2C_PORT0_0_SCL, GPIO_I2C_PORT0_0_SDA},
+ {"muxes", MEC1322_I2C0_1, 100,
+ GPIO_I2C_PORT0_1_SCL, GPIO_I2C_PORT0_1_SDA},
+ {"pd_mcu", MEC1322_I2C1, 1000,
+ GPIO_I2C_PORT1_SCL, GPIO_I2C_PORT1_SDA},
+ {"sensors", MEC1322_I2C2, 100,
+ GPIO_I2C_PORT2_SCL, GPIO_I2C_PORT2_SDA},
+ {"thermal", MEC1322_I2C3, 100,
+ GPIO_I2C_PORT3_SCL, GPIO_I2C_PORT3_SDA}
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+const enum gpio_signal hibernate_wake_pins[] = {
+ GPIO_POWER_BUTTON_L,
+};
+
+const int hibernate_wake_pins_used = ARRAY_SIZE(hibernate_wake_pins);
+
+/*
+ * Temperature sensors data; must be in same order as enum temp_sensor_id.
+ * Sensor index and name must match those present in coreboot:
+ * src/mainboard/google/${board}/acpi/dptf.asl
+ */
+const struct temp_sensor_t temp_sensors[] = {
+ {"TMP432_Internal", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
+ TMP432_IDX_LOCAL, 4},
+ {"TMP432_Sensor_1", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
+ TMP432_IDX_REMOTE1, 4},
+ {"TMP432_Sensor_2", TEMP_SENSOR_TYPE_BOARD, tmp432_get_val,
+ TMP432_IDX_REMOTE2, 4},
+ {"Battery", TEMP_SENSOR_TYPE_BATTERY, charge_temp_sensor_get_val,
+ 0, 4},
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/* ALS instances. Must be in same order as enum als_id. */
+struct als_t als[] = {
+ {"ISL", isl29035_read_lux, 5},
+};
+BUILD_ASSERT(ARRAY_SIZE(als) == ALS_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[] = {
+ {{0, 0, 0}, 0, 0}, /* TMP432_Internal */
+ {{0, 0, 0}, 0, 0}, /* TMP432_Sensor_1 */
+ {{0, 0, 0}, 0, 0}, /* TMP432_Sensor_2 */
+ {{0, 0, 0}, 0, 0}, /* Battery Sensor */
+};
+BUILD_ASSERT(ARRAY_SIZE(thermal_params) == TEMP_SENSOR_COUNT);
+
+const struct button_config buttons[] = {
+ {"Volume Down", KEYBOARD_BUTTON_VOLUME_DOWN, GPIO_VOLUME_DOWN,
+ 30 * MSEC, 0},
+ {"Volume Up", KEYBOARD_BUTTON_VOLUME_UP, GPIO_VOLUME_UP,
+ 30 * MSEC, 0},
+};
+BUILD_ASSERT(ARRAY_SIZE(buttons) == CONFIG_BUTTON_COUNT);
+
+/* Four Motion sensors */
+/* kxcj9 mutex and local/private data*/
+static struct mutex g_kxcj9_mutex[2];
+struct kionix_accel_data g_kxcj9_data[2];
+
+/* Matrix to rotate accelrator into standard reference frame */
+const matrix_3x3_t base_standard_ref = {
+ { 0, FLOAT_TO_FP(1), 0},
+ {FLOAT_TO_FP(-1), 0, 0},
+ { 0, 0, FLOAT_TO_FP(1)}
+};
+
+const matrix_3x3_t lid_standard_ref = {
+ {FLOAT_TO_FP(1), 0, 0},
+ { 0, FLOAT_TO_FP(1), 0},
+ { 0, 0, FLOAT_TO_FP(1)}
+};
+
+struct motion_sensor_t motion_sensors[] = {
+ [BASE_ACCEL] = {
+ .name = "Base Accel",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_KXCJ9,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &kionix_accel_drv,
+ .mutex = &g_kxcj9_mutex[0],
+ .drv_data = &g_kxcj9_data[0],
+ .port = I2C_PORT_ACCEL,
+ .addr = KXCJ9_ADDR1,
+ .rot_standard_ref = &base_standard_ref,
+ .default_range = 2, /* g, enough for laptop. */
+ .config = {
+ /* AP: by default shutdown all sensors */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ }
+ },
+ [LID_ACCEL] = {
+ .name = "Lid Accel",
+ .active_mask = SENSOR_ACTIVE_S0_S3,
+ .chip = MOTIONSENSE_CHIP_KXCJ9,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &kionix_accel_drv,
+ .mutex = &g_kxcj9_mutex[1],
+ .drv_data = &g_kxcj9_data[1],
+ .port = I2C_PORT_ACCEL,
+ .addr = KXCJ9_ADDR0,
+ .rot_standard_ref = &lid_standard_ref,
+ .default_range = 2, /* g, enough for laptop. */
+ .config = {
+ /* AP: by default shutdown all sensors */
+ [SENSOR_CONFIG_AP] = {
+ .odr = 0,
+ .ec_rate = 0,
+ },
+ /* EC use accel for angle detection */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 0,
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ /* Sensor off in S3/S5 */
+ [SENSOR_CONFIG_EC_S5] = {
+ .odr = 0,
+ .ec_rate = 0
+ },
+ },
+ },
+};
+const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+
+/* init ADC ports to avoid floating state due to thermistors */
+static void adc_pre_init(void)
+{
+ /* Configure GPIOs */
+ gpio_config_module(MODULE_ADC, 1);
+}
+DECLARE_HOOK(HOOK_INIT, adc_pre_init, HOOK_PRIO_INIT_ADC - 1);
+
+int i2c_port_is_smbus(int port)
+{
+ return (port == MEC1322_I2C0_0 || port == MEC1322_I2C0_1) ? 1 : 0;
+}
diff --git a/board/strago/board.h b/board/strago/board.h
new file mode 100644
index 0000000000..29214bec14
--- /dev/null
+++ b/board/strago/board.h
@@ -0,0 +1,165 @@
+/* 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.
+ */
+
+/* Strago board configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+/* Optional features */
+#define CONFIG_WATCHDOG_HELP
+#define CONFIG_CLOCK_CRYSTAL
+#define CONFIG_CHIPSET_BRASWELL
+#define CONFIG_SCI_GPIO GPIO_PCH_SCI_L
+
+#define CONFIG_BOARD_VERSION
+
+#define CONFIG_KEYBOARD_COL2_INVERTED
+#define CONFIG_KEYBOARD_IRQ_GPIO GPIO_KBD_IRQ_L
+#undef CONFIG_KEYBOARD_KSO_BASE
+#define CONFIG_KEYBOARD_KSO_BASE 4 /* KSO starts from KSO04 */
+#define CONFIG_KEYBOARD_PROTOCOL_8042
+#define CONFIG_POWER_BUTTON
+#define CONFIG_POWER_BUTTON_X86
+#define CONFIG_LID_SWITCH
+#define CONFIG_LOW_POWER_IDLE
+#define CONFIG_LOW_POWER_PSEUDO_G3
+#define CONFIG_POWER_COMMON
+#define CONFIG_POWER_SHUTDOWN_PAUSE_IN_S5
+#define CONFIG_EXTPOWER_GPIO
+#define CONFIG_VBOOT_HASH
+#define CONFIG_PORT80_TASK_EN
+#define CONFIG_WIRELESS
+
+#define CONFIG_SPI_PORT 1
+#define CONFIG_SPI_CS_GPIO GPIO_PVT_CS0
+#define CONFIG_SPI_FLASH
+#define CONFIG_SPI_FLASH_SIZE 524288
+#define CONFIG_SPI_FLASH_W25Q64
+
+#define CONFIG_USB_PORT_POWER_SMART
+#define CONFIG_USB_PORT_POWER_SMART_SIMPLE
+
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_TMP432
+
+#define CONFIG_PMIC
+
+#define CONFIG_ALS
+#define CONFIG_ALS_ISL29035
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_PRESENT_GPIO GPIO_BAT_PRESENT_L
+#define CONFIG_BATTERY_SMART
+#define CONFIG_CHARGER
+#define CONFIG_CHARGER_V2
+#define CONFIG_CHARGER_BQ24770
+#define CONFIG_CHARGER_ILIM_PIN_DISABLED
+#define CONFIG_CHARGER_SENSE_RESISTOR 10
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10
+#define CONFIG_CHARGER_INPUT_CURRENT 2240
+#define CONFIG_CHARGER_DISCHARGE_ON_AC
+
+#define CONFIG_PWM
+#define CONFIG_LED_COMMON
+
+#define CONFIG_I2C
+
+/* Accelerometer */
+#define CONFIG_ACCEL_KXCJ9
+#define CONFIG_CMD_ACCELS
+#define CONFIG_CMD_ACCEL_INFO
+#define CONFIG_LID_ANGLE
+
+/* Wireless signals */
+#define WIRELESS_GPIO_WLAN GPIO_WLAN_OFF_L
+
+/* Number of buttons */
+#define CONFIG_BUTTON_COUNT 2
+
+/* Modules we want to exclude */
+#undef CONFIG_EEPROM
+#undef CONFIG_EOPTION
+#undef CONFIG_PSTORE
+#undef CONFIG_PECI
+#undef CONFIG_FANS
+#undef CONFIG_ADC
+#ifndef __ASSEMBLER__
+
+#include "gpio_signal.h"
+#include "registers.h"
+
+/* I2C ports */
+#define I2C_PORT_BATTERY MEC1322_I2C0_0
+#define I2C_PORT_CHARGER MEC1322_I2C0_0
+#define I2C_PORT_PD_MCU MEC1322_I2C1
+#define I2C_PORT_TCPC MEC1322_I2C1
+#define I2C_PORT_ACCEL MEC1322_I2C2
+#define I2C_PORT_GYRO MEC1322_I2C2
+#define I2C_PORT_ALS MEC1322_I2C2
+#define I2C_PORT_THERMAL MEC1322_I2C3
+
+/* ADC signal */
+enum adc_channel {
+ /* Number of ADC channels */
+ ADC_CH_COUNT
+};
+
+/* Sensor index definition */
+enum sensor_id {
+ BASE_ACCEL = 0,
+ LID_ACCEL = 1,
+};
+
+/*
+ * We have not enabled the sensor FIFO on the accels, so we force the EC
+ * to collect at every sample.
+ */
+#define CONFIG_ACCEL_FORCE_MODE_MASK \
+ ((1 << BASE_ACCEL) | (1 << LID_ACCEL))
+
+#define CONFIG_LID_ANGLE_SENSOR_BASE BASE_ACCEL
+#define CONFIG_LID_ANGLE_SENSOR_LID LID_ACCEL
+
+/* power signal definitions */
+enum power_signal {
+ X86_ALL_SYS_PWRGD = 0,
+ X86_RSMRST_L_PWRGD,
+ X86_SLP_S3_DEASSERTED,
+ X86_SLP_S4_DEASSERTED,
+
+ /* Number of X86 signals */
+ POWER_SIGNAL_COUNT
+};
+
+enum pwm_channel {
+ PWM_CH_LED_RED,
+ PWM_CH_LED_BLUE,
+ PWM_CH_LED_GREEN,
+ /* Number of PWM channels */
+ PWM_CH_COUNT
+};
+
+enum temp_sensor_id {
+ /* TMP432 local and remote sensors */
+ TEMP_SENSOR_I2C_TMP432_LOCAL,
+ TEMP_SENSOR_I2C_TMP432_REMOTE1,
+ TEMP_SENSOR_I2C_TMP432_REMOTE2,
+
+ /* Battery temperature sensor */
+ TEMP_SENSOR_BATTERY,
+
+ TEMP_SENSOR_COUNT
+};
+
+/* Light sensors */
+enum als_id {
+ ALS_ISL29035 = 0,
+
+ ALS_COUNT,
+};
+
+#endif /* !__ASSEMBLER__ */
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/strago/build.mk b/board/strago/build.mk
new file mode 100644
index 0000000000..894de2b191
--- /dev/null
+++ b/board/strago/build.mk
@@ -0,0 +1,14 @@
+# -*- 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 SMSC MEC1322 / external SPI is 4MB / external clock is crystal
+CHIP:=mec1322
+CHIP_SPI_SIZE_KB:=512
+
+board-y=board.o led.o
+board-$(CONFIG_BATTERY_SMART)+=battery.o
diff --git a/board/strago/ec.tasklist b/board/strago/ec.tasklist
new file mode 100644
index 0000000000..036a6b8764
--- /dev/null
+++ b/board/strago/ec.tasklist
@@ -0,0 +1,29 @@
+/* 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.
+ */
+
+/**
+ * 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' in the name of the task
+ * 'r' in the main routine of the task
+ * 'd' in 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, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(MOTIONSENSE, motion_sense_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(PORT80, port80_task, NULL, 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/strago/gpio.inc b/board/strago/gpio.inc
new file mode 100644
index 0000000000..1a4addc539
--- /dev/null
+++ b/board/strago/gpio.inc
@@ -0,0 +1,150 @@
+/* -*- 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.
+ */
+
+GPIO_INT(LID_OPEN, PIN(27), GPIO_INT_BOTH | GPIO_PULL_UP, lid_interrupt) /* Lid switch */
+GPIO_INT(AC_PRESENT, PIN(30), GPIO_INT_BOTH | GPIO_PULL_UP | GPIO_PULL_DOWN, extpower_interrupt) /* BC_ACOK / EC_ACIN - to know if battery or AC connected */
+#ifdef CONFIG_BUTTON_COUNT
+GPIO_INT(VOLUME_UP, PIN(31), GPIO_INT_BOTH, button_interrupt) /* Volume up button */
+GPIO_INT(VOLUME_DOWN, PIN(34), GPIO_INT_BOTH, button_interrupt) /* Volume down button */
+#endif
+GPIO_INT(POWER_BUTTON_L, PIN(35), GPIO_INT_BOTH, power_button_interrupt) /* Power button */
+GPIO_INT(RSMRST_L_PGOOD, PIN(63), GPIO_INT_BOTH, power_signal_interrupt) /* RSMRST_N_PWRGD from power logic */
+GPIO_INT(ALL_SYS_PGOOD, PIN(130), GPIO_INT_BOTH, power_signal_interrupt) /* ALL_SYS_PWRGD from power logic */
+#ifdef CONFIG_LOW_POWER_IDLE
+GPIO_INT(UART0_RX, PIN(162), GPIO_INT_BOTH_DSLEEP | GPIO_PULL_UP, uart_deepsleep_interrupt) /* UART0 RX input */
+#else
+GPIO_INT(UART0_RX, PIN(162), GPIO_INPUT | GPIO_PULL_UP, NULL) /* UART0 RX input */
+#endif
+GPIO_INT(PCH_SLP_S4_L, PIN(200), GPIO_INT_BOTH, power_signal_interrupt) /* SLP_S4# signal from PCH */
+GPIO_INT(PCH_SLP_S3_L, PIN(206), GPIO_INT_BOTH, power_signal_interrupt) /* SLP_S3# signal from PCH */
+
+GPIO(BOARD_VERSION2, PIN(0), GPIO_INPUT) /* BOARD_ID1 */
+GPIO(KBD_KSO2, PIN(1), GPIO_KB_OUTPUT_COL2) /* Negative edge triggered irq. */
+
+GPIO(NC_USBPD_BOOT0, PIN(12), GPIO_INPUT | GPIO_PULL_DOWN) /* NC */
+GPIO(USB_ILIM_SEL, PIN(13), GPIO_OUT_HIGH) /* USB current control */
+GPIO(I2C_PORT0_0_SCL, PIN(15), GPIO_INPUT)
+GPIO(I2C_PORT0_0_SDA, PIN(16), GPIO_INPUT)
+GPIO(I2C_PORT0_1_SCL, PIN(134), GPIO_INPUT)
+GPIO(I2C_PORT0_1_SDA, PIN(17), GPIO_INPUT)
+GPIO(I2C_PORT1_SCL, PIN(22), GPIO_INPUT)
+GPIO(I2C_PORT1_SDA, PIN(23), GPIO_INPUT)
+GPIO(I2C_PORT2_SCL, PIN(20), GPIO_INPUT)
+GPIO(I2C_PORT2_SDA, PIN(21), GPIO_INPUT)
+GPIO(I2C_PORT3_SCL, PIN(24), GPIO_INPUT)
+GPIO(I2C_PORT3_SDA, PIN(25), GPIO_INPUT)
+GPIO(PCH_SCI_L, PIN(26), GPIO_ODR_HIGH) /* SCI output */
+
+#ifndef CONFIG_BUTTON_COUNT
+GPIO(VOLUME_UP, PIN(31), GPIO_INPUT) /* Volume up button */
+#endif
+GPIO(WP_L, PIN(33), GPIO_INPUT) /* EC_SPI_WP_ME_L */
+#ifndef CONFIG_BUTTON_COUNT
+GPIO(VOLUME_DOWN, PIN(34), GPIO_INPUT) /* Volume down button */
+#endif
+GPIO(USB2_ENABLE, PIN(36), GPIO_OUT_LOW) /* Enable power for USB2 Port */
+
+GPIO(ENTERING_RW, PIN(41), GPIO_OUT_LOW) /* Indicate when EC is entering RW code */
+GPIO(PCH_SMI_L, PIN(44), GPIO_ODR_HIGH) /* SMI output */
+GPIO(USB_OC1_L, PIN(45), GPIO_INT_FALLING) /* DB2 BC1.2 over current signal to EC */
+GPIO(DP_USB_C_HPD_Q, PIN(46), GPIO_OUT_HIGH) /* DP hot plug detect from EC to SOC */
+
+GPIO(OTG_SW_EN, PIN(50), GPIO_OUT_LOW) /* */
+GPIO(PCH_SUS_STAT_L, PIN(51), GPIO_INT_FALLING) /* Signal to inform EC that SOC is entering low power state */
+GPIO(EC_ACDET_CTRL, PIN(52), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(TRACKPAD_PWREN, PIN(53), GPIO_OUT_HIGH) /* Enable power for Track Pad */
+GPIO(USB_OC0_L, PIN(55), GPIO_INT_FALLING) /* Over current signal of the BC1.2 charger to EC */
+GPIO(EC_ADC1, PIN(57), GPIO_INPUT) /* EC_ADC1, TEMP_SENSOR_2 no_stuff */
+
+GPIO(EC_ADC0, PIN(61), GPIO_INPUT) /* EC_ADC0 */
+GPIO(EC_HIB_L, PIN(64), GPIO_OUT_LOW) /* Set to high before Pseduo G3 */
+GPIO(PCH_SYS_PWROK, PIN(65), GPIO_OUT_LOW) /* EC thinks everything is up and ready (DELAY_ALL_SYS_PWRGD) */
+GPIO(PCH_WAKE_L, PIN(66), GPIO_ODR_HIGH) /* PCH wake pin */
+GPIO(USB1_ENABLE, PIN(67), GPIO_OUT_LOW) /* Enable power for USB3 Port */
+
+GPIO(NC_GPIO100, PIN(100), GPIO_INPUT | GPIO_PULL_UP) /* NC */
+GPIO(NC_GPIO101, PIN(101), GPIO_INPUT | GPIO_PULL_UP) /* NC */
+GPIO(BOARD_VERSION3, PIN(102), GPIO_INPUT) /* BOARD_ID2 */
+GPIO(USB_CTL1, PIN(105), GPIO_OUT_HIGH) /* USB charging mode control */
+
+GPIO(PCH_RCIN_L, PIN(110), GPIO_ODR_HIGH) /* Reset line to PCH (for 8042 emulation) */
+GPIO(NC_115, PIN(115), GPIO_INPUT | GPIO_PULL_UP) /* NC */
+GPIO(EC_VNN_VCLK, PIN(122), GPIO_INPUT | GPIO_PULL_UP) /* Interrupt from USB PD Controller to EC */
+GPIO(STRAP_L, PIN(123), GPIO_OUT_LOW)
+GPIO(EC_VNN_ALERT_L, PIN(124), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(GYRO_INT2, PIN(127), GPIO_INPUT | GPIO_PULL_DOWN) /* Gyro sensor interrupt 2 to EC */
+
+GPIO(EC_PLUG_DETECT, PIN(132), GPIO_INT_BOTH | GPIO_PULL_UP | GPIO_PULL_DOWN)
+GPIO(PD_RST_L, PIN(135), GPIO_ODR_HIGH) /* USB PD MCU reset */
+
+GPIO(THERMAL_PROBE_EN_L,PIN(140), GPIO_OUT_HIGH)
+GPIO(PCH_RSMRST_L, PIN(143), GPIO_OUT_LOW) /* RSMRST_N to PCH */
+GPIO(EC_KBD_ALERT, PIN(145), GPIO_OUT_LOW) /* EC_KBD_ALERT */
+GPIO(PVT_CS0, PIN(146), GPIO_ODR_HIGH) /* SPI PVT Chip select */
+GPIO(ALS_INT, PIN(147), GPIO_INPUT | GPIO_PULL_UP) /* ALS sensor interrupt to EC */
+
+GPIO(WLAN_OFF_L, PIN(150), GPIO_ODR_HIGH) /* Wireless LAN */
+GPIO(CPU_PROCHOT, PIN(151), GPIO_OUT_LOW)
+GPIO(KBD_IRQ_L, PIN(152), GPIO_ODR_HIGH) /* Negative edge triggered irq. */
+GPIO(BOARD_VERSION1, PIN(154), GPIO_INPUT) /* BOARD_ID0 */
+GPIO(EC_PERICOM_INT, PIN(155), GPIO_INT_BOTH) /* Pericom USB device interrupt */
+GPIO(PWR_BTN_SELECT, PIN(156), GPIO_ODR_HIGH) /* HIGH in clamshell mode and LOW in tablet mode */
+GPIO(PCH_SUSPWRDNACK, PIN(157), GPIO_INT_FALLING) /* PMC SUSPWRDNACK signal from SOC to EC */
+
+GPIO(PCH_PWRBTN_L, PIN(160), GPIO_OUT_HIGH) /* Power button output to PCH */
+GPIO(GYRO_INT1, PIN(161), GPIO_INPUT | GPIO_PULL_DOWN) /* Gyro sensor interrupt 1 to EC */
+GPIO(VP9_CODEC_RESET_L, PIN(163), GPIO_OUT_LOW) /* VP9_CODEC_RESET_L, OUTPUT, ACTIVE LOW */
+
+GPIO(STARTUP_LATCH_SET, PIN(201), GPIO_INPUT) /* Not used in BCRD2. Programmed as Input to fix EC power leakage in S3*/
+GPIO(EC_BL_DISABLE_L, PIN(202), GPIO_OUT_HIGH) /* EDP backligh disable signal from EC */
+GPIO(SMC_SHUTDOWN, PIN(203), GPIO_OUT_LOW) /* Shutdown signal from EC to power sequencing PLD */
+GPIO(USBPD_BST_OFF, PIN(204), GPIO_OUT_LOW)
+
+GPIO(BAT_PRESENT_L, PIN(210), GPIO_INPUT) /* HW detection signal from battery to EC */
+GPIO(GPIO_3_EC, PIN(211), GPIO_OUT_LOW) /* Sleep SOIX signal from SOC to EC */
+
+/* Alternate functions GPIO definition */
+ALTERNATE(PIN_MASK(16, 0x24), 1, MODULE_UART, 0) /* UART0 */
+
+ALTERNATE(PIN_MASK(1, 0x60), 2, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C0: Battery Charger */
+ALTERNATE(PIN_MASK(2, 0x3f), 2, MODULE_I2C, GPIO_OPEN_DRAIN) /* I2C1: Temp Sensor / I2C2: SOC / I2C3: VNN */
+
+ALTERNATE(PIN_MASK(0, 0xfc), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(1, 0x03), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(10, 0xd8), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(3, 0x04), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+ALTERNATE(PIN_MASK(4, 0x0d), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+ALTERNATE(PIN_MASK(12, 0x60), 2, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+ALTERNATE(PIN_MASK(14, 0x14), 3, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+
+ALTERNATE(PIN_MASK(1, 0x10), 0, MODULE_LPC, GPIO_ODR_HIGH) /* 14: LPC CLKRUN - Program as GPIO for power saving */
+ALTERNATE(PIN_MASK(11, 0x9e), 1, MODULE_LPC, 0) /* 111~114:LAD[0:3], 117:PCI_CLK */
+ALTERNATE(PIN_MASK(11, 0x40), 1, MODULE_LPC, GPIO_INT_BOTH) /* 116: LRESET# */
+ALTERNATE(PIN_MASK(12, 0x01), 1, MODULE_LPC, 0) /* 120: LFRAME# */
+
+ALTERNATE(PIN_MASK(5, 0x10), 1, MODULE_SPI, 0)
+ALTERNATE(PIN_MASK(16, 0x10), 1, MODULE_SPI, 0)
+ALTERNATE(PIN_MASK(15, 0x08), 1, MODULE_SPI, 0) /* 153: CLK */
+
+ALTERNATE(PIN_MASK(13, 0x48), 1, MODULE_PWM_LED, GPIO_OUTPUT) /* 133: PWM0, 136: PWM1 */
+ALTERNATE(PIN_MASK(14, 0x02), 1, MODULE_PWM_LED, GPIO_OUTPUT) /* 141: PWM3 */
+ALTERNATE(PIN_MASK(5, 0x40), 1, MODULE_ADC, 0) /* 56: temperature sensor 1 */
+ALTERNATE(PIN_MASK(6, 0x05), 1, MODULE_ADC, 0) /* 60: PC_MON, 62: temperature sensor 3 */
+
+/* Re-Config LPC Pins to GPIO Open Drain for SOC G3 (EC - POWER_G3) state */
+ALTERNATE(PIN_MASK(1, 0x10), 0, MODULE_GPIO, GPIO_ODR_HIGH) /* 14: LPC CLKRUN */
+ALTERNATE(PIN_MASK(11, 0x9e), 0, MODULE_GPIO, GPIO_ODR_HIGH) /* 111~114:LAD[0:3], 117:PCI_CLK */
+ALTERNATE(PIN_MASK(11, 0x40), 0, MODULE_GPIO, GPIO_ODR_HIGH) /* 116: LRESET# */
+ALTERNATE(PIN_MASK(12, 0x01), 0, MODULE_GPIO, GPIO_ODR_HIGH) /* 120: LFRAME# */
+
+/* I2C pins */
+/* I2C0_0 CLK - GPIO015, I2C0_0 DAT - GPIO016, I2C0_1 DAT - GPIO017 */
+ALTERNATE(PIN_MASK(1, 0xe0), 2, MODULE_I2C, GPIO_ODR_HIGH)
+/* I2C0_1 CLK - GPIO134 */
+ALTERNATE(PIN_MASK(13, 0x10), 2, MODULE_I2C, GPIO_ODR_HIGH)
+/* I2C{1,2,3} CLK / DAT - GPIO022-GPIO025*/
+ALTERNATE(PIN_MASK(2, 0x3f), 2, MODULE_I2C, GPIO_ODR_HIGH)
diff --git a/board/strago/led.c b/board/strago/led.c
new file mode 100644
index 0000000000..74c5da3598
--- /dev/null
+++ b/board/strago/led.c
@@ -0,0 +1,210 @@
+/* Copyright 2015 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/Battery LED control for Strago
+ */
+
+#include "charge_state.h"
+#include "chipset.h"
+#include "console.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "led_common.h"
+#include "pwm.h"
+#include "registers.h"
+#include "util.h"
+
+#define CPRINTF(format, args...) cprintf(CC_PWM, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_PWM, format, ## args)
+
+#define LED_TOTAL_TICKS 16
+#define LED_ON_TICKS 4
+
+static int led_debug;
+
+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);
+
+enum led_color {
+ LED_OFF = 0,
+ LED_RED,
+ LED_AMBER,
+ LED_GREEN,
+
+ /* Number of colors, not a color itself */
+ LED_COLOR_COUNT
+};
+
+/* Brightness vs. color, in the order of off, red, amber, and green */
+static const uint8_t color_brightness[LED_COLOR_COUNT][3] = {
+ /* {Red, Blue, Green}, */
+ [LED_OFF] = { 0, 0, 0},
+ [LED_RED] = {100, 0, 0},
+ [LED_AMBER] = { 75, 0, 10},
+ [LED_GREEN] = { 0, 0, 100},
+};
+
+/**
+ * Set LED color
+ *
+ * @param color Enumerated color value
+ */
+static void set_color(enum led_color color)
+{
+ pwm_set_duty(PWM_CH_LED_RED, color_brightness[color][0]);
+ pwm_set_duty(PWM_CH_LED_BLUE, color_brightness[color][1]);
+ pwm_set_duty(PWM_CH_LED_GREEN, color_brightness[color][2]);
+}
+
+void led_get_brightness_range(enum ec_led_id led_id, uint8_t *brightness_range)
+{
+ brightness_range[EC_LED_COLOR_RED] = 100;
+ brightness_range[EC_LED_COLOR_BLUE] = 100;
+ brightness_range[EC_LED_COLOR_GREEN] = 100;
+}
+
+int led_set_brightness(enum ec_led_id led_id, const uint8_t *brightness)
+{
+ pwm_set_duty(PWM_CH_LED_RED, brightness[EC_LED_COLOR_RED]);
+ pwm_set_duty(PWM_CH_LED_BLUE, brightness[EC_LED_COLOR_BLUE]);
+ pwm_set_duty(PWM_CH_LED_GREEN, brightness[EC_LED_COLOR_GREEN]);
+ return EC_SUCCESS;
+}
+
+static void strago_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. */
+ set_color(
+ (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))
+ set_color(LED_OFF);
+ else if (chipset_in_state(CHIPSET_STATE_ON))
+ set_color(LED_GREEN);
+}
+
+static void strago_led_set_battery(void)
+{
+ static int battery_ticks;
+
+ battery_ticks++;
+
+ switch (charge_get_state()) {
+ case PWR_STATE_CHARGE:
+ set_color(LED_AMBER);
+ break;
+ case PWR_STATE_ERROR:
+ set_color(LED_RED);
+ break;
+ case PWR_STATE_CHARGE_NEAR_FULL:
+ case PWR_STATE_IDLE: /* External power connected in IDLE. */
+ set_color(LED_GREEN);
+ break;
+ default:
+ /* Other states don't alter LED behavior */
+ break;
+ }
+}
+
+static void led_init(void)
+{
+ /* Configure GPIOs */
+ gpio_config_module(MODULE_PWM_LED, 1);
+
+ /*
+ * Enable PWMs and set to 0% duty cycle. If they're disabled,
+ * seems to ground the pins instead of letting them float.
+ */
+ pwm_enable(PWM_CH_LED_RED, 1);
+ pwm_enable(PWM_CH_LED_GREEN, 1);
+ pwm_enable(PWM_CH_LED_BLUE, 1);
+
+ set_color(LED_OFF);
+}
+DECLARE_HOOK(HOOK_INIT, led_init, HOOK_PRIO_DEFAULT);
+
+/**
+ * Called by hook task every 250 ms
+ */
+static void led_tick(void)
+{
+ if (led_debug)
+ return;
+
+ if (extpower_is_present()) {
+ if (led_auto_control_is_enabled(EC_LED_ID_BATTERY_LED)) {
+ strago_led_set_battery();
+ return;
+ }
+ } else if (led_auto_control_is_enabled(EC_LED_ID_POWER_LED)) {
+ strago_led_set_power();
+ return;
+ }
+
+ set_color(LED_OFF);
+}
+DECLARE_HOOK(HOOK_TICK, led_tick, HOOK_PRIO_DEFAULT);
+
+static void dump_pwm_channels(void)
+{
+ int ch;
+ for (ch = 0; ch < 4; ch++) {
+ CPRINTF("channel = %d\n", ch);
+ CPRINTF("0x%04X 0x%04X 0x%04X\n",
+ MEC1322_PWM_CFG(ch),
+ MEC1322_PWM_ON(ch),
+ MEC1322_PWM_OFF(ch));
+ }
+}
+/******************************************************************/
+/* Console commands */
+static int command_led_color(int argc, char **argv)
+{
+ if (argc > 1) {
+ if (!strcasecmp(argv[1], "debug")) {
+ led_debug ^= 1;
+ CPRINTF("led_debug = %d\n", led_debug);
+ } else if (!strcasecmp(argv[1], "off")) {
+ set_color(LED_OFF);
+ } else if (!strcasecmp(argv[1], "red")) {
+ set_color(LED_RED);
+ } else if (!strcasecmp(argv[1], "green")) {
+ set_color(LED_GREEN);
+ } else if (!strcasecmp(argv[1], "amber")) {
+ set_color(LED_AMBER);
+ } else {
+ /* maybe handle charger_discharge_on_ac() too? */
+ return EC_ERROR_PARAM1;
+ }
+ }
+
+ if (led_debug == 1)
+ dump_pwm_channels();
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(ledcolor, command_led_color,
+ "[debug|red|green|amber|off]",
+ "Change LED color",
+ NULL);
+
diff --git a/board/strago/lfw/gpio.inc b/board/strago/lfw/gpio.inc
new file mode 100644
index 0000000000..122aff0cdf
--- /dev/null
+++ b/board/strago/lfw/gpio.inc
@@ -0,0 +1,16 @@
+/* -*- 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.
+ *
+ * Minimal set of GPIOs needed for LFW loader
+ */
+
+GPIO(PVT_CS0, PIN(146), GPIO_ODR_HIGH) /* SPI PVT Chip select */
+
+/* Alternate functions GPIO definition */
+ALTERNATE(PIN_MASK(16, 0x24), 1, MODULE_UART, 0) /* UART0 */
+ALTERNATE(PIN_MASK(5, 0x10), 1, MODULE_SPI, 0)
+ALTERNATE(PIN_MASK(16, 0x10), 1, MODULE_SPI, 0)
+ALTERNATE(PIN_MASK(15, 0x08), 1, MODULE_SPI, 0) /* 153: CLK */
diff --git a/driver/gyro_l3gd20h.c b/driver/gyro_l3gd20h.c
new file mode 100644
index 0000000000..0f63a93ced
--- /dev/null
+++ b/driver/gyro_l3gd20h.c
@@ -0,0 +1,439 @@
+/* Copyright 2015 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.
+ */
+
+/**
+ * L3GD20H gyro module for Chrome EC 3D digital gyroscope.
+ */
+
+#include "accelgyro.h"
+#include "common.h"
+#include "console.h"
+#include "driver/gyro_l3gd20h.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "task.h"
+#include "util.h"
+
+#define CPUTS(outstr) cputs(CC_ACCEL, outstr)
+#define CPRINTF(format, args...) cprintf(CC_ACCEL, format, ## args)
+
+/*
+ * Struct for pairing an engineering value with the register value for a
+ * parameter.
+ */
+struct gyro_param_pair {
+ int val; /* Value in engineering units. */
+ int reg_val; /* Corresponding register value. */
+};
+
+/*
+ * List of angular rate range values in +/-dps's
+ * and their associated register values.
+ */
+const struct gyro_param_pair dps_ranges[] = {
+ {245, L3GD20_DPS_SEL_245},
+ {500, L3GD20_DPS_SEL_500},
+ {2000, L3GD20_DPS_SEL_2000_0},
+ {2000, L3GD20_DPS_SEL_2000_1}
+};
+
+static inline const struct gyro_param_pair *get_range_table(
+ enum motionsensor_type type, int *psize)
+{
+ if (psize)
+ *psize = ARRAY_SIZE(dps_ranges);
+ return dps_ranges;
+}
+
+/* List of ODR values in mHz and their associated register values. */
+const struct gyro_param_pair gyro_odr[] = {
+ {0, L3GD20_ODR_PD | L3GD20_LOW_ODR_MASK},
+ {12500, L3GD20_ODR_12_5HZ | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK},
+ {25000, L3GD20_ODR_25HZ | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK},
+ {50000, L3GD20_ODR_50HZ_0 | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK},
+ {50000, L3GD20_ODR_50HZ_1 | L3GD20_ODR_PD_MASK | L3GD20_LOW_ODR_MASK},
+ {100000, L3GD20_ODR_100HZ | L3GD20_ODR_PD_MASK},
+ {200000, L3GD20_ODR_200HZ | L3GD20_ODR_PD_MASK},
+ {400000, L3GD20_ODR_400HZ | L3GD20_ODR_PD_MASK},
+ {800000, L3GD20_ODR_800HZ | L3GD20_ODR_PD_MASK},
+};
+
+static inline const struct gyro_param_pair *get_odr_table(
+ enum motionsensor_type type, int *psize)
+{
+ if (psize)
+ *psize = ARRAY_SIZE(gyro_odr);
+ return gyro_odr;
+}
+
+static inline int get_ctrl_reg(enum motionsensor_type type)
+{
+ return L3GD20_CTRL_REG1;
+}
+
+static inline int get_xyz_reg(enum motionsensor_type type)
+{
+ return L3GD20_OUT_X_L | (1 << 7);
+}
+
+/**
+ * @return reg value that matches the given engineering value passed in.
+ * The round_up flag is used to specify whether to round up or down.
+ * Note, this function always returns a valid reg value. If the request is
+ * outside the range of values, it returns the closest valid reg value.
+ */
+static int get_reg_val(const int eng_val, const int round_up,
+ const struct gyro_param_pair *pairs, const int size)
+{
+ int i;
+ for (i = 0; i < size - 1; i++) {
+ if (eng_val <= pairs[i].val)
+ break;
+
+ if (eng_val < pairs[i+1].val) {
+ if (round_up)
+ i += 1;
+ break;
+ }
+ }
+ return pairs[i].reg_val;
+}
+
+/**
+ * @return engineering value that matches the given reg val
+ */
+static int get_engineering_val(const int reg_val,
+ const struct gyro_param_pair *pairs, const int size)
+{
+ int i;
+ for (i = 0; i < size; i++) {
+ if (reg_val == pairs[i].reg_val)
+ break;
+ }
+ return pairs[i].val;
+}
+
+/**
+ * Read register from Gyrometer.
+ */
+static inline int raw_read8(const int addr, const int reg, int *data_ptr)
+{
+ return i2c_read8(I2C_PORT_GYRO, addr, reg, data_ptr);
+}
+
+/**
+ * Write register from Gyrometer.
+ */
+static inline int raw_write8(const int addr, const int reg, int data)
+{
+ return i2c_write8(I2C_PORT_GYRO, addr, reg, data);
+}
+
+static int set_range(const struct motion_sensor_t *s,
+ int range,
+ int rnd)
+{
+ int ret, ctrl_val, range_tbl_size;
+ uint8_t ctrl_reg, reg_val;
+ const struct gyro_param_pair *ranges;
+ struct l3gd20_data *data = (struct l3gd20_data *)s->drv_data;
+
+ ctrl_reg = L3GD20_CTRL_REG4;
+ ranges = get_range_table(s->type, &range_tbl_size);
+
+ reg_val = get_reg_val(range, rnd, ranges, range_tbl_size);
+
+ /*
+ * Lock Gyro resource to prevent another task from attempting
+ * to write Gyro parameters until we are done.
+ */
+ mutex_lock(s->mutex);
+
+ ret = raw_read8(s->i2c_addr, ctrl_reg, &ctrl_val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ ctrl_val = (ctrl_val & ~L3GD20_RANGE_MASK) | reg_val;
+ ret = raw_write8(s->i2c_addr, ctrl_reg, ctrl_val);
+
+ /* Now that we have set the range, update the driver's value. */
+ if (ret == EC_SUCCESS)
+ data->base.range = get_engineering_val(reg_val, ranges,
+ range_tbl_size);
+
+gyro_cleanup:
+ mutex_unlock(s->mutex);
+ return EC_SUCCESS;
+}
+
+static int get_range(const struct motion_sensor_t *s, int *range)
+{
+ struct l3gd20_data *data = (struct l3gd20_data *)s->drv_data;
+
+ return data->base.range;
+}
+
+static int set_resolution(const struct motion_sensor_t *s,
+ int res,
+ int rnd)
+{
+ /* Only one resolution, L3GD20_RESOLUTION, so nothing to do. */
+ return EC_SUCCESS;
+}
+
+static int get_resolution(const struct motion_sensor_t *s,
+ int *res)
+{
+ *res = L3GD20_RESOLUTION;
+ return EC_SUCCESS;
+}
+
+static int set_data_rate(const struct motion_sensor_t *s,
+ int rate,
+ int rnd)
+{
+ int ret, val, odr_tbl_size;
+ uint8_t ctrl_reg, reg_val;
+ const struct gyro_param_pair *data_rates;
+ struct l3gd20_data *data = s->drv_data;
+
+ ctrl_reg = get_ctrl_reg(s->type);
+ data_rates = get_odr_table(s->type, &odr_tbl_size);
+ reg_val = get_reg_val(rate, rnd, data_rates, odr_tbl_size);
+
+ /*
+ * Lock gyro resource to prevent another task from attempting
+ * to write gyro parameters until we are done.
+ */
+ mutex_lock(s->mutex);
+
+ ret = raw_read8(s->i2c_addr, ctrl_reg, &val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ val = (val & ~(L3GD20_ODR_MASK | L3GD20_ODR_PD_MASK)) |
+ (reg_val & ~L3GD20_LOW_ODR_MASK);
+ ret = raw_write8(s->i2c_addr, ctrl_reg, val);
+
+ /* Now that we have set the odr, update the driver's value. */
+ if (ret == EC_SUCCESS)
+ data->base.odr = get_engineering_val(reg_val, data_rates,
+ odr_tbl_size);
+
+ ret = raw_read8(s->i2c_addr, L3GD20_LOW_ODR, &val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ /* We need to clear low_ODR bit for higher data rates */
+ if (reg_val & L3GD20_LOW_ODR_MASK)
+ val |= 1;
+ else
+ val &= ~1;
+
+ ret = raw_write8(s->i2c_addr, L3GD20_LOW_ODR, val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ /* CTRL_REG5 24h
+ * [7] low-power mode = 0;
+ * [6] fifo disabled = 0;
+ * [5] Stop on fth = 0;
+ * [4] High pass filter enable = 1;
+ * [3:2] int1_sel = 0;
+ * [1:0] out_sel = 1;
+ */
+ ret = raw_read8(s->i2c_addr, L3GD20_CTRL_REG5, &val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ val |= (1 << 4); /* high-pass filter enabled */
+ val |= (1 << 0); /* data in data reg are high-pass filtered */
+ ret = raw_write8(s->i2c_addr, L3GD20_CTRL_REG5, val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ ret = raw_read8(s->i2c_addr, L3GD20_CTRL_REG2, &val);
+ if (ret != EC_SUCCESS)
+ goto gyro_cleanup;
+
+ /*
+ * Table 25. High pass filter mode configuration
+ * Table 26. High pass filter cut off frequency configuration
+ */
+ val &= 0xf0;
+ val |= 0x04;
+ ret = raw_write8(s->i2c_addr, L3GD20_CTRL_REG2, val);
+
+gyro_cleanup:
+ mutex_unlock(s->mutex);
+ return ret;
+}
+
+static int get_data_rate(const struct motion_sensor_t *s,
+ int *rate)
+{
+ struct l3gd20_data *data = (struct l3gd20_data *)s->drv_data;
+
+ *rate = data->base.odr;
+ return EC_SUCCESS;
+}
+
+static int set_offset(const struct motion_sensor_t *s,
+ const int16_t *offset,
+ int16_t temp)
+{
+ /* temperature is ignored */
+ struct l3gd20_data *data = s->drv_data;
+ data->offset[X] = offset[X];
+ data->offset[Y] = offset[Y];
+ data->offset[Z] = offset[Z];
+ return EC_SUCCESS;
+}
+
+static int get_offset(const struct motion_sensor_t *s,
+ int16_t *offset,
+ int16_t *temp)
+{
+ struct l3gd20_data *data = s->drv_data;
+ offset[X] = data->offset[X];
+ offset[Y] = data->offset[Y];
+ offset[Z] = data->offset[Z];
+ *temp = EC_MOTION_SENSE_INVALID_CALIB_TEMP;
+ return EC_SUCCESS;
+}
+
+#ifdef CONFIG_ACCEL_INTERRUPTS
+static int set_interrupt(const struct motion_sensor_t *s,
+ unsigned int threshold)
+{
+ /* Currently unsupported. */
+ return EC_ERROR_UNKNOWN;
+}
+#endif
+
+static int is_data_ready(const struct motion_sensor_t *s, int *ready)
+{
+ int ret, tmp;
+
+ ret = raw_read8(s->i2c_addr, L3GD20_STATUS_REG, &tmp);
+
+ if (ret != EC_SUCCESS) {
+ CPRINTF("[%T %s type:0x%X RS Error]", s->name, s->type);
+ return ret;
+ }
+
+ *ready = (tmp & L3GD20_STS_ZYXDA_MASK) ? 1 : 0;
+
+ return EC_SUCCESS;
+}
+
+static int read(const struct motion_sensor_t *s, vector_3_t v)
+{
+ uint8_t raw[6];
+ uint8_t xyz_reg;
+ int ret, range, i, tmp = 0;
+ struct l3gd20_data *data = s->drv_data;
+
+ ret = is_data_ready(s, &tmp);
+ if (ret != EC_SUCCESS)
+ return ret;
+
+ /*
+ * If sensor data is not ready, return the previous read data.
+ * Note: return success so that motion senor task can read again
+ * to get the latest updated sensor data quickly.
+ */
+ if (!tmp) {
+ if (v != s->raw_xyz)
+ memcpy(v, s->raw_xyz, sizeof(s->raw_xyz));
+ return EC_SUCCESS;
+ }
+
+ xyz_reg = get_xyz_reg(s->type);
+
+ /* Read 6 bytes starting at xyz_reg */
+ i2c_lock(I2C_PORT_GYRO, 1);
+ ret = i2c_xfer(I2C_PORT_GYRO, s->i2c_addr,
+ &xyz_reg, 1, raw, 6, I2C_XFER_SINGLE);
+ i2c_lock(I2C_PORT_GYRO, 0);
+
+ if (ret != EC_SUCCESS) {
+ CPRINTF("[%T %s type:0x%X RD XYZ Error]",
+ s->name, s->type);
+ return ret;
+ }
+
+ get_range(s, &range);
+ for (i = X; i <= Z; i++) {
+ v[i] = ((int16_t)((raw[i * 2 + 1] << 8) | raw[i * 2]));
+ v[i] += (data->offset[i] << 5) / range;
+ }
+ if (*s->rot_standard_ref != NULL)
+ rotate(v, *s->rot_standard_ref, v);
+
+ return EC_SUCCESS;
+}
+
+static int init(const struct motion_sensor_t *s)
+{
+ int ret = 0, tmp;
+
+ ret = raw_read8(s->i2c_addr, L3GD20_WHO_AM_I_REG, &tmp);
+ if (ret)
+ return EC_ERROR_UNKNOWN;
+
+ if (tmp != L3GD20_WHO_AM_I)
+ return EC_ERROR_ACCESS_DENIED;
+
+ /* All axes are enabled */
+ ret = raw_write8(s->i2c_addr, L3GD20_CTRL_REG1, 0x0f);
+ if (ret)
+ return EC_ERROR_UNKNOWN;
+
+ mutex_lock(s->mutex);
+ ret = raw_read8(s->i2c_addr, L3GD20_CTRL_REG4, &tmp);
+ if (ret) {
+ mutex_unlock(s->mutex);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ tmp |= L3GD20_BDU_ENABLE;
+ ret = raw_write8(s->i2c_addr, L3GD20_CTRL_REG4, tmp);
+ mutex_unlock(s->mutex);
+ if (ret)
+ return EC_ERROR_UNKNOWN;
+
+ /* Config GYRO Range */
+ ret = set_range(s, s->runtime_config.range, 1);
+ if (ret)
+ return EC_ERROR_UNKNOWN;
+
+ /* Config GYRO ODR */
+ ret = set_data_rate(s, s->runtime_config.odr, 1);
+ if (ret)
+ return EC_ERROR_UNKNOWN;
+
+ CPRINTF("[%T %s: MS Done Init type:0x%X range:%d odr:%d]\n",
+ s->name, s->type, s->runtime_config.range,
+ s->runtime_config.odr);
+ return ret;
+}
+
+const struct accelgyro_drv l3gd20h_drv = {
+ .init = init,
+ .read = read,
+ .set_range = set_range,
+ .get_range = get_range,
+ .set_resolution = set_resolution,
+ .get_resolution = get_resolution,
+ .set_data_rate = set_data_rate,
+ .get_data_rate = get_data_rate,
+ .set_offset = set_offset,
+ .get_offset = get_offset,
+ .perform_calib = NULL,
+#ifdef CONFIG_ACCEL_INTERRUPTS
+ .set_interrupt = set_interrupt,
+#endif
+};
diff --git a/driver/gyro_l3gd20h.h b/driver/gyro_l3gd20h.h
new file mode 100644
index 0000000000..6ff9fba044
--- /dev/null
+++ b/driver/gyro_l3gd20h.h
@@ -0,0 +1,102 @@
+/* Copyright 2015 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.
+ */
+
+/* L3GD20H gyro module for Chrome EC */
+
+#ifndef __CROS_EC_GYRO_L3GD20H_H
+#define __CROS_EC_GYRO_L3GD20H_H
+
+#include "accelgyro.h"
+#include "task.h"
+
+/*
+ * 7-bit address is 110101Xb. Where 'X' is determined
+ * by the voltage on the ADDR pin.
+ */
+#define L3GD20_ADDR0 0xd4
+#define L3GD20_ADDR1 0xd6
+
+/* who am I */
+#define L3GD20_WHO_AM_I 0xd7
+
+/* Chip specific registers. */
+#define L3GD20_WHO_AM_I_REG 0x0f
+#define L3GD20_CTRL_REG1 0x20
+#define L3GD20_CTRL_REG2 0x21
+#define L3GD20_CTRL_REG3 0x22
+#define L3GD20_CTRL_REG4 0x23
+#define L3GD20_CTRL_REG5 0x24
+#define L3GD20_CTRL_REFERENCE 0x25
+#define L3GD20_OUT_TEMP 0x26
+#define L3GD20_STATUS_REG 0x27
+#define L3GD20_OUT_X_L 0x28
+#define L3GD20_OUT_X_H 0x29
+#define L3GD20_OUT_Y_L 0x2a
+#define L3GD20_OUT_Y_H 0x2b
+#define L3GD20_OUT_Z_L 0x2c
+#define L3GD20_OUT_Z_H 0x2d
+#define L3GD20_FIFO_CTRL_REG 0x2e
+#define L3GD20_FIFO_SRC_REG 0x2f
+#define L3GD20_INT1_CFG 0x30
+#define L3GD20_INT1_SRC 0x31
+#define L3GD20_INT1_TSH_XH 0x32
+#define L3GD20_INT1_TSH_XL 0x33
+#define L3GD20_INT1_TSH_YH 0x34
+#define L3GD20_INT1_TSH_YL 0x35
+#define L3GD20_INT1_TSH_ZH 0x36
+#define L3GD20_INT1_TSH_ZL 0x37
+#define L3GD20_INT1_DURATION 0x38
+#define L3GD20_LOW_ODR 0x39
+
+#define L3GD20_DPS_SEL_245 (0 << 4)
+#define L3GD20_DPS_SEL_500 (1 << 4)
+#define L3GD20_DPS_SEL_2000_0 (2 << 4)
+#define L3GD20_DPS_SEL_2000_1 (3 << 4)
+
+#define L3GD20_ODR_PD (0 << 3)
+#define L3GD20_ODR_12_5HZ (0 << 6)
+#define L3GD20_ODR_25HZ (1 << 6)
+#define L3GD20_ODR_50HZ_0 (2 << 6)
+#define L3GD20_ODR_50HZ_1 (3 << 6)
+#define L3GD20_ODR_100HZ (0 << 6)
+#define L3GD20_ODR_200HZ (1 << 6)
+#define L3GD20_ODR_400HZ (2 << 6)
+#define L3GD20_ODR_800HZ (3 << 6)
+
+#define L3GD20_ODR_MASK (3 << 6)
+#define L3GD20_STS_ZYXDA_MASK (1 << 3)
+#define L3GD20_RANGE_MASK (3 << 4)
+#define L3GD20_LOW_ODR_MASK (1 << 0)
+#define L3GD20_ODR_PD_MASK (1 << 3)
+
+/*
+ * Register : STATUS_REG
+ * Address : 0X27
+ */
+enum l3gd20_status {
+ L3GD20_STS_DOWN = 0x00,
+ L3GD20_STS_ZYXDA_UP = 0x08,
+};
+
+/*
+ * Register : CTRL_REG4
+ * Address : 0X23
+ * Bit Group Name: BDU
+ */
+enum l3gd20_bdu {
+ L3GD20_BDU_DISABLE = 0x00,
+ L3GD20_BDU_ENABLE = 0x80,
+};
+
+/* Sensor resolution in number of bits. This sensor has fixed resolution. */
+#define L3GD20_RESOLUTION 16
+
+extern const struct accelgyro_drv l3gd20h_drv;
+struct l3gd20_data {
+ struct motion_data_t base;
+ int16_t offset[3];
+};
+
+#endif /* __CROS_EC_GYRO_L3GD20H_H */