summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2020-01-14 11:31:25 -0800
committerCommit Bot <commit-bot@chromium.org>2020-01-21 23:55:42 +0000
commitad996f4235597d7a3b64dbfc5c050cc4055a5194 (patch)
treedd41433d0bc3b21dee0e4178d2c2c71fd2215d48
parent39b17e1375b5e149cd9807ac826cdf0dddfa9dbb (diff)
downloadchrome-ec-ad996f4235597d7a3b64dbfc5c050cc4055a5194.tar.gz
waddledoo: Add Type-C, PD, and charging support
This commit adds USB Type-C, Power Delivery and charging support to waddledoo. Waddledoo is using the new TCPMv2, low power mode has been disabled for the time being while we sort out issues with the TCPC. Currently in this state, we cannot actually receive any PD messages, but the PD task is running. BUG=b:147257992 BRANCH=None TEST=Build and flash on waddledoo, verify that we can detect Type-C chargers, and that it can charge a battery. Change-Id: Id30218ef685ed27a934bae3a580f47754f659ac6 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2001127 Commit-Queue: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--baseboard/dedede/baseboard.h69
-rw-r--r--board/waddledoo/battery.c86
-rw-r--r--board/waddledoo/board.c236
-rw-r--r--board/waddledoo/board.h20
-rw-r--r--board/waddledoo/build.mk2
-rw-r--r--board/waddledoo/ec.tasklist10
-rw-r--r--board/waddledoo/gpio.inc5
-rw-r--r--board/waddledoo/usb_pd_policy.c66
8 files changed, 490 insertions, 4 deletions
diff --git a/baseboard/dedede/baseboard.h b/baseboard/dedede/baseboard.h
index a1e85abf1a..b2683c8df9 100644
--- a/baseboard/dedede/baseboard.h
+++ b/baseboard/dedede/baseboard.h
@@ -57,6 +57,8 @@
#define GPIO_POWER_BUTTON_L GPIO_H1_EC_PWR_BTN_ODL
#define GPIO_RSMRST_L_PGOOD GPIO_RSMRST_PWRGD_L
#define GPIO_SYS_RESET_L GPIO_SYS_RST_ODL
+#define GPIO_USB_C0_DP_HPD GPIO_EC_AP_USB_C0_HPD
+#define GPIO_USB_C1_DP_HPD GPIO_EC_AP_USB_C1_HDMI_HPD
#define GPIO_VOLUME_UP_L GPIO_VOLUP_BTN_ODL
#define GPIO_VOLUME_DOWN_L GPIO_VOLDN_BTN_ODL
#define GPIO_WP GPIO_EC_WP_OD
@@ -76,6 +78,12 @@
#define CONFIG_VSTORE
#define CONFIG_VSTORE_SLOT_COUNT 1
+/* Battery */
+#define CONFIG_BATTERY_CUT_OFF
+#define CONFIG_BATTERY_PRESENT_GPIO GPIO_EC_BATTERY_PRES_ODL
+#define CONFIG_BATTERY_REVIVE_DISCONNECT
+#define CONFIG_BATTERY_SMART
+
/* Buttons / Switches */
#define CONFIG_SWITCH
#define CONFIG_VOLUME_BUTTONS
@@ -85,6 +93,17 @@
#define CONFIG_CROS_BOARD_INFO
#define CONFIG_BOARD_VERSION_CBI
+/* Charger */
+#define CONFIG_CHARGE_MANAGER
+#define CONFIG_CHARGER
+#define CONFIG_CHARGER_INPUT_CURRENT 256
+#define CONFIG_USB_CHARGER
+#define CONFIG_USB_PD_5V_EN_CUSTOM
+#define CONFIG_TRICKLE_CHARGING
+
+/* /\* PWM *\/ */
+/* #define CONFIG_PWM */
+
/* SoC */
#define CONFIG_BOARD_HAS_RTC_RESET
#define CONFIG_CHIPSET_JASPERLAKE
@@ -93,10 +112,60 @@
#define CONFIG_POWER_BUTTON_X86
#define CONFIG_POWER_COMMON
+/* USB Type-C */
+#define CONFIG_USB_MUX_PI3USB31532
+#define CONFIG_USBC_SS_MUX
+#define CONFIG_USBC_SS_MUX_DFP_ONLY
+#define CONFIG_USBC_VCONN
+#define CONFIG_USBC_VCONN_SWAP
+
+/* USB PD */
+#define CONFIG_USB_PD_ALT_MODE
+#define CONFIG_USB_PD_ALT_MODE_DFP
+#define CONFIG_USB_PD_DISCHARGE_TCPC
+#define CONFIG_USB_PD_DP_HPD_GPIO
+#define CONFIG_USB_PD_DUAL_ROLE
+#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
+#define CONFIG_USB_PD_LOGGING
+#define CONFIG_USB_PD_PORT_MAX_COUNT 2
+/* #define CONFIG_USB_PD_TCPC_LOW_POWER */
+#define CONFIG_USB_PD_TCPM_MUX
+#define CONFIG_USB_PD_TCPM_TCPCI
+#define CONFIG_USB_PD_TRY_SRC
+/*
+ * Don't attempt Try.Src if the battery is too low. Even batteries which report
+ * 1% state of charge can sometimes disable their discharge FET if the load is
+ * too much. Therefore, set this threshold a bit higher. 5% should leave
+ * plenty of margin.
+ */
+#undef CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC
+#define CONFIG_USB_PD_TRY_SRC_MIN_BATT_SOC 5
+/* #define CONFIG_USB_PD_VBUS_DETECT_CHARGER */
+#define CONFIG_USB_PD_VBUS_DETECT_TCPC
+#define CONFIG_USB_PD_VBUS_MEASURE_CHARGER
+#define CONFIG_USB_PD_DECODE_SOP
+#define CONFIG_USB_PID 0x5042
+#define CONFIG_USB_POWER_DELIVERY
+#define CONFIG_USB_SM_FRAMEWORK
+#define CONFIG_USB_TYPEC_DRP_ACC_TRYSRC
+
+/* Define typical operating power and max power. */
+#define PD_MAX_VOLTAGE_MV 20000
+#define PD_MAX_CURRENT_MA 3000
+#define PD_MAX_POWER_MW 45000
+#define PD_OPERATING_POWER_MW 15000
+
+/* TODO(b:147314141): Verify these timings */
+#define PD_POWER_SUPPLY_TURN_ON_DELAY 30000 /* us */
+#define PD_POWER_SUPPLY_TURN_OFF_DELAY 250000 /* us */
+#define PD_VCONN_SWAP_DELAY 5000 /* us */
#ifndef __ASSEMBLER__
#include "gpio_signal.h"
+/* Reset all TCPCs */
+void board_reset_pd_mcu(void);
+
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BASEBOARD_H */
diff --git a/board/waddledoo/battery.c b/board/waddledoo/battery.c
new file mode 100644
index 0000000000..7f82bcb95f
--- /dev/null
+++ b/board/waddledoo/battery.c
@@ -0,0 +1,86 @@
+/* Copyright 2020 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 information
+ */
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "common.h"
+#include "ec_commands.h"
+#include "extpower.h"
+
+/* Shutdown mode parameter to write to manufacturer access register */
+#define SB_SHUTDOWN_DATA 0x0010
+
+/* Battery info */
+static const struct battery_info info = {
+ .voltage_max = 8880,
+ .voltage_normal = 7700,
+ .voltage_min = 6000,
+ .precharge_current = 160,
+ .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 EC_RES_ERROR;
+
+ rv = sb_write(SB_MANUFACTURER_ACCESS, SB_SHUTDOWN_DATA);
+ return rv ? EC_RES_ERROR : EC_RES_SUCCESS;
+}
+
+enum battery_disconnect_state battery_get_disconnect_state(void)
+{
+ uint8_t data[6];
+ int rv;
+
+ /*
+ * Take note if we find that the battery isn't in disconnect state,
+ * and always return NOT_DISCONNECTED without probing the battery.
+ * This assumes the battery will not go to disconnect state during
+ * runtime.
+ */
+ static int not_disconnected;
+
+ if (not_disconnected)
+ return BATTERY_NOT_DISCONNECTED;
+
+ /* Check if battery discharge FET 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)) {
+ not_disconnected = 1;
+ return BATTERY_NOT_DISCONNECTED;
+ }
+
+ /*
+ * Battery discharge FET is disabled. Verify that we didn't enter this
+ * state due to a safety fault.
+ */
+ rv = sb_read_mfgacc(PARAM_SAFETY_STATUS,
+ SB_ALT_MANUFACTURER_ACCESS, data, sizeof(data));
+ if (rv || data[2] || data[3] || data[4] || data[5])
+ return BATTERY_DISCONNECT_ERROR;
+
+ /* No safety fault, battery is disconnected */
+ return BATTERY_DISCONNECTED;
+}
diff --git a/board/waddledoo/board.c b/board/waddledoo/board.c
index 8ef3330887..a9303be923 100644
--- a/board/waddledoo/board.c
+++ b/board/waddledoo/board.c
@@ -7,24 +7,165 @@
#include "adc_chip.h"
#include "button.h"
+#include "charge_manager.h"
+#include "charge_state_v2.h"
+#include "charger.h"
#include "common.h"
#include "compile_time_macros.h"
#include "driver/accel_bma2x2.h"
#include "driver/accelgyro_bmi160.h"
+#include "driver/bc12/pi3usb9201.h"
#include "driver/sync.h"
+#include "driver/tcpm/raa489000.h"
+#include "driver/tcpm/tcpci.h"
+#include "driver/usb_mux/pi3usb3x532.h"
#include "extpower.h"
#include "gpio.h"
+#include "hooks.h"
#include "i2c.h"
#include "lid_switch.h"
#include "motion_sense.h"
#include "power.h"
#include "power_button.h"
+#include "stdbool.h"
#include "switch.h"
#include "tablet_mode.h"
#include "task.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+
+#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args)
+
+static void tcpc_alert_event(enum gpio_signal s)
+{
+ int port = (s == GPIO_USB_C0_INT_ODL) ? 0 : 1;
+
+ schedule_deferred_pd_interrupt(port);
+}
+
+static void usb_c0_interrupt(enum gpio_signal s)
+{
+ /*
+ * The interrupt line is shared between the TCPC and BC 1.2 detection
+ * chip. Therefore we'll need to check both ICs.
+ */
+ tcpc_alert_event(s);
+ task_set_event(TASK_ID_USB_CHG_P0, USB_CHG_EVENT_BC12, 0);
+}
+
+static void sub_usb_c1_interrupt(enum gpio_signal s)
+{
+ /*
+ * The interrupt line is shared between the TCPC and BC 1.2 detection
+ * chip. Therefore we'll need to check both ICs.
+ */
+ tcpc_alert_event(s);
+ task_set_event(TASK_ID_USB_CHG_P1, USB_CHG_EVENT_BC12, 0);
+}
#include "gpio_list.h"
+void board_init(void)
+{
+ gpio_enable_interrupt(GPIO_USB_C0_INT_ODL);
+ gpio_enable_interrupt(GPIO_SUB_USB_C1_INT_ODL);
+}
+DECLARE_HOOK(HOOK_INIT, board_init, HOOK_PRIO_DEFAULT);
+
+void board_reset_pd_mcu(void)
+{
+ /*
+ * TODO(b:147316511): Here we could issue a digital reset to the IC,
+ * unsure if we actually want to do that or not yet.
+ */
+}
+
+int board_is_sourcing_vbus(int port)
+{
+ int regval;
+
+ tcpc_read(port, TCPC_REG_POWER_STATUS, &regval);
+ return !!(regval & TCPC_REG_POWER_STATUS_SOURCING_VBUS);
+
+}
+
+int board_set_active_charge_port(int port)
+{
+ int is_real_port = (port >= 0 &&
+ port < CONFIG_USB_PD_PORT_MAX_COUNT);
+ int i;
+ int old_port;
+
+ if (!is_real_port && port != CHARGE_PORT_NONE)
+ return EC_ERROR_INVAL;
+
+ old_port = charge_manager_get_active_charge_port();
+
+ CPRINTS("New chg p%d", port);
+
+ /* Disable all ports. */
+ if (port == CHARGE_PORT_NONE) {
+ for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++)
+ tcpc_write(i, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_SNK_CTRL_LOW);
+
+ return EC_SUCCESS;
+ }
+
+ /* Check if port is sourcing VBUS. */
+ if (board_is_sourcing_vbus(port)) {
+ CPRINTS("Skip enable p%d", port);
+ return EC_ERROR_INVAL;
+ }
+
+ /*
+ * Turn off the other ports' sink path FETs, before enabling the
+ * requested charge port.
+ */
+ for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) {
+ if (i == port)
+ continue;
+
+ if (tcpc_write(i, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_SNK_CTRL_LOW))
+ CPRINTS("p%d: sink path disable failed.", i);
+ }
+
+ /*
+ * Stop the charger IC from switching while changing ports. Otherwise,
+ * we can overcurrent the adapter we're switching to. (crbug.com/926056)
+ */
+ if (old_port != CHARGE_PORT_NONE)
+ charger_discharge_on_ac(1);
+
+ /* Enable requested charge port. */
+ if (tcpc_write(port, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_SNK_CTRL_HIGH)) {
+ CPRINTS("p%d: sink path enable failed.", port);
+ charger_discharge_on_ac(0);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ /* Allow the charger IC to begin/continue switching. */
+ charger_discharge_on_ac(0);
+
+ return EC_SUCCESS;
+}
+
+void board_set_charge_limit(int port, int supplier, int charge_ma,
+ int max_ma, int charge_mv)
+{
+ int icl = MAX(charge_ma, CONFIG_CHARGER_INPUT_CURRENT);
+
+ /*
+ * TODO(b:147463641): Characterize the input current limit in case that
+ * a scaling needs to be applied here.
+ */
+ charge_set_input_current_limit(icl, charge_mv);
+}
+
/* Sensors */
static struct mutex g_lid_mutex;
static struct mutex g_base_mutex;
@@ -114,14 +255,105 @@ struct motion_sensor_t motion_sensors[] = {
const unsigned int motion_sensor_count = ARRAY_SIZE(motion_sensors);
-
int extpower_is_present(void)
{
/*
* TODO(b:146651593) We can likely use the charger IC to determine VBUS
* presence.
*/
- return 1;
+ return pd_snk_is_vbus_provided(0) || pd_snk_is_vbus_provided(1);
+}
+
+int pd_snk_is_vbus_provided(int port)
+{
+ int regval = 0;
+
+ tcpc_read(port, TCPC_REG_POWER_STATUS, &regval);
+ return regval & TCPC_REG_POWER_STATUS_VBUS_PRES;
+}
+
+const struct pi3usb9201_config_t pi3usb9201_bc12_chips[] = {
+ {
+ .i2c_port = I2C_PORT_USB_C0,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+
+ {
+ .i2c_port = I2C_PORT_SUB_USB_C1,
+ .i2c_addr_flags = PI3USB9201_I2C_ADDR_3_FLAGS,
+ },
+};
+
+const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_MAX_COUNT] = {
+ {
+ .bus_type = EC_BUS_TYPE_I2C,
+ .i2c_info = {
+ .port = I2C_PORT_USB_C0,
+ .addr_flags = RAA489000_TCPC0_I2C_FLAGS,
+ },
+ .drv = &raa489000_tcpm_drv,
+ },
+
+ {
+ .bus_type = EC_BUS_TYPE_I2C,
+ .i2c_info = {
+ .port = I2C_PORT_SUB_USB_C1,
+ .addr_flags = RAA489000_TCPC0_I2C_FLAGS,
+ },
+ .drv = &raa489000_tcpm_drv,
+ },
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_MAX_COUNT] = {
+ {
+ .port_addr = MUX_PORT_AND_ADDR(I2C_PORT_USB_C0, 0x54),
+ .driver = &pi3usb3x532_usb_mux_driver,
+ },
+ {
+ .port_addr = MUX_PORT_AND_ADDR(I2C_PORT_SUB_USB_C1, 0x54),
+ .driver = &pi3usb3x532_usb_mux_driver,
+ }
+};
+
+uint16_t tcpc_get_alert_status(void)
+{
+ uint16_t status = 0;
+ int regval;
+
+ /*
+ * The interrupt line is shared between the TCPC and BC1.2 detector IC.
+ * Therefore, go out and actually read the alert registers to report the
+ * alert status.
+ */
+ if (!gpio_get_level(GPIO_USB_C0_INT_ODL)) {
+ /*
+ * TODO(b:147716486) If we decide to handle TCPCIv2.0, we cannot
+ * ignore bits 14:12 any longer.
+ */
+ if (!tcpc_read16(0, TCPC_REG_ALERT, &regval)) {
+ /* The TCPCI v1.0 spec says to ignore bits 14:12. */
+ regval &= ~((1 << 14) | (1 << 13) | (1 << 12));
+
+ if (regval)
+ status |= PD_STATUS_TCPC_ALERT_0;
+ }
+ }
+
+ if (!gpio_get_level(GPIO_SUB_USB_C1_INT_ODL)) {
+ /*
+ * TODO(b:147716486) If we decide to handle TCPCIv2.0, we cannot
+ * ignore bits 14:12 any longer.
+ */
+ if (!tcpc_read16(1, TCPC_REG_ALERT, &regval)) {
+ /* TCPCI spec v1.0 says to ignore bits 14:12. */
+ regval &= ~((1 << 14) | (1 << 13) | (1 << 12));
+
+ if (regval)
+ status |= PD_STATUS_TCPC_ALERT_1;
+ }
+ }
+
+ return status;
}
#ifndef TEST_BUILD
diff --git a/board/waddledoo/board.h b/board/waddledoo/board.h
index f19f92133e..582bcd1495 100644
--- a/board/waddledoo/board.h
+++ b/board/waddledoo/board.h
@@ -11,12 +11,30 @@
#define VARIANT_DEDEDE_EC_NPCX796FC
#include "baseboard.h"
+/* Charger */
+#define CONFIG_CHARGER_DISCHARGE_ON_AC
+#define CONFIG_CHARGER_RAA489000
+#define CONFIG_CHARGER_SENSE_RESISTOR_AC 10
+#define CONFIG_CHARGER_SENSE_RESISTOR 10
+
+/* EC console commands */
+#define CONFIG_CMD_TCPCI_DUMP
+
+/* USB */
+#define CONFIG_BC12_DETECT_PI3USB9201
+
+/* USB PD */
+#define CONFIG_USB_PD_TCPM_RAA489000
+
/* I2C configuration */
#define I2C_PORT_EEPROM NPCX_I2C_PORT7_0
#define I2C_PORT_BATTERY NPCX_I2C_PORT5_0
#define I2C_PORT_SENSOR NPCX_I2C_PORT0_0
#define I2C_PORT_USB_C0 NPCX_I2C_PORT1_0
#define I2C_PORT_SUB_USB_C1 NPCX_I2C_PORT2_0
+#define I2C_PORT_USB_MUX I2C_PORT_USB_C0
+/* TODO(b:147440290): Need to handle multiple charger ICs */
+#define I2C_PORT_CHARGER I2C_PORT_USB_C0
#define I2C_PORT_ACCEL I2C_PORT_SENSOR
@@ -75,5 +93,7 @@ enum sensor_id {
SENSOR_COUNT
};
+int board_is_sourcing_vbus(int port);
+
#endif /* !__ASSEMBLER__ */
#endif /* __CROS_EC_BOARD_H */
diff --git a/board/waddledoo/build.mk b/board/waddledoo/build.mk
index 620016f814..aeaa29b2a4 100644
--- a/board/waddledoo/build.mk
+++ b/board/waddledoo/build.mk
@@ -11,4 +11,4 @@ CHIP_FAMILY:=npcx7
CHIP_VARIANT:=npcx7m6fc
BASEBOARD:=dedede
-board-y=board.o
+board-y=board.o battery.o usb_pd_policy.o
diff --git a/board/waddledoo/ec.tasklist b/board/waddledoo/ec.tasklist
index 2bc06ded0c..1b0823ccdd 100644
--- a/board/waddledoo/ec.tasklist
+++ b/board/waddledoo/ec.tasklist
@@ -10,8 +10,16 @@
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(MOTIONSENSE, motion_sense_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P0, usb_charger_task, 0, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(USB_CHG_P1, usb_charger_task, 1, LARGER_TASK_STACK_SIZE) \
+ TASK_ALWAYS(CHARGER, charger_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_NOTEST(CHIPSET, chipset_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_NOTEST(PDCMD, pd_command_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, VENTI_TASK_STACK_SIZE) \
- TASK_ALWAYS(POWERBTN, power_button_task, NULL, VENTI_TASK_STACK_SIZE)
+ TASK_ALWAYS(POWERBTN, power_button_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C0, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_C1, pd_task, NULL, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C0, pd_interrupt_handler_task, 0, VENTI_TASK_STACK_SIZE) \
+ TASK_ALWAYS(PD_INT_C1, pd_interrupt_handler_task, 1, VENTI_TASK_STACK_SIZE)
diff --git a/board/waddledoo/gpio.inc b/board/waddledoo/gpio.inc
index ccf041cb44..dd1931e23a 100644
--- a/board/waddledoo/gpio.inc
+++ b/board/waddledoo/gpio.inc
@@ -23,6 +23,10 @@ GPIO_INT(PG_VCCIO_EXT_OD, PIN(B, 0), GPIO_INT_BOTH, power_signal_interrupt)
GPIO_INT(PG_PP5000_U_OD, PIN(E, 2), GPIO_INT_BOTH, power_signal_interrupt)
GPIO_INT(PG_DRAM_OD, PIN(E, 4), GPIO_INT_BOTH, power_signal_interrupt)
+/* USB-C interrupts */
+GPIO_INT(USB_C0_INT_ODL, PIN(6, 2), GPIO_INT_FALLING | GPIO_PULL_UP, usb_c0_interrupt)
+GPIO_INT(SUB_USB_C1_INT_ODL, PIN(F, 5), GPIO_INT_FALLING | GPIO_PULL_UP, sub_usb_c1_interrupt)
+
/* Button interrupts */
GPIO_INT(H1_EC_PWR_BTN_ODL, PIN(0, 1), GPIO_INT_BOTH | GPIO_PULL_UP, power_button_interrupt)
GPIO_INT(VOLDN_BTN_ODL, PIN(4, 0), GPIO_INT_BOTH | GPIO_PULL_UP | GPIO_SEL_1P8V, button_interrupt)
@@ -84,6 +88,7 @@ GPIO(USB_C0_RST_ODL, PIN(9, 7), GPIO_OUT_HIGH) /* currently unused */
GPIO(EC_AP_USB_C1_HDMI_HPD, PIN(9, 6), GPIO_OUT_LOW)
GPIO(EC_AP_USB_C0_HPD, PIN(9, 3), GPIO_OUT_LOW)
GPIO(HDMI_SEL_L, PIN(7, 2), GPIO_OUT_HIGH)
+GPIO(EC_BATTERY_PRES_ODL, PIN(E, 1), GPIO_INPUT)
/*
* Waddledoo doesn't have these physical pins coming to the EC but uses other
diff --git a/board/waddledoo/usb_pd_policy.c b/board/waddledoo/usb_pd_policy.c
new file mode 100644
index 0000000000..bcdf8300c5
--- /dev/null
+++ b/board/waddledoo/usb_pd_policy.c
@@ -0,0 +1,66 @@
+/* Copyright 2020 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 "charge_manager.h"
+#include "chipset.h"
+#include "common.h"
+#include "console.h"
+#include "driver/tcpm/tcpci.h"
+#include "usb_pd.h"
+
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+
+int pd_check_vconn_swap(int port)
+{
+ /* Allow VCONN swaps if the AP is on. */
+ return chipset_in_state(CHIPSET_STATE_ANY_SUSPEND | CHIPSET_STATE_ON);
+}
+
+void pd_power_supply_reset(int port)
+{
+ /* Disable VBUS */
+ tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_SRC_CTRL_LOW);
+
+#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+ /* Give back the current quota we are no longer using */
+ charge_manager_source_port(port, 0);
+#endif /* defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */
+
+ /* Notify host of power info change. */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ int rv;
+
+ if (port >= CONFIG_USB_PD_PORT_MAX_COUNT)
+ return EC_ERROR_INVAL;
+
+ /* Disable charging. */
+ rv = tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_SNK_CTRL_LOW);
+ if (rv)
+ return rv;
+
+ /* Our policy is not to source VBUS when the AP is off. */
+ if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ return EC_ERROR_NOT_POWERED;
+
+ /* Provide Vbus. */
+ rv = tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_SRC_CTRL_HIGH);
+ if (rv)
+ return rv;
+
+#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
+ /* Ensure we advertise the proper available current quota */
+ charge_manager_source_port(port, 1);
+#endif /* defined(CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT) */
+
+ /* Notify host of power info change. */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+
+ return EC_SUCCESS;
+}