summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@google.com>2018-03-27 12:56:37 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-04-06 14:44:06 -0700
commitc0ebdaee162cc5090458207b354fad4cb8ea89a9 (patch)
tree815f6dad3f37ff31d2a6610d2e1f5431e5c71272
parent7e50bfd037af520cafa3e71fafe9e95d1e9487ba (diff)
downloadchrome-ec-c0ebdaee162cc5090458207b354fad4cb8ea89a9.tar.gz
atlas: Add new board
This is based on the initial code from Caveh here: https://chromium-review.googlesource.com/959861 Most things are functional, with some workarounds for P0 boards. The type-c hotplug is not working in this commit, the HPD will be run from the tcpm in the next board build. For now we might be able to get it working on P0 with some more tweaking.. The other known issue is that the battery takes ~2 seconds to come back online after a cutoff (the auto-power-on timeout is one second so the board will not power on like it should) and sometimes the battery is not responding properly on i2c and it requires an EC reset. BUG=b:75070158 BRANCH=none TEST=tested on P0 boards Change-Id: I438cb93b78d6f501426842d6cbe3d6a994563358 Signed-off-by: Duncan Laurie <dlaurie@google.com> Signed-off-by: Caveh Jalali <caveh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/982498 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Caveh Jalali <caveh@google.com> Reviewed-by: Caveh Jalali <caveh@google.com>
-rw-r--r--board/atlas/battery.c293
-rw-r--r--board/atlas/board.c597
-rw-r--r--board/atlas/board.h270
-rw-r--r--board/atlas/build.mk15
-rw-r--r--board/atlas/ec.tasklist35
-rw-r--r--board/atlas/gpio.inc152
-rw-r--r--board/atlas/usb_pd_policy.c453
7 files changed, 1815 insertions, 0 deletions
diff --git a/board/atlas/battery.c b/board/atlas/battery.c
new file mode 100644
index 0000000000..d764367d0c
--- /dev/null
+++ b/board/atlas/battery.c
@@ -0,0 +1,293 @@
+/* Copyright 2018 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.
+ *
+ * Placeholder values for temporary battery pack.
+ */
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "bd9995x.h"
+#include "charge_ramp.h"
+#include "charge_state.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_CHARGER, format, ## args)
+
+/* Shutdown mode parameter to write to manufacturer access register */
+#define SB_SHUTDOWN_DATA 0x0010
+
+enum battery_type {
+ BATTERY_LG,
+ BATTERY_LISHEN,
+ BATTERY_SIMPLO,
+ BATTERY_TYPE_COUNT,
+};
+
+struct board_batt_params {
+ const char *manuf_name;
+ const struct battery_info *batt_info;
+};
+
+/*
+ * Set LISHEN as default since the LG precharge current level could cause the
+ * LISHEN battery to not accept charge when it's recovering from a fully
+ * discharged state.
+ */
+#define DEFAULT_BATTERY_TYPE BATTERY_LISHEN
+static enum battery_present batt_pres_prev = BP_NOT_SURE;
+static enum battery_type board_battery_type = BATTERY_TYPE_COUNT;
+
+/* Battery may delay reporting battery present */
+static int battery_report_present = 1;
+
+/*
+ * Battery info for LG A50. Note that the fields start_charging_min/max and
+ * charging_min/max are not used for the Eve charger. The effective temperature
+ * limits are given by discharging_min/max_c.
+ */
+static const struct battery_info batt_info_lg = {
+ .voltage_max = TARGET_WITH_MARGIN(8800, 5), /* mV */
+ .voltage_normal = 7700,
+ .voltage_min = 6100, /* Add 100mV for charger accuracy */
+ .precharge_current = 256, /* mA */
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 46,
+ .charging_min_c = 10,
+ .charging_max_c = 50,
+ .discharging_min_c = 0,
+ .discharging_max_c = 60,
+};
+
+/*
+ * Battery info for LISHEN. Note that the fields start_charging_min/max and
+ * charging_min/max are not used for the Eve charger. The effective temperature
+ * limits are given by discharging_min/max_c.
+ */
+static const struct battery_info batt_info_lishen = {
+ .voltage_max = TARGET_WITH_MARGIN(8800, 5), /* mV */
+ .voltage_normal = 7700,
+ .voltage_min = 6100, /* Add 100mV for charger accuracy */
+ .precharge_current = 256, /* mA */
+ .start_charging_min_c = 0,
+ .start_charging_max_c = 46,
+ .charging_min_c = 10,
+ .charging_max_c = 50,
+ .discharging_min_c = 0,
+ .discharging_max_c = 60,
+};
+
+static const struct board_batt_params info[] = {
+ [BATTERY_LG] = {
+ .manuf_name = "LG A50",
+ .batt_info = &batt_info_lg,
+ },
+
+ [BATTERY_LISHEN] = {
+ .manuf_name = "Lishen A50",
+ .batt_info = &batt_info_lishen,
+ },
+
+ [BATTERY_SIMPLO] = {
+ .manuf_name = "Simplo A50",
+ .batt_info = &batt_info_lishen,
+ },
+
+};
+BUILD_ASSERT(ARRAY_SIZE(info) == BATTERY_TYPE_COUNT);
+
+/* Get type of the battery connected on the board */
+static int board_get_battery_type(void)
+{
+ char name[3];
+ int i;
+
+ if (!battery_manufacturer_name(name, sizeof(name))) {
+ for (i = 0; i < BATTERY_TYPE_COUNT; i++) {
+ if (!strncasecmp(name, info[i].manuf_name,
+ ARRAY_SIZE(name)-1)) {
+ board_battery_type = i;
+ break;
+ }
+ }
+ }
+
+ return board_battery_type;
+}
+
+/*
+ * Initialize the battery type for the board.
+ *
+ * Very first battery info is called by the charger driver to initialize
+ * the charger parameters hence initialize the battery type for the board
+ * as soon as the I2C is initialized.
+ */
+static void board_init_battery_type(void)
+{
+ if (board_get_battery_type() != BATTERY_TYPE_COUNT)
+ CPRINTS("found batt: %s", info[board_battery_type].manuf_name);
+ else
+ CPRINTS("battery not found");
+}
+DECLARE_HOOK(HOOK_INIT, board_init_battery_type, HOOK_PRIO_INIT_I2C + 1);
+
+const struct battery_info *battery_get_info(void)
+{
+ return info[board_battery_type == BATTERY_TYPE_COUNT ?
+ DEFAULT_BATTERY_TYPE : board_battery_type].batt_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 EC_RES_ERROR;
+
+ rv = sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+ return rv ? EC_RES_ERROR : EC_RES_SUCCESS;
+}
+
+int charger_profile_override(struct charge_state_data *curr)
+{
+ const struct battery_info *batt_info;
+ /* battery temp in 0.1 deg C */
+ int bat_temp_c = curr->batt.temperature - 2731;
+
+ batt_info = battery_get_info();
+ /* Don't charge if outside of allowable temperature range */
+ if (bat_temp_c >= batt_info->charging_max_c * 10 ||
+ bat_temp_c < batt_info->charging_min_c * 10) {
+ curr->requested_current = 0;
+ curr->requested_voltage = 0;
+ curr->batt.flags &= ~BATT_FLAG_WANT_CHARGE;
+ curr->state = ST_IDLE;
+ }
+ return 0;
+}
+
+/* Customs options controllable by host command. */
+#define PARAM_FASTCHARGE (CS_PARAM_CUSTOM_PROFILE_MIN + 0)
+
+enum ec_status charger_profile_override_get_param(uint32_t param,
+ uint32_t *value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+enum ec_status charger_profile_override_set_param(uint32_t param,
+ uint32_t value)
+{
+ return EC_RES_INVALID_PARAM;
+}
+
+enum battery_present battery_hw_present(void)
+{
+ /* The GPIO is low when the battery is physically present */
+ return gpio_get_level(GPIO_BATTERY_PRESENT_L) ? BP_NO : BP_YES;
+}
+
+static int battery_init(void)
+{
+ int batt_status;
+
+ return battery_status(&batt_status) ? 0 :
+ !!(batt_status & STATUS_INITIALIZED);
+}
+
+/* Allow booting now that the battery has woke up */
+static void battery_now_present(void)
+{
+ CPRINTS("battery will now report present");
+ battery_report_present = 1;
+}
+DECLARE_DEFERRED(battery_now_present);
+
+/*
+ * Check for case where XDSG bit is set indicating that even
+ * though the FG can be read from the battery, the battery is not able to be
+ * charged or discharged. This situation will happen if a battery disconnect was
+ * intiaited via H1 setting the DISCONN signal to the battery. This will put the
+ * battery pack into a sleep state and when power is reconnected, the FG can be
+ * read, but the battery is still not able to provide power to the system. The
+ * calling function returns batt_pres = BP_NO, which instructs the charging
+ * state machine to prevent powering up the AP on battery alone which could lead
+ * to a brownout event when the battery isn't able yet to provide power to the
+ * system. .
+ */
+static int battery_check_disconnect(void)
+{
+ int rv;
+ uint8_t data[6];
+
+ /* Check if battery discharging is disabled. */
+ rv = sb_read_mfgacc(PARAM_OPERATION_STATUS,
+ SB_ALT_MANUFACTURER_ACCESS, data, sizeof(data));
+ if (rv)
+ return BATTERY_DISCONNECT_ERROR;
+
+ if (data[3] & BATTERY_DISCHARGING_DISABLED)
+ return BATTERY_DISCONNECTED;
+
+ return BATTERY_NOT_DISCONNECTED;
+}
+
+/*
+ * Physical detection of battery.
+ */
+enum battery_present battery_is_present(void)
+{
+ enum battery_present batt_pres;
+ static int battery_report_present_timer_started;
+
+ /* Get the physical hardware status */
+ batt_pres = battery_hw_present();
+
+ /*
+ * Make sure battery status is implemented, I2C transactions are
+ * success & the battery status is Initialized to find out if it
+ * is a working battery and it is not in the cut-off mode.
+ *
+ * If battery I2C fails but VBATT is high, battery is booting from
+ * cut-off mode.
+ *
+ * FETs are turned off after Power Shutdown time.
+ * The device will wake up when a voltage is applied to PACK.
+ * Battery status will be inactive until it is initialized.
+ */
+ if (batt_pres == BP_YES && batt_pres_prev != batt_pres &&
+ (battery_is_cut_off() != BATTERY_CUTOFF_STATE_NORMAL ||
+ battery_check_disconnect() != BATTERY_NOT_DISCONNECTED ||
+ battery_init() == 0)) {
+ battery_report_present = 0;
+ } else if (batt_pres == BP_YES && batt_pres_prev == BP_NO &&
+ !battery_report_present_timer_started) {
+ /*
+ * Wait 1 second before reporting present if it was
+ * previously reported as not present
+ */
+ battery_report_present_timer_started = 1;
+ battery_report_present = 0;
+ hook_call_deferred(&battery_now_present_data, SECOND);
+ }
+
+ if (!battery_report_present)
+ batt_pres = BP_NO;
+
+ batt_pres_prev = batt_pres;
+
+ return batt_pres;
+}
+
+int board_battery_initialized(void)
+{
+ return battery_hw_present() == batt_pres_prev;
+}
diff --git a/board/atlas/board.c b/board/atlas/board.c
new file mode 100644
index 0000000000..1399c6040d
--- /dev/null
+++ b/board/atlas/board.c
@@ -0,0 +1,597 @@
+/* Copyright 2018 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.
+ */
+
+/* Atlas board-specific configuration */
+
+#include "adc_chip.h"
+#include "bd99992gw.h"
+#include "board_config.h"
+#include "charge_manager.h"
+#include "charger.h"
+#include "charge_state.h"
+#include "chipset.h"
+#include "console.h"
+#include "driver/accelgyro_bmi160.h"
+#include "driver/als_opt3001.h"
+#include "driver/tcpm/ps8xxx.h"
+#include "driver/tcpm/tcpci.h"
+#include "driver/tcpm/tcpm.h"
+#include "driver/temp_sensor/bd99992gw.h"
+#include "espi.h"
+#include "extpower.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "keyboard_8042_sharedlib.h"
+#include "keyboard_scan.h"
+#include "lid_switch.h"
+#include "motion_sense.h"
+#include "power_button.h"
+#include "power.h"
+#include "pwm_chip.h"
+#include "pwm.h"
+#include "spi.h"
+#include "switch.h"
+#include "system.h"
+#include "task.h"
+#include "temp_sensor.h"
+#include "timer.h"
+#include "uart.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+#include "util.h"
+
+#define CPRINTS(format, args...) cprints(CC_SYSTEM, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_SYSTEM, format, ## args)
+
+static void tcpc_alert_event(enum gpio_signal signal)
+{
+ if ((signal == GPIO_USB_C0_PD_INT_ODL) &&
+ !gpio_get_level(GPIO_USB_C0_PD_RST_L))
+ return;
+ else if ((signal == GPIO_USB_C1_PD_INT_ODL) &&
+ !gpio_get_level(GPIO_USB_C1_PD_RST_L))
+ return;
+
+#ifdef HAS_TASK_PDCMD
+ /* Exchange status with TCPCs */
+ host_command_pd_send_status(PD_CHARGE_NO_CHANGE);
+#endif
+}
+
+#include "gpio_list.h"
+
+/* power signal list. Must match order of enum power_signal. */
+const struct power_signal_info power_signal_list[] = {
+ {GPIO_SLP_S0_L,
+ POWER_SIGNAL_ACTIVE_HIGH | POWER_SIGNAL_DISABLE_AT_BOOT,
+ "SLP_S0_DEASSERTED"},
+ {VW_SLP_S3_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S3_DEASSERTED"},
+ {VW_SLP_S4_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_S4_DEASSERTED"},
+ {GPIO_PCH_SLP_SUS_L, POWER_SIGNAL_ACTIVE_HIGH, "SLP_SUS_DEASSERTED"},
+ {GPIO_RSMRST_L_PGOOD, POWER_SIGNAL_ACTIVE_HIGH, "RSMRST_L_PGOOD"},
+ {GPIO_PMIC_DPWROK, POWER_SIGNAL_ACTIVE_HIGH, "PMIC_DPWROK"},
+};
+BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
+
+/* Keyboard scan. Increase output_settle_us to 80us from default 50us. */
+struct keyboard_scan_config keyscan_config = {
+ .output_settle_us = 80,
+ .debounce_down_us = 9 * MSEC,
+ .debounce_up_us = 30 * MSEC,
+ .scan_period_us = 3 * MSEC,
+ .min_post_scan_delay_us = 1000,
+ .poll_timeout_us = 100 * MSEC,
+ .actual_key_mask = {
+ 0x3c, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xff,
+ 0xa4, 0xff, 0xfe, 0x55, 0xfa, 0xca /* full set */
+ },
+};
+
+/* PWM channels. Must be in the exactly same order as in enum pwm_channel. */
+const struct pwm_t pwm_channels[] = {
+ [PWM_CH_KBLIGHT] = { 3, 0, 10000 },
+ [PWM_CH_LED1] = { 0, PWM_CONFIG_DSLEEP, 100 },
+ [PWM_CH_LED2] = { 2, PWM_CONFIG_DSLEEP, 100 },
+};
+BUILD_ASSERT(ARRAY_SIZE(pwm_channels) == PWM_CH_COUNT);
+
+/* Hibernate wake configuration */
+const enum gpio_signal hibernate_wake_pins[] = {
+ GPIO_AC_PRESENT,
+ GPIO_LID_OPEN,
+ GPIO_POWER_BUTTON_L,
+};
+const int hibernate_wake_pins_used = ARRAY_SIZE(hibernate_wake_pins);
+
+const struct adc_t adc_channels[] = {
+ /*
+ * Adapter current output or battery charging/discharging current (uV)
+ * 18x amplification on charger side.
+ */
+ [ADC_AMON_BMON] = {
+ "AMON_BMON",
+ NPCX_ADC_CH2,
+ ADC_MAX_VOLT*1000/18,
+ ADC_READ_MAX+1,
+ 0
+ },
+ /*
+ * ISL9238 PSYS output is 1.44 uA/W over 12.4K resistor, to read
+ * 0.8V @ 45 W, i.e. 56250 uW/mV. Using ADC_MAX_VOLT*56250 and
+ * ADC_READ_MAX+1 as multiplier/divider leads to overflows, so we
+ * only divide by 2 (enough to avoid precision issues).
+ */
+ [ADC_PSYS] = {
+ "PSYS",
+ NPCX_ADC_CH3,
+ ADC_MAX_VOLT*56250*2/(ADC_READ_MAX+1),
+ 2,
+ 0
+ },
+};
+BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ADC_CH_COUNT);
+
+/* I2C port map */
+const struct i2c_port_t i2c_ports[] = {
+ {"power", I2C_PORT_POWER, 100,
+ GPIO_EC_I2C3_POWER_SCL, GPIO_EC_I2C3_POWER_SDA},
+ {"tcpc0", I2C_PORT_TCPC0, 400,
+ GPIO_EC_I2C0_USB_C0_SCL, GPIO_EC_I2C0_USB_C0_SDA},
+ {"tcpc1", I2C_PORT_TCPC1, 400,
+ GPIO_EC_I2C0_USB_C1_SCL, GPIO_EC_I2C0_USB_C1_SDA},
+ {"sensor", I2C_PORT_SENSOR, 100,
+ GPIO_EC_I2C2_SENSOR_3V3_SCL, GPIO_EC_I2C2_SENSOR_3V3_SDA},
+ {"battery", I2C_PORT_BATTERY, 100,
+ GPIO_EC_I2C4_BATTERY_SCL, GPIO_EC_I2C4_BATTERY_SDA},
+ {"gyro", I2C_PORT_GYRO, 100,
+ GPIO_EC_I2C1_GYRO_SCL, GPIO_EC_I2C1_GYRO_SDA},
+};
+const unsigned int i2c_ports_used = ARRAY_SIZE(i2c_ports);
+
+/* TCPC mux configuration */
+const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .i2c_host_port = I2C_PORT_TCPC0,
+ .i2c_slave_addr = I2C_ADDR_TCPC,
+ .drv = &ps8xxx_tcpm_drv,
+ .pol = TCPC_ALERT_ACTIVE_LOW
+ },
+ {
+ .i2c_host_port = I2C_PORT_TCPC1,
+ .i2c_slave_addr = I2C_ADDR_TCPC,
+ .drv = &ps8xxx_tcpm_drv,
+ .pol = TCPC_ALERT_ACTIVE_LOW
+ },
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .port_addr = 0,
+ .driver = &tcpci_tcpm_usb_mux_driver,
+ },
+ {
+ .port_addr = 1,
+ .driver = &tcpci_tcpm_usb_mux_driver,
+ },
+};
+
+void board_reset_pd_mcu(void)
+{
+ gpio_set_level(GPIO_USB_PD_RST_L, 0);
+ msleep(PS8XXX_RST_L_RST_H_DELAY_MS);
+ gpio_set_level(GPIO_USB_PD_RST_L, 1);
+}
+
+void board_tcpc_init(void)
+{
+ /* Only reset TCPC if not sysjump */
+ if (!system_jumped_to_this_image())
+ board_reset_pd_mcu();
+
+ gpio_enable_interrupt(GPIO_USB_C0_PD_INT_ODL);
+ gpio_enable_interrupt(GPIO_USB_C1_PD_INT_ODL);
+}
+DECLARE_HOOK(HOOK_INIT, board_tcpc_init, HOOK_PRIO_INIT_I2C+1);
+
+uint16_t tcpc_get_alert_status(void)
+{
+ uint16_t status = 0;
+
+ if (!gpio_get_level(GPIO_USB_C0_PD_INT_ODL)) {
+ if (gpio_get_level(GPIO_USB_C0_PD_RST_L))
+ status |= PD_STATUS_TCPC_ALERT_0;
+ }
+
+ if (!gpio_get_level(GPIO_USB_C1_PD_INT_ODL)) {
+ if (gpio_get_level(GPIO_USB_C1_PD_RST_L))
+ status |= PD_STATUS_TCPC_ALERT_1;
+ }
+
+ return status;
+}
+
+const struct temp_sensor_t temp_sensors[] = {
+ {"Battery", TEMP_SENSOR_TYPE_BATTERY, charge_get_battery_temp, 0, 4},
+ /* BD99992GW temp sensors are only readable in S0 */
+ {"systherm0", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM0, 4},
+ {"systherm1", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM1, 4},
+ {"systherm2", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM2, 4},
+ {"systherm3", TEMP_SENSOR_TYPE_BOARD, bd99992gw_get_val,
+ BD99992GW_ADC_CHANNEL_SYSTHERM3, 4},
+ {"gyro", TEMP_SENSOR_TYPE_BOARD, bmi160_get_sensor_temp, BASE_GYRO, 1},
+};
+BUILD_ASSERT(ARRAY_SIZE(temp_sensors) == TEMP_SENSOR_COUNT);
+
+/*
+ * Check if PMIC fault registers indicate VR fault. If yes, print out fault
+ * register info to console. Additionally, set panic reason so that the OS can
+ * check for fault register info by looking at offset 0x14(PWRSTAT1) and
+ * 0x15(PWRSTAT2) in cros ec panicinfo.
+ */
+static void board_report_pmic_fault(const char *str)
+{
+ int vrfault, pwrstat1 = 0, pwrstat2 = 0;
+ uint32_t info;
+
+ /* RESETIRQ1 -- Bit 4: VRFAULT */
+ if (i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x8, &vrfault)
+ != EC_SUCCESS)
+ return;
+
+ if (!(vrfault & (1 << 4)))
+ return;
+
+ /* VRFAULT has occurred, print VRFAULT status bits. */
+
+ /* PWRSTAT1 */
+ i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x16, &pwrstat1);
+
+ /* PWRSTAT2 */
+ i2c_read8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x17, &pwrstat2);
+
+ CPRINTS("PMIC VRFAULT: %s", str);
+ CPRINTS("PMIC VRFAULT: PWRSTAT1=0x%02x PWRSTAT2=0x%02x", pwrstat1,
+ pwrstat2);
+
+ /* Clear all faults -- Write 1 to clear. */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x8, (1 << 4));
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x16, pwrstat1);
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x17, pwrstat2);
+
+ /*
+ * Status of the fault registers can be checked in the OS by looking at
+ * offset 0x14(PWRSTAT1) and 0x15(PWRSTAT2) in cros ec panicinfo.
+ */
+ info = ((pwrstat2 & 0xFF) << 8) | (pwrstat1 & 0xFF);
+ panic_set_reason(PANIC_SW_PMIC_FAULT, info, 0);
+}
+
+static void board_pmic_disable_slp_s0_vr_decay(void)
+{
+ /*
+ * VCCIOCNT:
+ * Bit 6 (0) - Disable decay of VCCIO on SLP_S0# assertion
+ * Bits 5:4 (00) - Nominal output voltage: 0.850V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x30, 0x3a);
+
+ /*
+ * V18ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (10) - Nominal voltage set to 1.8V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x34, 0x2a);
+
+ /*
+ * V100ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (01) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x37, 0x1a);
+
+ /*
+ * V085ACNT:
+ * Bits 7:6 (00) - Disable low power mode on SLP_S0# assertion
+ * Bits 5:4 (11) - Nominal voltage 0.85V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x38, 0x2a);
+}
+
+static void board_pmic_enable_slp_s0_vr_decay(void)
+{
+ /*
+ * VCCIOCNT:
+ * Bit 6 (1) - Enable decay of VCCIO on SLP_S0# assertion
+ * Bits 5:4 (00) - Nominal output voltage: 0.850V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x30, 0x7a);
+
+ /*
+ * V18ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (10) - Nominal voltage set to 1.8V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x34, 0x6a);
+
+ /*
+ * V100ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (01) - Nominal voltage 1.0V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x37, 0x5a);
+
+ /*
+ * V085ACNT:
+ * Bits 7:6 (01) - Enable low power mode on SLP_S0# assertion
+ * Bits 5:4 (11) - Nominal voltage 0.85V
+ * Bits 3:2 (10) - VR set to AUTO on SLP_S0# de-assertion
+ * Bits 1:0 (10) - VR set to AUTO operating mode
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x38, 0x6a);
+}
+
+void power_board_handle_host_sleep_event(enum host_sleep_event state)
+{
+ if (state == HOST_SLEEP_EVENT_S0IX_SUSPEND)
+ board_pmic_enable_slp_s0_vr_decay();
+ else if (state == HOST_SLEEP_EVENT_S0IX_RESUME)
+ board_pmic_disable_slp_s0_vr_decay();
+}
+
+static void board_pmic_init(void)
+{
+ board_report_pmic_fault("SYSJUMP");
+
+ /* Clear power source events */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x04, 0xff);
+
+ /* Disable power button shutdown timer */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x14, 0x00);
+
+ if (system_jumped_to_this_image())
+ return;
+
+ /* DISCHGCNT2 - enable 100 ohm discharge on V3.3A and V1.8A */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x3d, 0x05);
+
+ /* DISCHGCNT3 - enable 100 ohm discharge on V1.00A */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x3e, 0x04);
+
+ /*
+ * Set V085ACNT / V0.85A Control Register:
+ * Nominal output = 0.85V.
+ */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x38, 0x2a);
+
+ /* VRMODECTRL - disable low-power mode for all rails */
+ i2c_write8(I2C_PORT_PMIC, I2C_ADDR_BD99992, 0x3b, 0x1f);
+}
+DECLARE_HOOK(HOOK_INIT, board_pmic_init, HOOK_PRIO_DEFAULT);
+
+/* Initialize board. */
+static void board_init(void)
+{
+ /* Provide AC status to the PCH */
+ gpio_set_level(GPIO_PCH_ACOK, extpower_is_present());
+
+ /* Enable interrupts from BMI160 sensor. */
+ gpio_enable_interrupt(GPIO_ACCELGYRO3_INT_L);
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+static void board_extpower(void)
+{
+ gpio_set_level(GPIO_PCH_ACOK, extpower_is_present());
+}
+DECLARE_HOOK(HOOK_AC_CHANGE, board_extpower, HOOK_PRIO_DEFAULT);
+
+/**
+ * Set active charge port -- only one port can be active at a time.
+ *
+ * @param charge_port Charge port to enable.
+ *
+ * Returns EC_SUCCESS if charge port is accepted and made active,
+ * EC_ERROR_* otherwise.
+ */
+int board_set_active_charge_port(int charge_port)
+{
+ /* charge port is a physical port */
+ int is_real_port = (charge_port >= 0 &&
+ charge_port < CONFIG_USB_PD_PORT_COUNT);
+ /* check if we are sourcing VBUS on the port */
+ int is_source = gpio_get_level(charge_port == 0 ?
+ GPIO_USB_C0_5V_EN : GPIO_USB_C1_5V_EN);
+
+ if (is_real_port && is_source) {
+ CPRINTF("No charging on source port p%d is ", charge_port);
+ return EC_ERROR_INVAL;
+ }
+
+ CPRINTF("New chg p%d", charge_port);
+
+ if (charge_port == CHARGE_PORT_NONE) {
+ /* Disable both ports */
+ gpio_set_level(GPIO_EN_USB_C0_CHARGE_L, 1);
+ gpio_set_level(GPIO_EN_USB_C1_CHARGE_L, 1);
+ } else {
+ /* Make sure non-charging port is disabled */
+ gpio_set_level(charge_port ? GPIO_EN_USB_C0_CHARGE_L :
+ GPIO_EN_USB_C1_CHARGE_L, 1);
+ /* Enable charging port */
+ gpio_set_level(charge_port ? GPIO_EN_USB_C1_CHARGE_L :
+ GPIO_EN_USB_C0_CHARGE_L, 0);
+ }
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Set the charge limit based upon desired maximum.
+ *
+ * @param port Port number.
+ * @param supplier Charge supplier type.
+ * @param charge_ma Desired charge limit (mA).
+ * @param charge_mv Negotiated charge voltage (mV).
+ */
+void board_set_charge_limit(int port, int supplier, int charge_ma,
+ int max_ma, int charge_mv)
+{
+ /*
+ * Limit the input current to 95% negotiated limit,
+ * to account for the charger chip margin.
+ */
+ charge_ma = (charge_ma * 95) / 100;
+ charge_set_input_current_limit(MAX(charge_ma,
+ CONFIG_CHARGER_INPUT_CURRENT), charge_mv);
+}
+
+static void board_chipset_suspend(void)
+{
+ gpio_set_level(GPIO_ENABLE_BACKLIGHT, 0);
+}
+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, board_chipset_suspend, HOOK_PRIO_DEFAULT);
+
+static void board_chipset_resume(void)
+{
+ gpio_set_level(GPIO_ENABLE_BACKLIGHT, 1);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, board_chipset_resume, HOOK_PRIO_DEFAULT);
+
+static void board_chipset_reset(void)
+{
+ board_report_pmic_fault("CHIPSET RESET");
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESET, board_chipset_reset, HOOK_PRIO_DEFAULT);
+
+int board_get_version(void)
+{
+ static int ver;
+
+ if (!ver) {
+ /*
+ * Read the board EC ID on the tristate strappings
+ * using ternary encoding: 0 = 0, 1 = 1, Hi-Z = 2
+ */
+ uint8_t id0, id1, id2;
+
+ id0 = gpio_get_ternary(GPIO_BOARD_VERSION1);
+ id1 = gpio_get_ternary(GPIO_BOARD_VERSION2);
+ id2 = gpio_get_ternary(GPIO_BOARD_VERSION3);
+
+ ver = (id2 * 9) + (id1 * 3) + id0;
+ CPRINTS("Board ID = %d", ver);
+ }
+
+ return ver;
+}
+
+/* Base Sensor mutex */
+static struct mutex g_base_mutex;
+
+static struct bmi160_drv_data_t g_bmi160_data;
+static struct opt3001_drv_data_t g_opt3001_data = {
+ .scale = 1,
+ .uscale = 0,
+ .offset = 0,
+};
+
+/* Matrix to rotate accelrator into standard reference frame */
+const matrix_3x3_t base_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_S5,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &bmi160_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_GYRO,
+ .addr = BMI160_ADDR0,
+ .rot_standard_ref = &base_standard_ref,
+ .default_range = 2, /* g, enough for laptop. */
+ .min_frequency = BMI160_ACCEL_MIN_FREQ,
+ .max_frequency = BMI160_ACCEL_MAX_FREQ,
+ .config = {
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ .ec_rate = 100 * MSEC,
+ },
+ [SENSOR_CONFIG_EC_S3] = {
+ .odr = 10000 | ROUND_UP_FLAG,
+ },
+ },
+ },
+ [BASE_GYRO] = {
+ .name = "Base Gyro",
+ .active_mask = SENSOR_ACTIVE_S0_S3_S5,
+ .chip = MOTIONSENSE_CHIP_BMI160,
+ .type = MOTIONSENSE_TYPE_GYRO,
+ .location = MOTIONSENSE_LOC_BASE,
+ .drv = &bmi160_drv,
+ .mutex = &g_base_mutex,
+ .drv_data = &g_bmi160_data,
+ .port = I2C_PORT_GYRO,
+ .addr = BMI160_ADDR0,
+ .default_range = 1000, /* dps */
+ .rot_standard_ref = &base_standard_ref,
+ .min_frequency = BMI160_GYRO_MIN_FREQ,
+ .max_frequency = BMI160_GYRO_MAX_FREQ,
+ },
+ [LID_ALS] = {
+ .name = "Light",
+ .active_mask = SENSOR_ACTIVE_S0,
+ .chip = MOTIONSENSE_CHIP_OPT3001,
+ .type = MOTIONSENSE_TYPE_LIGHT,
+ .location = MOTIONSENSE_LOC_LID,
+ .drv = &opt3001_drv,
+ .drv_data = &g_opt3001_data,
+ .port = I2C_PORT_SENSOR,
+ .addr = OPT3001_I2C_ADDR,
+ .rot_standard_ref = NULL,
+ .default_range = 0x10000, /* scale = 1; uscale = 0 */
+ .min_frequency = OPT3001_LIGHT_MIN_FREQ,
+ .max_frequency = OPT3001_LIGHT_MAX_FREQ,
+ .config = {
+ /* Sensor on in S0 */
+ [SENSOR_CONFIG_EC_S0] = {
+ .odr = 1000,
+ },
+ },
+ },
+};
+const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
+
+/* ALS instances when LPC mapping is needed. Each entry directs to a sensor. */
+const struct motion_sensor_t *motion_als_sensors[] = {
+ &motion_sensors[LID_ALS],
+};
+BUILD_ASSERT(ARRAY_SIZE(motion_als_sensors) == ALS_COUNT);
diff --git a/board/atlas/board.h b/board/atlas/board.h
new file mode 100644
index 0000000000..1ef45910c8
--- /dev/null
+++ b/board/atlas/board.h
@@ -0,0 +1,270 @@
+/* Copyright 2018 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.
+ */
+
+/* Atlas board configuration */
+
+#ifndef __CROS_EC_BOARD_H
+#define __CROS_EC_BOARD_H
+
+/*
+ * By default, enable all console messages excepted HC, ACPI and event:
+ * The sensor stack is generating a lot of activity.
+ */
+#define CC_DEFAULT (CC_ALL & ~(CC_MASK(CC_EVENTS) | CC_MASK(CC_LPC)))
+#undef CONFIG_HOSTCMD_DEBUG_MODE
+#define CONFIG_HOSTCMD_DEBUG_MODE HCDEBUG_OFF
+
+/*
+ * Allow dangerous commands.
+ * TODO: Remove this config before production.
+ */
+#define CONFIG_SYSTEM_UNLOCKED
+
+/* EC */
+#define CONFIG_ADC
+#define CONFIG_BACKLIGHT_LID
+#define CONFIG_BOARD_VERSION
+#define CONFIG_BOARD_SPECIFIC_VERSION
+#define CONFIG_BOARD_FORCE_RESET_PIN
+#define CONFIG_DPTF
+#define CONFIG_FPU
+#define CONFIG_I2C
+#define CONFIG_I2C_MASTER
+#define CONFIG_LID_SWITCH
+#define CONFIG_LOW_POWER_IDLE
+#define CONFIG_LTO
+#define CONFIG_CHIP_PANIC_BACKUP
+#define CONFIG_SOFTWARE_PANIC
+#define CONFIG_PWM
+#define CONFIG_PWM_KBLIGHT
+#define CONFIG_SHA256_UNROLLED
+
+/* Internal SPI flash on NPCX7 */
+#define CONFIG_FLASH_SIZE (512 * 1024) /* It's really 1MB. */
+#define CONFIG_SPI_FLASH_REGS
+#define CONFIG_SPI_FLASH_W25Q80 /* Internal SPI flash type. */
+
+#define CONFIG_VBOOT_HASH
+#define CONFIG_VSTORE
+#define CONFIG_VSTORE_SLOT_COUNT 1
+#define CONFIG_WATCHDOG_HELP
+
+/* EC console commands */
+#define CONFIG_CMD_ACCELS
+#define CONFIG_CMD_ACCEL_INFO
+#define CONFIG_CMD_BATT_MFG_ACCESS
+#define CONFIG_CMD_CHARGER_ADC_AMON_BMON
+#define CONFIG_CMD_PD_CONTROL
+
+/* SOC */
+#define CONFIG_CHIPSET_SKYLAKE
+#define CONFIG_CHIPSET_HAS_PLATFORM_PMIC_RESET
+#define CONFIG_CHIPSET_RESET_HOOK
+#define CONFIG_ESPI
+#define CONFIG_ESPI_VW_SIGNALS
+#define CONFIG_LPC
+#define CONFIG_KEYBOARD_BOARD_CONFIG
+#define CONFIG_KEYBOARD_COL2_INVERTED
+#define CONFIG_KEYBOARD_PROTOCOL_8042
+#define CONFIG_KEYBOARD_REFRESH_ROW3
+
+/* Battery */
+#define CONFIG_BATTERY_CRITICAL_SHUTDOWN_CUT_OFF
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_DEVICE_CHEMISTRY "LION"
+#define CONFIG_BATTERY_HW_PRESENT_CUSTOM
+#define CONFIG_BATTERY_PRESENT_CUSTOM
+#define CONFIG_BATTERY_SMART
+
+/* Charger */
+#define CONFIG_CHARGE_MANAGER
+#define CONFIG_CHARGE_MANAGER_EXTERNAL_POWER_LIMIT
+#define CONFIG_CHARGER
+#define CONFIG_CHARGER_V2
+#define CONFIG_CHARGER_ISL9238
+#define CONFIG_CHARGER_DISCHARGE_ON_AC
+#define CONFIG_CHARGER_INPUT_CURRENT 512
+#define CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON 2
+#define CONFIG_CHARGER_PROFILE_OVERRIDE
+#define CONFIG_CHARGER_PSYS
+#define CONFIG_CHARGER_PSYS_READ
+#define CONFIG_CHARGER_SENSE_RESISTOR 10
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 20
+#define CONFIG_EXTPOWER_GPIO
+#define CONFIG_POWER_BUTTON
+#define CONFIG_POWER_BUTTON_X86
+#define CONFIG_POWER_COMMON
+#define CONFIG_POWER_SIGNAL_INTERRUPT_STORM_DETECT_THRESHOLD 30
+#define CONFIG_POWER_S0IX
+#define CONFIG_POWER_TRACK_HOST_SLEEP_STATE
+
+/* Temperature Sensor */
+#define CONFIG_TEMP_SENSOR
+#define CONFIG_TEMP_SENSOR_BD99992GW
+#define CONFIG_THERMISTOR_NCP15WB
+
+/* Sensor */
+#define CONFIG_MKBP_EVENT
+#define CONFIG_MKBP_USE_HOST_EVENT
+#define CONFIG_ALS
+#define CONFIG_ALS_OPT3001
+#define ALS_COUNT 1
+#define OPT3001_I2C_ADDR OPT3001_I2C_ADDR1
+#define CONFIG_ACCEL_FIFO 1024
+#define CONFIG_ACCEL_FIFO_THRES (CONFIG_ACCEL_FIFO / 3)
+#define CONFIG_ACCEL_INTERRUPTS
+#define CONFIG_ACCELGYRO_BMI160
+#define CONFIG_ACCELGYRO_BMI160_INT_EVENT TASK_EVENT_CUSTOM(4)
+
+/* USB */
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_ALT_MODE_DFP
+#define CONFIG_USB_PD_CUSTOM_VDM
+#define CONFIG_USB_PD_DISCHARGE
+#define CONFIG_USB_PD_DISCHARGE_TCPC
+#define CONFIG_USB_PD_DUAL_ROLE
+#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT TYPEC_RP_3A0
+#define CONFIG_USB_PD_PORT_COUNT 2
+#define CONFIG_USB_PD_VBUS_DETECT_TCPC
+#define CONFIG_USB_PD_TCPC_LOW_POWER
+#define CONFIG_USB_PD_TCPM_MUX
+#define CONFIG_USB_PD_TCPM_PS8751
+#define CONFIG_USB_PD_TCPM_TCPCI
+#define CONFIG_USB_PD_TRY_SRC
+#undef CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC
+#define CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC 2
+#define CONFIG_USB_PD_VBUS_MEASURE_NOT_PRESENT
+#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USBC_SS_MUX
+#define CONFIG_USBC_SS_MUX_DFP_ONLY /* FIXME: b/77151299 */
+#define CONFIG_USBC_VCONN
+#define CONFIG_USBC_VCONN_SWAP
+
+/* Optional feature to configure npcx chip */
+#define NPCX_UART_MODULE2 1 /* 1:GPIO64/65 as UART */
+#define NPCX_JTAG_MODULE2 0 /* 0:GPIO21/17/16/20 as JTAG */
+#define NPCX_TACH_SEL2 0 /* 0:GPIO40/73 1:GPIO93/A6 as TACH */
+#define NPCX7_PWM1_SEL 0 /* GPIO C2 is not used as PWM1. */
+
+/* I2C ports */
+#define I2C_PORT_POWER NPCX_I2C_PORT0_0 /* pmic/charger */
+#define I2C_PORT_TCPC0 NPCX_I2C_PORT1_0
+#define I2C_PORT_TCPC1 NPCX_I2C_PORT2_0
+#define I2C_PORT_SENSOR NPCX_I2C_PORT3_0 /* als */
+#define I2C_PORT_BATTERY NPCX_I2C_PORT4_1
+#define I2C_PORT_GYRO NPCX_I2C_PORT5_0 /* accel/gyro */
+
+#define I2C_PORT_ACCEL I2C_PORT_GYRO
+#define I2C_PORT_CHARGER I2C_PORT_POWER
+#define I2C_PORT_PMIC I2C_PORT_POWER
+#define I2C_PORT_THERMAL I2C_PORT_POWER
+
+/* I2C addresses */
+#define I2C_ADDR_TCPC 0x16
+#define I2C_ADDR_MP2949 0x40
+#define I2C_ADDR_BD99992 0x60
+
+#ifndef __ASSEMBLER__
+
+#include "gpio_signal.h"
+#include "registers.h"
+
+enum power_signal {
+ X86_SLP_S0_DEASSERTED,
+ X86_SLP_S3_DEASSERTED,
+ X86_SLP_S4_DEASSERTED,
+ X86_SLP_SUS_DEASSERTED,
+ X86_RSMRST_L_PGOOD,
+ X86_PMIC_DPWROK,
+ POWER_SIGNAL_COUNT
+};
+
+enum temp_sensor_id {
+ TEMP_SENSOR_BATTERY, /* BD99956GW TSENSE */
+ TEMP_SENSOR_SYSTHERM0, /* BD99992GW SYSTHERM0 */
+ TEMP_SENSOR_SYSTHERM1, /* BD99992GW SYSTHERM1 */
+ TEMP_SENSOR_SYSTHERM2, /* BD99992GW SYSTHERM2 */
+ TEMP_SENSOR_SYSTHERM3, /* BD99992GW SYSTHERM3 */
+ TEMP_SENSOR_GYRO,
+ TEMP_SENSOR_COUNT
+};
+
+enum pwm_channel {
+ PWM_CH_KBLIGHT,
+ PWM_CH_LED1,
+ PWM_CH_LED2,
+ PWM_CH_COUNT
+};
+
+enum sensor_id {
+ BASE_ACCEL,
+ BASE_GYRO,
+ LID_ALS,
+};
+
+enum adc_channel {
+ ADC_AMON_BMON,
+ ADC_PSYS,
+ ADC_CH_COUNT
+};
+
+/*
+ * delay to turn on the power supply max is ~16ms.
+ * delay to turn off the power supply max is about ~180ms.
+ */
+#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */
+#define PD_POWER_SUPPLY_TURN_OFF_DELAY 250000 /* us */
+
+/* delay to turn on/off vconn */
+#define PD_VCONN_SWAP_DELAY 5000 /* us */
+
+/* Define typical operating power and max power */
+#define PD_OPERATING_POWER_MW 15000
+#define PD_MAX_POWER_MW 45000
+#define PD_MAX_CURRENT_MA 3000
+#define PD_MAX_VOLTAGE_MV 20000
+
+/* Board specific handlers */
+int board_get_version(void);
+void board_reset_pd_mcu(void);
+
+#endif /* !__ASSEMBLER__ */
+
+/*
+ * these are mappings from signal names used in the atlas schematics
+ * vs. names hard-coded in various parts of the EC codebase.
+ */
+
+#define GPIO_AC_PRESENT GPIO_ROP_EC_ACOK
+#define GPIO_BATTERY_PRESENT_L GPIO_EC_BATT_PRES_L
+#define GPIO_BOARD_VERSION1 GPIO_EC_BRD_ID1
+#define GPIO_BOARD_VERSION2 GPIO_EC_BRD_ID2
+#define GPIO_BOARD_VERSION3 GPIO_EC_BRD_ID3
+#define GPIO_CPU_PROCHOT GPIO_EC_PROCHOT_ODL
+#define GPIO_ENABLE_BACKLIGHT GPIO_EC_BL_DISABLE_L
+#define GPIO_ENTERING_RW GPIO_EC_ENTERING_RW
+#define GPIO_KBD_KSO2 GPIO_EC_KB_ROW02_INV
+#define GPIO_PCH_ACOK GPIO_EC_PCH_ACPRESENT
+#define GPIO_PCH_PWRBTN_L GPIO_EC_PCH_PWR_BTN_ODL
+#define GPIO_PCH_RSMRST_L GPIO_RSMRST_L
+#define GPIO_PCH_SLP_SUS_L GPIO_SLP_SUS_L_PCH
+#define GPIO_PCH_WAKE_L GPIO_EC_PCH_WAKE_L
+#define GPIO_PMIC_DPWROK GPIO_ROP_DSW_PWROK_EC
+#define GPIO_PMIC_SLP_SUS_L GPIO_SLP_SUS_L_PMIC
+#define GPIO_POWER_BUTTON_L GPIO_MECH_PWR_BTN_ODL
+#define GPIO_RSMRST_L_PGOOD GPIO_ROP_EC_RSMRST_L
+#define GPIO_PCH_SLP_S0_L GPIO_SLP_S0_L
+#define GPIO_USB_C0_5V_EN GPIO_EN_USB_C0_5V_OUT
+#define GPIO_USB_C0_PD_RST_L GPIO_USB_PD_RST_L
+#define GPIO_USB_C1_5V_EN GPIO_EN_USB_C1_5V_OUT
+#define GPIO_USB_C1_PD_RST_L GPIO_USB_PD_RST_L
+#define GPIO_WP_L GPIO_EC_WP_L
+
+/* ps8751 requires 1ms reset down assertion */
+#define PS8XXX_RST_L_RST_H_DELAY_MS 1
+
+#endif /* __CROS_EC_BOARD_H */
diff --git a/board/atlas/build.mk b/board/atlas/build.mk
new file mode 100644
index 0000000000..8fbcd50554
--- /dev/null
+++ b/board/atlas/build.mk
@@ -0,0 +1,15 @@
+# -*- makefile -*-
+# Copyright 2018 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
+#
+
+CHIP:=npcx
+CHIP_FAMILY:=npcx7
+CHIP_VARIANT:=npcx7m6f
+
+board-y=board.o
+board-$(CONFIG_BATTERY_SMART)+=battery.o
+board-$(CONFIG_USB_POWER_DELIVERY)+=usb_pd_policy.o
diff --git a/board/atlas/ec.tasklist b/board/atlas/ec.tasklist
new file mode 100644
index 0000000000..ab24aa1f67
--- /dev/null
+++ b/board/atlas/ec.tasklist
@@ -0,0 +1,35 @@
+/* Copyright 2018 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
+ *
+ * For USB PD tasks, IDs must be in consecutive order and correspond to
+ * the port which they are for. See TASK_ID_TO_PD_PORT() macro.
+ */
+
+#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_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_NOTEST(CHIPSET, chipset_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
+ TASK_NOTEST(PDCMD, pd_command_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_ALWAYS(POWERBTN, power_button_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_NOTEST(KEYSCAN, keyboard_scan_task, NULL, TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, LARGER_TASK_STACK_SIZE)
diff --git a/board/atlas/gpio.inc b/board/atlas/gpio.inc
new file mode 100644
index 0000000000..76713cf432
--- /dev/null
+++ b/board/atlas/gpio.inc
@@ -0,0 +1,152 @@
+/* -*- mode:c -*-
+ *
+ * Copyright 2018 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.
+ */
+
+/* Declare symbolic names for all the GPIOs that we care about.
+ * Note: Those with interrupt handlers must be declared first. */
+
+/* USB PD interrupt handler section */
+GPIO_INT(USB_C0_PD_INT_ODL, PIN(6, 1), GPIO_INT_FALLING, tcpc_alert_event)
+GPIO_INT(USB_C1_PD_INT_ODL, PIN(F, 5), GPIO_INT_FALLING, tcpc_alert_event)
+
+/* power seq interrupt handler section */
+GPIO_INT(ROP_DSW_PWROK_EC, PIN(F, 4), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(ROP_EC_RSMRST_L, PIN(E, 2), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(MECH_PWR_BTN_ODL, PIN(0, 1), GPIO_INT_BOTH | GPIO_PULL_UP, power_button_interrupt)
+GPIO_INT(SLP_S0_L, PIN(A, 4), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(SLP_SUS_L_PCH, PIN(D, 4), GPIO_INT_BOTH, power_signal_interrupt)
+GPIO_INT(ROP_EC_ACOK, PIN(0, 0), GPIO_INT_BOTH, extpower_interrupt)
+
+/* misc interrupt handler section */
+GPIO_INT(EC_WP_L, PIN(A, 1), GPIO_INT_BOTH, switch_interrupt)
+GPIO_INT(LID_OPEN, PIN(D, 2), GPIO_INT_BOTH, lid_interrupt)
+GPIO_INT(ACCELGYRO3_INT_L, PIN(4, 1), GPIO_INT_FALLING, bmi160_interrupt)
+
+/* SoC section */
+GPIO(RSMRST_L, PIN(C, 2), GPIO_OUT_LOW) /* SOC Resume Reset */
+GPIO(EC_PCH_PWR_BTN_ODL, PIN(C, 1), GPIO_ODR_HIGH) /* Power button to SOC */
+GPIO(EC_PCH_RTCRST, PIN(7, 6), GPIO_OUT_LOW) /* RTC Reset (broken) */
+GPIO(EC_PCH_WAKE_L, PIN(7, 4), GPIO_ODR_HIGH) /* PCH wake */
+GPIO(EC_PROCHOT_ODL, PIN(3, 4), GPIO_ODR_HIGH) /* SOC PROCHOT# */
+GPIO(SYS_RESET_L, PIN(0, 2), GPIO_ODR_HIGH) /* SOC reset */
+GPIO(USB_C0_DP_HPD, PIN(C, 5), GPIO_OUT_LOW) /* C0 Hotplug */
+GPIO(USB_C1_DP_HPD, PIN(C, 6), GPIO_OUT_LOW) /* C1 Hotplug */
+
+/* power seq section */
+GPIO(EC_PCH_ACPRESENT, PIN(7, 3), GPIO_ODR_LOW) /* ACOK to SOC */
+/* note: SLP_SUS_L_PMIC is an input in the schematics */
+GPIO(SLP_SUS_L_PMIC, PIN(B, 7), GPIO_OUT_LOW) /* SOC SLP_SUS# */
+GPIO(SLP_S4_L, PIN(A, 3), GPIO_INPUT) /* SOC SLP_S4# */
+GPIO(SLP_S3_L, PIN(A, 6), GPIO_INPUT) /* SOC SLP_S3# */
+GPIO(ROP_INT_L, PIN(D, 5), GPIO_INPUT | GPIO_PULL_UP) /* PMIC IRQ (Unused) */
+
+/* USB PD section */
+GPIO(EN_USB_C0_5V_OUT, PIN(6, 7), GPIO_OUT_LOW) /* C0 5V Enable */
+GPIO(EN_USB_C0_CHARGE_L, PIN(0, 3), GPIO_OUT_LOW) /* alt fn */
+GPIO(EN_USB_C0_3A, PIN(6, 2), GPIO_OUT_LOW) /* 1.5/3.0 C0 current limit selection */
+GPIO(EN_USB_C1_5V_OUT, PIN(7, 0), GPIO_OUT_LOW) /* C1 5V Enable */
+GPIO(EN_USB_C1_CHARGE_L, PIN(0, 4), GPIO_OUT_LOW) /* alt fn */
+GPIO(EN_USB_C1_3A, PIN(8, 3), GPIO_OUT_LOW) /* alt fn 1.5/3.0 C1 current limit selection */
+GPIO(USB_PD_RST_L, PIN(F, 1), GPIO_OUT_LOW) /* C0,C1 PD Reset */
+
+/* misc section */
+GPIO(CCD_MODE_ODL, PIN(E, 3), GPIO_INPUT) /* Case Closed Debug Mode */
+GPIO(EC_BATT_PRES_L, PIN(E, 5), GPIO_INPUT) /* Battery Present */
+GPIO(EC_ENTERING_RW, PIN(E, 1), GPIO_OUTPUT) /* EC Entering RW */
+GPIO(EC_BL_DISABLE_L, PIN(D, 3), GPIO_ODR_LOW) /* Enable Backlight */
+GPIO(EC_BRD_ID1, PIN(9, 6), GPIO_INPUT) /* Board ID bit0 */
+GPIO(EC_BRD_ID2, PIN(9, 3), GPIO_INPUT) /* Board ID bit1 */
+GPIO(EC_BRD_ID3, PIN(F, 0), GPIO_INPUT) /* Board ID bit2 */
+GPIO(KBD_BL_EN, PIN(7, 5), GPIO_OUT_LOW) /* KB backlight enable */
+GPIO(EC_PLATFORM_RST, PIN(8, 6), GPIO_OUT_LOW) /* EC Reset to LDO_EN */
+
+/* I2C pins - these will be reconfigured for alternate function below */
+
+GPIO(EC_I2C0_USB_C0_SCL, PIN(9, 0), GPIO_INPUT) /* alt fn I2C1_SCL */
+GPIO(EC_I2C0_USB_C0_SDA, PIN(8, 7), GPIO_INPUT) /* alt fn I2C1_SDA */
+GPIO(EC_I2C0_USB_C1_SCL, PIN(9, 2), GPIO_INPUT) /* alt fn I2C2_SCL */
+GPIO(EC_I2C0_USB_C1_SDA, PIN(9, 1), GPIO_INPUT) /* alt fn I2C2_SDA */
+GPIO(EC_I2C1_GYRO_SCL, PIN(3, 3), GPIO_INPUT) /* alt fn I2C5_SCL */
+GPIO(EC_I2C1_GYRO_SDA, PIN(3, 6), GPIO_INPUT) /* alt fn I2C5_SDA */
+GPIO(EC_I2C2_SENSOR_3V3_SCL, PIN(D, 1), GPIO_INPUT) /* alt fn I2C3_SCL */
+GPIO(EC_I2C2_SENSOR_3V3_SDA, PIN(D, 0), GPIO_INPUT) /* alt fn I2C3_SDA */
+GPIO(EC_I2C3_POWER_SCL, PIN(B, 5), GPIO_INPUT) /* alt fn I2C0_SCL */
+GPIO(EC_I2C3_POWER_SDA, PIN(B, 4), GPIO_INPUT) /* alt fn I2C0_SDA */
+GPIO(EC_I2C4_BATTERY_SCL, PIN(F, 3), GPIO_INPUT) /* alt fn I2C4_SCL */
+GPIO(EC_I2C4_BATTERY_SDA, PIN(F, 2), GPIO_INPUT) /* alt fn I2C4_SDA */
+
+/* Not connected */
+GPIO(NC_GPIO32, PIN(3, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO35, PIN(3, 5), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO37, PIN(3, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO40, PIN(4, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO44, PIN(4, 4), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO45, PIN(4, 5), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO50, PIN(5, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO56, PIN(5, 6), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO57, PIN(5, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO60, PIN(6, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO63, PIN(6, 3), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO66, PIN(6, 6), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO82, PIN(8, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO95, PIN(9, 5), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOA0, PIN(A, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOA2, PIN(A, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOB1, PIN(B, 1), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOB2, PIN(B, 2), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOB3, PIN(B, 3), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOC0, PIN(C, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOC7, PIN(C, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOD6, PIN(D, 6), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOD7, PIN(D, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOE0, PIN(E, 0), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOE4, PIN(E, 4), GPIO_INPUT | GPIO_PULL_UP)
+
+/* WoV is unused */
+GPIO(NC_GPIO94, PIN(9, 4), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIO97, PIN(9, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOA5, PIN(A, 5), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOA7, PIN(A, 7), GPIO_INPUT | GPIO_PULL_UP)
+GPIO(NC_GPIOB0, PIN(B, 0), GPIO_INPUT | GPIO_PULL_UP)
+
+/* gpio alternate functions */
+ALTERNATE(PIN_MASK(0, 0x19), 0, MODULE_GPIO, 0) /* GPIO00|GPIO03|GPIO04 */
+ALTERNATE(PIN_MASK(8, 0x08), 0, MODULE_GPIO, 0) /* GPIO83 */
+ALTERNATE(PIN_MASK(A, 0x08), 0, MODULE_GPIO, 0) /* GPIOA3 */
+ALTERNATE(PIN_MASK(D, 0x04), 0, MODULE_GPIO, 0) /* GPIOD2 */
+
+/* PWM channels */
+ALTERNATE(PIN_MASK(8, 0x01), 0, MODULE_PWM, 0) /* GPIO80 PWM3 KBD_BL_PWM */
+ALTERNATE(PIN_MASK(C, 0x08), 0, MODULE_PWM, 0) /* GPIOC3 PWM0 CHARGE_LED1 */
+ALTERNATE(PIN_MASK(C, 0x10), 0, MODULE_PWM, 0) /* GPIOC4 PWM2 CHARGE_LED2 */
+
+/* I2C alternate functions */
+ALTERNATE(PIN_MASK(B, 0x30), 0, MODULE_I2C, 0) /* I2C0_SCL0|I2C0_SDA0 */
+ALTERNATE(PIN_MASK(9, 0x01), 0, MODULE_I2C, 0) /* I2C1_SCL0 */
+ALTERNATE(PIN_MASK(8, 0x80), 0, MODULE_I2C, 0) /* I2C1_SDA0 */
+ALTERNATE(PIN_MASK(9, 0x06), 0, MODULE_I2C, 0) /* I2C2_SCL0|I2C2_SDA0 */
+ALTERNATE(PIN_MASK(D, 0x03), 0, MODULE_I2C, 0) /* I2C3_SCL0|I2C3_SDA0 */
+ALTERNATE(PIN_MASK(F, 0x0c), 0, MODULE_I2C, 0) /* I2C4_SCL1|I2C4_SDA1 */
+ALTERNATE(PIN_MASK(3, 0x48), 0, MODULE_I2C, 0) /* I2C5_SDA0|I2C5_SCL0 */
+
+/* ADC alternate functions */
+ALTERNATE(PIN_MASK(4, 0x0c), 0, MODULE_ADC, 0) /* ADC2-3 */
+
+/* UART alternate functions */
+ALTERNATE(PIN_MASK(6, 0x30), 0, MODULE_UART, 0) /* UART from EC to Servo */
+
+/* keyboard */
+#define GPIO_KB_INPUT (GPIO_INPUT | GPIO_PULL_UP)
+#define GPIO_KB_OUTPUT (GPIO_ODR_HIGH)
+#define GPIO_KB_OUTPUT_COL2 (GPIO_OUT_LOW)
+
+/* keyboard alternate functions */
+ALTERNATE(PIN_MASK(0, 0xe0), 0, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(1, 0x7f), 0, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(2, 0x03), 0, MODULE_KEYBOARD_SCAN, GPIO_KB_OUTPUT)
+ALTERNATE(PIN_MASK(2, 0xfc), 0, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+ALTERNATE(PIN_MASK(3, 0x03), 0, MODULE_KEYBOARD_SCAN, GPIO_KB_INPUT)
+GPIO(EC_KB_ROW02_INV, PIN(1, 7), GPIO_KB_OUTPUT_COL2)
diff --git a/board/atlas/usb_pd_policy.c b/board/atlas/usb_pd_policy.c
new file mode 100644
index 0000000000..8ce281cf3a
--- /dev/null
+++ b/board/atlas/usb_pd_policy.c
@@ -0,0 +1,453 @@
+/* Copyright 2018 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.
+ */
+
+#include "atomic.h"
+#include "extpower.h"
+#include "charge_manager.h"
+#include "common.h"
+#include "console.h"
+#include "driver/tcpm/ps8xxx.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "tcpci.h"
+#include "timer.h"
+#include "util.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+
+#define PDO_FIXED_FLAGS (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP |\
+ PDO_FIXED_COMM_CAP)
+
+const uint32_t pd_src_pdo[] = {
+ PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS),
+};
+const int pd_src_pdo_cnt = ARRAY_SIZE(pd_src_pdo);
+const uint32_t pd_src_pdo_max[] = {
+ PDO_FIXED(5000, 3000, PDO_FIXED_FLAGS),
+};
+const int pd_src_pdo_max_cnt = ARRAY_SIZE(pd_src_pdo_max);
+
+const uint32_t pd_snk_pdo[] = {
+ PDO_FIXED(5000, 500, PDO_FIXED_FLAGS),
+ PDO_BATT(4750, 21000, 15000),
+ PDO_VAR(4750, 21000, 3000),
+};
+const int pd_snk_pdo_cnt = ARRAY_SIZE(pd_snk_pdo);
+
+int pd_is_valid_input_voltage(int mv)
+{
+ return 1;
+}
+
+void pd_transition_voltage(int idx)
+{
+ /* No-operation: we are always 5V */
+}
+
+static uint8_t vbus_en[CONFIG_USB_PD_PORT_COUNT];
+static uint8_t vbus_rp[CONFIG_USB_PD_PORT_COUNT] = {TYPEC_RP_1A5, TYPEC_RP_1A5};
+
+int board_vbus_source_enabled(int port)
+{
+ return vbus_en[port];
+}
+
+static void board_vbus_update_source_current(int port)
+{
+ enum gpio_signal gpio_5v_en = port ? GPIO_USB_C1_5V_EN :
+ GPIO_USB_C0_5V_EN;
+ enum gpio_signal gpio_3a_en = port ? GPIO_EN_USB_C1_3A :
+ GPIO_EN_USB_C0_3A;
+
+ /*
+ * 1.5 vs 3.0 A limit is controlled by a dedicated gpio where
+ * high = 3.0A and low = 1.5A. VBUS on/off is controlled by
+ * GPIO_USB_C0/1_5V_EN.
+ */
+ gpio_set_level(gpio_3a_en, vbus_rp[port] == TYPEC_RP_3A0 ? 1 : 0);
+ gpio_set_level(gpio_5v_en, vbus_en[port]);
+}
+
+void typec_set_source_current_limit(int port, int rp)
+{
+ vbus_rp[port] = rp;
+
+ /* change the GPIO driving the load switch if needed */
+ board_vbus_update_source_current(port);
+}
+
+int pd_snk_is_vbus_provided(int port)
+{
+ return tcpci_tcpm_get_vbus_level(port);
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ /* Disable charging */
+ gpio_set_level(port ? GPIO_EN_USB_C1_CHARGE_L :
+ GPIO_EN_USB_C0_CHARGE_L, 1);
+
+ /* Ensure we advertise the proper available current quota */
+ charge_manager_source_port(port, 1);
+
+ pd_set_vbus_discharge(port, 0);
+ /* Provide VBUS */
+ vbus_en[port] = 1;
+ board_vbus_update_source_current(port);
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+
+ return EC_SUCCESS; /* we are ready */
+}
+
+void pd_power_supply_reset(int port)
+{
+ int prev_en;
+
+ prev_en = vbus_en[port];
+
+ /* Disable VBUS */
+ vbus_en[port] = 0;
+ board_vbus_update_source_current(port);
+
+ /* Enable discharge if we were previously sourcing 5V */
+ if (prev_en)
+ pd_set_vbus_discharge(port, 1);
+
+ /* Give back the current quota we are no longer using */
+ charge_manager_source_port(port, 0);
+
+ /* notify host of power info change */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+}
+
+int pd_board_checks(void)
+{
+ return EC_SUCCESS;
+}
+
+int pd_check_power_swap(int port)
+{
+ /*
+ * Allow power swap as long as we are acting as a dual role device,
+ * otherwise assume our role is fixed (not in S0 or console command
+ * to fix our role).
+ */
+ return pd_get_dual_role() == PD_DRP_TOGGLE_ON ? 1 : 0;
+}
+
+int pd_check_data_swap(int port, int data_role)
+{
+ /*
+ * Allow data swap if we are a UFP, otherwise don't allow.
+ *
+ * When we are still in the Read-Only firmware, avoid swapping roles
+ * so we don't jump in RW as a SNK/DFP and potentially confuse the
+ * power supply by sending a soft-reset with wrong data role.
+ */
+ return (data_role == PD_ROLE_UFP) &&
+ (system_get_image_copy() != SYSTEM_IMAGE_RO) ? 1 : 0;
+}
+
+int pd_check_vconn_swap(int port)
+{
+ /* in G3, do not allow vconn swap since pp5000_A rail is off */
+ return gpio_get_level(GPIO_PMIC_SLP_SUS_L);
+}
+
+void pd_execute_data_swap(int port, int data_role)
+{
+ /* Do nothing */
+}
+
+void pd_check_pr_role(int port, int pr_role, int flags)
+{
+ /*
+ * If partner is dual-role power and dualrole toggling is on, consider
+ * if a power swap is necessary.
+ */
+ if ((flags & PD_FLAGS_PARTNER_DR_POWER) &&
+ pd_get_dual_role() == PD_DRP_TOGGLE_ON) {
+ /*
+ * If we are a sink and partner is not externally powered, then
+ * swap to become a source. If we are source and partner is
+ * externally powered, swap to become a sink.
+ */
+ int partner_extpower = flags & PD_FLAGS_PARTNER_EXTPOWER;
+
+ if ((!partner_extpower && pr_role == PD_ROLE_SINK) ||
+ (partner_extpower && pr_role == PD_ROLE_SOURCE))
+ pd_request_power_swap(port);
+ }
+}
+
+void pd_check_dr_role(int port, int dr_role, int flags)
+{
+ /* If UFP, try to switch to DFP */
+ if ((flags & PD_FLAGS_PARTNER_DR_DATA) &&
+ dr_role == PD_ROLE_UFP &&
+ system_get_image_copy() != SYSTEM_IMAGE_RO)
+ pd_request_data_swap(port);
+}
+/* ----------------- Vendor Defined Messages ------------------ */
+const struct svdm_response svdm_rsp = {
+ .identity = NULL,
+ .svids = NULL,
+ .modes = NULL,
+};
+
+int pd_custom_vdm(int port, int cnt, uint32_t *payload,
+ uint32_t **rpayload)
+{
+ int cmd = PD_VDO_CMD(payload[0]);
+ uint16_t dev_id = 0;
+ int is_rw, is_latest;
+
+ /* make sure we have some payload */
+ if (cnt == 0)
+ return 0;
+
+ switch (cmd) {
+ case VDO_CMD_VERSION:
+ /* guarantee last byte of payload is null character */
+ *(payload + cnt - 1) = 0;
+ CPRINTF("version: %s\n", (char *)(payload+1));
+ break;
+ case VDO_CMD_READ_INFO:
+ case VDO_CMD_SEND_INFO:
+ /* copy hash */
+ if (cnt == 7) {
+ dev_id = VDO_INFO_HW_DEV_ID(payload[6]);
+ is_rw = VDO_INFO_IS_RW(payload[6]);
+
+ is_latest = pd_dev_store_rw_hash(port,
+ dev_id,
+ payload + 1,
+ is_rw ?
+ SYSTEM_IMAGE_RW :
+ SYSTEM_IMAGE_RO);
+ /*
+ * Send update host event unless our RW hash is
+ * already known to be the latest update RW.
+ */
+ if (!is_rw || !is_latest)
+ pd_send_host_event(PD_EVENT_UPDATE_DEVICE);
+
+ CPRINTF("DevId:%d.%d SW:%d RW:%d\n",
+ HW_DEV_ID_MAJ(dev_id),
+ HW_DEV_ID_MIN(dev_id),
+ VDO_INFO_SW_DBG_VER(payload[6]),
+ is_rw);
+ } else if (cnt == 6) {
+ /* really old devices don't have last byte */
+ pd_dev_store_rw_hash(port, dev_id, payload + 1,
+ SYSTEM_IMAGE_UNKNOWN);
+ }
+ break;
+ case VDO_CMD_CURRENT:
+ CPRINTF("Current: %dmA\n", payload[1]);
+ break;
+ case VDO_CMD_FLIP:
+ usb_mux_flip(port);
+ break;
+#ifdef CONFIG_USB_PD_LOGGING
+ case VDO_CMD_GET_LOG:
+ pd_log_recv_vdm(port, cnt, payload);
+ break;
+#endif /* CONFIG_USB_PD_LOGGING */
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+static int dp_flags[CONFIG_USB_PD_PORT_COUNT];
+static uint32_t dp_status[CONFIG_USB_PD_PORT_COUNT];
+
+static void svdm_safe_dp_mode(int port)
+{
+ /* make DP interface safe until configure */
+ dp_flags[port] = 0;
+ dp_status[port] = 0;
+ usb_mux_set(port, TYPEC_MUX_NONE,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
+}
+
+static int svdm_enter_dp_mode(int port, uint32_t mode_caps)
+{
+ /* Only enter mode if device is DFP_D capable */
+ if (mode_caps & MODE_DP_SNK) {
+ svdm_safe_dp_mode(port);
+ return 0;
+ }
+
+ return -1;
+}
+
+static int svdm_dp_status(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
+ CMD_DP_STATUS | VDO_OPOS(opos));
+ payload[1] = VDO_DP_STATUS(0, /* HPD IRQ ... not applicable */
+ 0, /* HPD level ... not applicable */
+ 0, /* exit DP? ... no */
+ 0, /* usb mode? ... no */
+ 0, /* multi-function ... no */
+ (!!(dp_flags[port] & DP_FLAGS_DP_ON)),
+ 0, /* power low? ... no */
+ (!!(dp_flags[port] & DP_FLAGS_DP_ON)));
+ return 2;
+};
+
+static int svdm_dp_config(int port, uint32_t *payload)
+{
+ int opos = pd_alt_mode(port, USB_SID_DISPLAYPORT);
+ int mf_pref = PD_VDO_DPSTS_MF_PREF(dp_status[port]);
+ int pin_mode = pd_dfp_dp_get_pin_mode(port, dp_status[port]);
+
+ if (!pin_mode)
+ return 0;
+
+ usb_mux_set(port, mf_pref ? TYPEC_MUX_DOCK : TYPEC_MUX_DP,
+ USB_SWITCH_CONNECT, pd_get_polarity(port));
+
+ payload[0] = VDO(USB_SID_DISPLAYPORT, 1,
+ CMD_DP_CONFIG | VDO_OPOS(opos));
+ payload[1] = VDO_DP_CFG(pin_mode, /* pin mode */
+ 1, /* DPv1.3 signaling */
+ 2); /* UFP connected */
+ return 2;
+};
+
+/*
+ * timestamp of the next possible toggle to ensure the 2-ms spacing
+ * between IRQ_HPD.
+ */
+static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_COUNT];
+
+#define PORT_TO_HPD(port) ((port) ? GPIO_USB_C1_DP_HPD : GPIO_USB_C0_DP_HPD)
+
+static void svdm_dp_post_config(int port)
+{
+ dp_flags[port] |= DP_FLAGS_DP_ON;
+ if (!(dp_flags[port] & DP_FLAGS_HPD_HI_PENDING))
+ return;
+
+ gpio_set_level(PORT_TO_HPD(port), 1);
+
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+}
+
+static int svdm_dp_attention(int port, uint32_t *payload)
+{
+ int cur_lvl;
+ int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]);
+ int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]);
+ enum gpio_signal hpd = PORT_TO_HPD(port);
+
+ cur_lvl = gpio_get_level(hpd);
+ dp_status[port] = payload[1];
+
+ /* Its initial DP status message prior to config */
+ if (!(dp_flags[port] & DP_FLAGS_DP_ON)) {
+ if (lvl)
+ dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING;
+ return 1;
+ }
+
+ if (irq & cur_lvl) {
+ uint64_t now = get_time().val;
+ /* wait for the minimum spacing between IRQ_HPD if needed */
+ if (now < hpd_deadline[port])
+ usleep(hpd_deadline[port] - now);
+
+ /* generate IRQ_HPD pulse */
+ gpio_set_level(hpd, 0);
+ usleep(HPD_DSTREAM_DEBOUNCE_IRQ);
+ gpio_set_level(hpd, 1);
+
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+ } else if (irq & !cur_lvl) {
+ CPRINTF("ERR:HPD:IRQ&LOW\n");
+ return 0; /* nak */
+ } else {
+ gpio_set_level(hpd, lvl);
+ /* set the minimum time delay (2ms) for the next HPD IRQ */
+ hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL;
+ }
+ /* ack */
+ return 1;
+}
+
+static void svdm_exit_dp_mode(int port)
+{
+ svdm_safe_dp_mode(port);
+ gpio_set_level(PORT_TO_HPD(port), 0);
+}
+
+static int svdm_enter_gfu_mode(int port, uint32_t mode_caps)
+{
+ /* Always enter GFU mode */
+ return 0;
+}
+
+static void svdm_exit_gfu_mode(int port)
+{
+}
+
+static int svdm_gfu_status(int port, uint32_t *payload)
+{
+ /*
+ * This is called after enter mode is successful, send unstructured
+ * VDM to read info.
+ */
+ pd_send_vdm(port, USB_VID_GOOGLE, VDO_CMD_READ_INFO, NULL, 0);
+ return 0;
+}
+
+static int svdm_gfu_config(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+static int svdm_gfu_attention(int port, uint32_t *payload)
+{
+ return 0;
+}
+
+const struct svdm_amode_fx supported_modes[] = {
+ {
+ .svid = USB_SID_DISPLAYPORT,
+ .enter = &svdm_enter_dp_mode,
+ .status = &svdm_dp_status,
+ .config = &svdm_dp_config,
+ .post_config = &svdm_dp_post_config,
+ .attention = &svdm_dp_attention,
+ .exit = &svdm_exit_dp_mode,
+ },
+ {
+ .svid = USB_VID_GOOGLE,
+ .enter = &svdm_enter_gfu_mode,
+ .status = &svdm_gfu_status,
+ .config = &svdm_gfu_config,
+ .attention = &svdm_gfu_attention,
+ .exit = &svdm_exit_gfu_mode,
+ }
+};
+const int supported_modes_cnt = ARRAY_SIZE(supported_modes);
+#endif /* CONFIG_USB_PD_ALT_MODE_DFP */