summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2022-07-30 17:04:09 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-08-04 16:07:58 +0000
commitfd17e4661220def8023e64d62d3d052da1ccb835 (patch)
tree3794536d0fc08d5d90da5f7c915c079ebd83105b
parent42d2e470451d10420f70cb263377cc5ebaab02f9 (diff)
downloadchrome-ec-fd17e4661220def8023e64d62d3d052da1ccb835.tar.gz
rex: Add support for battery/charging/USBC port 0
This CL adds config options and dts info for battery and charging. In addition, this CL adds support for USBC port 0. Charging depends on battery and there is also a dependency on USBC support, so this blocks must be added together. BRANCH=none BUG=b:240434243 TEST=zmake build rex Signed-off-by: Scott Collyer <scollyer@google.com> Change-Id: I180dd01f4b1b6e05a83677c9e5adc59829035c5c Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3803584 Reviewed-by: Fabio Baltieri <fabiobaltieri@google.com> Commit-Queue: Scott Collyer <scollyer@chromium.org> Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Vijay P Hiremath <vijay.p.hiremath@intel.com>
-rw-r--r--zephyr/projects/rex/BUILD.py2
-rw-r--r--zephyr/projects/rex/CMakeLists.txt3
-rw-r--r--zephyr/projects/rex/battery.dts12
-rw-r--r--zephyr/projects/rex/generated.dts3
-rw-r--r--zephyr/projects/rex/interrupts.dts20
-rw-r--r--zephyr/projects/rex/prj.conf46
-rw-r--r--zephyr/projects/rex/rex.dts64
-rw-r--r--zephyr/projects/rex/src/usb_pd_policy.c77
-rw-r--r--zephyr/projects/rex/src/usbc_config.c287
-rw-r--r--zephyr/projects/rex/usbc.dts51
10 files changed, 556 insertions, 9 deletions
diff --git a/zephyr/projects/rex/BUILD.py b/zephyr/projects/rex/BUILD.py
index 10abc7d3be..e19e46fc49 100644
--- a/zephyr/projects/rex/BUILD.py
+++ b/zephyr/projects/rex/BUILD.py
@@ -33,6 +33,8 @@ register_variant(
here / "generated.dts",
here / "interrupts.dts",
here / "power_signals.dts",
+ here / "battery.dts",
+ here / "usbc.dts",
],
extra_kconfig_files=[here / "prj_rex.conf"],
)
diff --git a/zephyr/projects/rex/CMakeLists.txt b/zephyr/projects/rex/CMakeLists.txt
index b724145961..469d8c918c 100644
--- a/zephyr/projects/rex/CMakeLists.txt
+++ b/zephyr/projects/rex/CMakeLists.txt
@@ -8,4 +8,5 @@ project(rex)
zephyr_include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ "src/board_power.c")
-
+zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USBC "src/usbc_config.c")
+zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USBC "src/usb_pd_policy.c")
diff --git a/zephyr/projects/rex/battery.dts b/zephyr/projects/rex/battery.dts
new file mode 100644
index 0000000000..5dee2e4578
--- /dev/null
+++ b/zephyr/projects/rex/battery.dts
@@ -0,0 +1,12 @@
+/* Copyright 2022 The ChromiumOS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/ {
+ batteries {
+ default_battery: batgqa05l22 {
+ compatible = "powertech,batgqa05l22", "battery-smart";
+ };
+ };
+};
diff --git a/zephyr/projects/rex/generated.dts b/zephyr/projects/rex/generated.dts
index c156892565..5d1c6e3eb8 100644
--- a/zephyr/projects/rex/generated.dts
+++ b/zephyr/projects/rex/generated.dts
@@ -156,9 +156,11 @@
};
gpio_usb_c0_bc12_int_odl: usb_c0_bc12_int_odl {
gpios = <&gpioc 6 GPIO_INPUT>;
+ enum-name = "GPIO_USB_C0_BC12_INT_ODL";
};
gpio_usb_c0_ppc_int_odl: usb_c0_ppc_int_odl {
gpios = <&gpio6 2 GPIO_INPUT>;
+ enum-name = "GPIO_USB_C0_PPC_INT_ODL";
};
gpio_usb_c0_rt_3p3_sx_en: usb_c0_rt_3p3_sx_en {
gpios = <&gpio0 3 GPIO_ODR_HIGH>;
@@ -168,6 +170,7 @@
};
gpio_usb_c0_tcpc_int_odl: usb_c0_tcpc_int_odl {
gpios = <&gpioe 0 GPIO_INPUT>;
+ enum-name = "GPIO_USB_C0_TCPC_INT_ODL";
};
gpio_usb_c0_tcpc_rst_odl: usb_c0_tcpc_rst_odl {
gpios = <&gpio6 7 GPIO_ODR_LOW>;
diff --git a/zephyr/projects/rex/interrupts.dts b/zephyr/projects/rex/interrupts.dts
index ae05c51335..5444bcfd06 100644
--- a/zephyr/projects/rex/interrupts.dts
+++ b/zephyr/projects/rex/interrupts.dts
@@ -22,6 +22,26 @@
flags = <GPIO_INT_EDGE_BOTH>;
handler = "lid_interrupt";
};
+ int_usb_c0_sbu_fault: c0_sbu_fault {
+ irq-pin = <&ioex_usb_c0_sbu_fault_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "sbu_fault_interrupt";
+ };
+ int_usb_c0_tcpc: usb_c0_tcpc {
+ irq-pin = <&gpio_usb_c0_tcpc_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "tcpc_alert_event";
+ };
+ int_usb_c0_ppc: usb_c0_ppc {
+ irq-pin = <&gpio_usb_c0_ppc_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "ppc_interrupt";
+ };
+ int_usb_c0_bc12: usb_c0_bc12 {
+ irq-pin = <&gpio_usb_c0_bc12_int_odl>;
+ flags = <GPIO_INT_EDGE_FALLING>;
+ handler = "bc12_interrupt";
+ };
};
};
diff --git a/zephyr/projects/rex/prj.conf b/zephyr/projects/rex/prj.conf
index f7f00a82d3..116272ba5d 100644
--- a/zephyr/projects/rex/prj.conf
+++ b/zephyr/projects/rex/prj.conf
@@ -53,6 +53,52 @@ CONFIG_ADC=y
# I2C
CONFIG_I2C=y
+# Battery
+CONFIG_PLATFORM_EC_BATTERY=y
+CONFIG_PLATFORM_EC_BATTERY_SMART=y
+CONFIG_PLATFORM_EC_BATTERY_FUEL_GAUGE=y
+CONFIG_PLATFORM_EC_BATTERY_CUT_OFF=y
+CONFIG_PLATFORM_EC_BATTERY_PRESENT_GPIO=y
+CONFIG_PLATFORM_EC_BATTERY_REVIVE_DISCONNECT=y
+
+# Charger
+CONFIG_PLATFORM_EC_CHARGER_DISCHARGE_ON_AC=y
+CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT=512
+CONFIG_PLATFORM_EC_CHARGER_ISL9241=y
+CONFIG_PLATFORM_EC_CHARGER_SENSE_RESISTOR=5
+CONFIG_PLATFORM_EC_CHARGER_SENSE_RESISTOR_AC=10
+CONFIG_PLATFORM_EC_CHARGER_MIN_POWER_MW_FOR_POWER_ON=30000
+CONFIG_PLATFORM_EC_CHARGER_MIN_POWER_MW_FOR_POWER_ON_WITH_BATT=15000
+
+# USBC
+CONFIG_PLATFORM_EC_USBC_PPC=y
+CONFIG_PLATFORM_EC_USBC_PPC_SYV682X=y
+CONFIG_PLATFORM_EC_USBC_PPC_SYV682C=y
+
+CONFIG_PLATFORM_EC_USB_DRP_ACC_TRYSRC=y
+CONFIG_PLATFORM_EC_USB_PD_VBUS_DETECT_TCPC=y
+CONFIG_PLATFORM_EC_USB_PD_DISCHARGE_PPC=y
+CONFIG_PLATFORM_EC_USB_PD_DISCHARGE_TCPC=y
+CONFIG_PLATFORM_EC_USB_PD_FRS=y
+CONFIG_PLATFORM_EC_USB_PD_TCPC_LOW_POWER=y
+CONFIG_PLATFORM_EC_USB_PD_TCPM_TCPCI=y
+CONFIG_PLATFORM_EC_USB_PD_TCPM_NCT38XX=y
+CONFIG_PLATFORM_EC_USB_PD_TRY_SRC=y
+CONFIG_PLATFORM_EC_USB_PD_TCPM_SBU=y
+CONFIG_PLATFORM_EC_USB_PD_DUAL_ROLE_AUTO_TOGGLE=y
+CONFIG_PLATFORM_EC_USBC_RETIMER_INTEL_HB=y
+CONFIG_PLATFORM_EC_USBC_VCONN=y
+CONFIG_PLATFORM_EC_USB_PD_TBT_COMPAT_MODE=y
+CONFIG_PLATFORM_EC_USB_PD_VBUS_MEASURE_CHARGER=y
+CONFIG_PLATFORM_EC_USB_PID=0x504D
+
+# BC 1.2
+CONFIG_PLATFORM_EC_BC12_DETECT_PI3USB9201=y
+
+#USB Mux
+CONFIG_PLATFORM_EC_USB_MUX_VIRTUAL=y
+CONFIG_PLATFORM_EC_USB_MUX_TASK=y
+
# External power
CONFIG_PLATFORM_EC_EXTPOWER_GPIO=y
diff --git a/zephyr/projects/rex/rex.dts b/zephyr/projects/rex/rex.dts
index cc5a4d8efe..6876113731 100644
--- a/zephyr/projects/rex/rex.dts
+++ b/zephyr/projects/rex/rex.dts
@@ -14,10 +14,16 @@
ec_wp_l: write-protect {
gpios = <&gpioa 0 GPIO_INPUT>;
};
-
gpio_ec_entering_rw: ec_entering_rw {
enum-name = "GPIO_ENTERING_RW";
};
+
+ ioex_usb_c0_sbu_fault_odl: usb_c0_sbu_fault_odl {
+ gpios = <&ioex_c0_port1 2 GPIO_INPUT>;
+ };
+ ioex_usb_c0_rt_rst_ls_l: usb_c0_rt_rst_ls_l {
+ gpios = <&ioex_c0_port0 7 GPIO_OUTPUT>;
+ };
};
};
@@ -52,15 +58,57 @@
};
&i2c1_0 {
- label = "I2C_PORT_USB_C0_TCPC";
+ label = "I2C_USB_C0_TCPC";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c1_0_sda_scl_gp87_90>;
pinctrl-names = "default";
+
+ bc12_port0: pi3usb9201@5f {
+ compatible = "pericom,pi3usb9201";
+ status = "okay";
+ reg = <0x5f>;
+ irq = <&int_usb_c0_bc12>;
+ };
+
+ nct3807_C0:nct3807_C0@70 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "nuvoton,nct38xx-gpio";
+ reg = <0x70>;
+ label = "NCT3807_C0";
+
+ ioex_c0_port0:gpio@0 {
+ compatible = "nuvoton,nct38xx-gpio-port";
+ reg = <0x0>;
+ label = "NCT3807_C0_GPIO0";
+ gpio-controller;
+ #gpio-cells = <2>;
+ ngpios = <8>;
+ pin_mask = <0xff>;
+ pinmux_mask = <0xf7>;
+ };
+ ioex_c0_port1:gpio@1 {
+ compatible = "nuvoton,nct38xx-gpio-port";
+ reg = <0x1>;
+ label = "NCT3807_C0_GPIO1";
+ gpio-controller;
+ #gpio-cells = <2>;
+ ngpios = <8>;
+ pin_mask = <0xff>;
+ };
+ };
+
+ nct3808_alert_0 {
+ compatible = "nuvoton,nct38xx-gpio-alert";
+ irq-gpios = <&gpioe 0 GPIO_ACTIVE_LOW>;
+ nct38xx-dev = <&nct3807_C0>;
+ label = "NCT3807_ALERT_0";
+ };
};
&i2c2_0 {
- label = "I2C_PORT_PPC0";
+ label = "I2C_PPC0";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c2_0_sda_scl_gp91_92>;
@@ -68,7 +116,7 @@
};
&i2c3_0 {
- label = "I2C_PORT_USB_C0_C2_MUX";
+ label = "I2C_USB_C0_C2_MUX";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c3_0_sda_scl_gpd0_d1>;
@@ -76,7 +124,7 @@
};
&i2c4_1 {
- label = "I2C_PORT_USB_C1_TCPC";
+ label = "I2_USB_C1_TCPC";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c4_1_sda_scl_gpf2_f3>;
@@ -84,7 +132,7 @@
};
&i2c5_0 {
- label = "I2C_PORT_BATTERY";
+ label = "I2C__BATTERY";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c5_0_sda_scl_gp33_36>;
@@ -92,7 +140,7 @@
};
&i2c6_1 {
- label = "I2C_PORT_USB_1_MIX";
+ label = "I2C_USB_1_MIX";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c6_1_sda_scl_gpe3_e4>;
@@ -100,7 +148,7 @@
};
&i2c7_0 {
- label = "I2C_PORT_CHARGER";
+ label = "I2C_CHARGER";
clock-frequency = <I2C_BITRATE_FAST>;
pinctrl-0 = <&i2c7_0_sda_scl_gpb2_b3>;
diff --git a/zephyr/projects/rex/src/usb_pd_policy.c b/zephyr/projects/rex/src/usb_pd_policy.c
new file mode 100644
index 0000000000..b61fcd6b70
--- /dev/null
+++ b/zephyr/projects/rex/src/usb_pd_policy.c
@@ -0,0 +1,77 @@
+/* Copyright 2022 The ChromiumOS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Shared USB-C policy for Rex boards */
+
+#include <zephyr/drivers/gpio.h>
+
+#include "charge_manager.h"
+#include "chipset.h"
+#include "common.h"
+#include "compile_time_macros.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "ioexpander.h"
+#include "system.h"
+#include "usb_mux.h"
+#include "usb_pd.h"
+#include "usbc_ppc.h"
+#include "util.h"
+
+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. */
+ ppc_vbus_source_enable(port, 0);
+
+ /* Enable discharge if we were previously sourcing 5V */
+ if (IS_ENABLED(CONFIG_USB_PD_DISCHARGE))
+ pd_set_vbus_discharge(port, 1);
+
+ /* Notify host of power info change. */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+}
+
+int pd_set_power_supply_ready(int port)
+{
+ int rv;
+
+ /* Disable charging. */
+ rv = ppc_vbus_sink_enable(port, 0);
+ if (rv)
+ return rv;
+
+ if (IS_ENABLED(CONFIG_USB_PD_DISCHARGE)) {
+ pd_set_vbus_discharge(port, 0);
+ }
+
+ /* Provide Vbus. */
+ rv = ppc_vbus_source_enable(port, 1);
+ if (rv) {
+ return rv;
+ }
+
+ /* Notify host of power info change. */
+ pd_send_host_event(PD_EVENT_POWER_CHANGE);
+
+ return EC_SUCCESS;
+}
+
+/* Used by Vbus discharge common code with CONFIG_USB_PD_DISCHARGE */
+int board_vbus_source_enabled(int port)
+{
+ return tcpm_get_src_ctrl(port);
+}
+
+/* Used by USB charger task with CONFIG_USB_PD_5V_EN_CUSTOM */
+int board_is_sourcing_vbus(int port)
+{
+ return board_vbus_source_enabled(port);
+}
diff --git a/zephyr/projects/rex/src/usbc_config.c b/zephyr/projects/rex/src/usbc_config.c
new file mode 100644
index 0000000000..358beea385
--- /dev/null
+++ b/zephyr/projects/rex/src/usbc_config.c
@@ -0,0 +1,287 @@
+/* Copyright 2022 The ChromiumOS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <zephyr/drivers/gpio.h>
+
+#include "battery_fuel_gauge.h"
+#include "charger.h"
+#include "charge_manager.h"
+#include "charge_ramp.h"
+#include "charge_state_v2.h"
+#include "charge_state.h"
+#include "charger.h"
+#include "driver/charger/isl9241.h"
+#include "driver/retimer/bb_retimer_public.h"
+#include "driver/tcpm/nct38xx.h"
+#include "driver/tcpm/tcpci.h"
+#include "gpio/gpio_int.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "ioexpander.h"
+#include "ppc/syv682x_public.h"
+#include "system.h"
+#include "task.h"
+#include "usb_mux.h"
+#include "usbc_ppc.h"
+
+#define CPRINTSUSB(format, args...) cprints(CC_USBCHARGE, format, ##args)
+#define CPRINTFUSB(format, args...) cprintf(CC_USBCHARGE, format, ##args)
+
+/*******************************************************************/
+/* USB-C Configuration Start */
+#define GPIO_USB_C0_TCPC_INT_NODE \
+ GPIO_DT_FROM_NODELABEL(gpio_usb_c0_tcpc_int_odl)
+#define GPIO_USB_C0_TCPC_RST_NODE \
+ GPIO_DT_FROM_NODELABEL(gpio_usb_c0_tcpc_rst_odl)
+
+/* USB-C ports */
+enum usbc_port { USBC_PORT_C0 = 0, USBC_PORT_COUNT };
+BUILD_ASSERT(USBC_PORT_COUNT == CONFIG_USB_PD_PORT_MAX_COUNT);
+
+static void usbc_interrupt_init(void)
+{
+ /* Enable PPC interrupts. */
+ gpio_enable_dt_interrupt(GPIO_INT_FROM_NODELABEL(int_usb_c0_ppc));
+
+ /* Enable TCPC interrupts. */
+ gpio_enable_dt_interrupt(GPIO_INT_FROM_NODELABEL(int_usb_c0_tcpc));
+
+ /* Enable BC 1.2 interrupts */
+ gpio_enable_dt_interrupt(GPIO_INT_FROM_NODELABEL(int_usb_c0_bc12));
+
+ /* Enable SBU fault interrupts */
+ gpio_enable_dt_interrupt(GPIO_INT_FROM_NODELABEL(int_usb_c0_sbu_fault));
+}
+DECLARE_HOOK(HOOK_INIT, usbc_interrupt_init, HOOK_PRIO_POST_I2C);
+
+void board_overcurrent_event(int port, int is_overcurrented)
+{
+ /*
+ * TODO: Meteorlake PCH does not use Physical GPIO for over current
+ * error, hence Send 'Over Current Virtual Wire' eSPI signal.
+ */
+}
+
+void sbu_fault_interrupt(enum gpio_signal signal)
+{
+ int port = USBC_PORT_C0;
+
+ CPRINTSUSB("C%d: SBU fault", port);
+ pd_handle_overcurrent(port);
+}
+
+void tcpc_alert_event(enum gpio_signal signal)
+{
+ int port;
+
+ switch (signal) {
+ case GPIO_USB_C0_TCPC_INT_ODL:
+ port = 0;
+ break;
+ default:
+ return;
+ }
+
+ schedule_deferred_pd_interrupt(port);
+}
+
+static void reset_nct38xx_port(int port)
+{
+ const struct gpio_dt_spec *reset_gpio_l;
+ const struct device *ioex_port0, *ioex_port1;
+
+ /* TODO(b/225189538): Save and restore ioex signals */
+ if (port == USBC_PORT_C0) {
+ reset_gpio_l = GPIO_DT_FROM_NODELABEL(gpio_usb_c0_tcpc_rst_odl);
+ ioex_port0 = DEVICE_DT_GET(DT_NODELABEL(ioex_c0_port0));
+ ioex_port1 = DEVICE_DT_GET(DT_NODELABEL(ioex_c0_port1));
+ } else {
+ /* Invalid port: do nothing */
+ return;
+ }
+
+ gpio_pin_set_dt(reset_gpio_l, 0);
+ msleep(NCT38XX_RESET_HOLD_DELAY_MS);
+ gpio_pin_set_dt(reset_gpio_l, 1);
+ nct38xx_reset_notify(port);
+ if (NCT3807_RESET_POST_DELAY_MS != 0) {
+ msleep(NCT3807_RESET_POST_DELAY_MS);
+ }
+
+ /* Re-enable the IO expander pins */
+ gpio_reset_port(ioex_port0);
+ gpio_reset_port(ioex_port1);
+}
+
+void board_reset_pd_mcu(void)
+{
+ /* Reset TCPC0 */
+ reset_nct38xx_port(USBC_PORT_C0);
+}
+
+uint16_t tcpc_get_alert_status(void)
+{
+ uint16_t status = 0;
+
+ /*
+ * Check which port has the ALERT line set and ignore if that TCPC has
+ * its reset line active.
+ */
+ if (!GPIO_USB_C0_TCPC_INT_NODE && GPIO_USB_C0_TCPC_RST_NODE) {
+ status |= PD_STATUS_TCPC_ALERT_0;
+ }
+
+ return status;
+}
+
+void ppc_interrupt(enum gpio_signal signal)
+{
+ switch (signal) {
+ case GPIO_USB_C0_PPC_INT_ODL:
+ syv682x_interrupt(USBC_PORT_C0);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void bc12_interrupt(enum gpio_signal signal)
+{
+ switch (signal) {
+ case GPIO_USB_C0_BC12_INT_ODL:
+ usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void board_set_charge_limit(int port, int supplier, int charge_ma, int max_ma,
+ int charge_mv)
+{
+ charge_set_input_current_limit(
+ MAX(charge_ma, CONFIG_CHARGER_INPUT_CURRENT), charge_mv);
+}
+
+static void board_disable_charger_ports(void)
+{
+ int i;
+
+ CPRINTSUSB("Disabling all charger ports");
+
+ /* Disable all ports. */
+ for (i = 0; i < ppc_cnt; i++) {
+ /*
+ * If this port had booted in dead battery mode, go
+ * ahead and reset it so EN_SNK responds properly.
+ */
+ if (nct38xx_get_boot_type(i) == NCT38XX_BOOT_DEAD_BATTERY) {
+ reset_nct38xx_port(i);
+ pd_set_error_recovery(i);
+ }
+
+ /*
+ * Do not return early if one fails otherwise we can
+ * get into a boot loop assertion failure.
+ */
+ if (ppc_vbus_sink_enable(i, 0)) {
+ CPRINTSUSB("Disabling C%d as sink failed.", i);
+ }
+ }
+}
+
+int board_set_active_charge_port(int port)
+{
+ int is_valid_port = (port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT);
+ int i;
+ int rv;
+
+ if (port == CHARGE_PORT_NONE) {
+ board_disable_charger_ports();
+ return EC_SUCCESS;
+ } else if (!is_valid_port) {
+ return EC_ERROR_INVAL;
+ }
+
+ /*
+ * Check if we can reset any ports in dead battery mode
+ *
+ * The NCT3807 may continue to keep EN_SNK low on the dead battery port
+ * and allow a dangerous level of voltage to pass through to the initial
+ * charge port (see b/183660105). We must reset the ports if we have
+ * sufficient battery to do so, which will bring EN_SNK back under
+ * normal control.
+ */
+ rv = EC_SUCCESS;
+ for (i = 0; i < board_get_usb_pd_port_count(); i++) {
+ if (nct38xx_get_boot_type(i) != NCT38XX_BOOT_DEAD_BATTERY) {
+ continue;
+ }
+
+ /* Handle dead battery boot case */
+ CPRINTSUSB("Found dead battery on %d", i);
+ /*
+ * If we have battery, get this port reset ASAP.
+ * This means temporarily rejecting charge manager
+ * sets to it.
+ */
+ if (pd_is_battery_capable()) {
+ reset_nct38xx_port(i);
+ pd_set_error_recovery(i);
+
+ if (port == i) {
+ rv = EC_ERROR_INVAL;
+ }
+ } else if (port != i) {
+ /*
+ * If other port is selected and in dead battery
+ * mode, reset this port. Otherwise, reject
+ * change because we'll brown out.
+ */
+ if (nct38xx_get_boot_type(port) ==
+ NCT38XX_BOOT_DEAD_BATTERY) {
+ reset_nct38xx_port(i);
+ pd_set_error_recovery(i);
+ } else {
+ rv = EC_ERROR_INVAL;
+ }
+ }
+ }
+
+ if (rv != EC_SUCCESS) {
+ return rv;
+ }
+
+ /* Check if the port is sourcing VBUS. */
+ if (tcpm_get_src_ctrl(port)) {
+ CPRINTSUSB("Skip enable C%d", port);
+ return EC_ERROR_INVAL;
+ }
+
+ CPRINTSUSB("New charge port: C%d", port);
+
+ /*
+ * Turn off the other ports' sink path FETs, before enabling the
+ * requested charge port.
+ */
+ for (i = 0; i < ppc_cnt; i++) {
+ if (i == port) {
+ continue;
+ }
+ if (ppc_vbus_sink_enable(i, 0)) {
+ CPRINTSUSB("C%d: sink path disable failed.", i);
+ }
+ }
+
+ /* Enable requested charge port. */
+ if (ppc_vbus_sink_enable(port, 1)) {
+ CPRINTSUSB("C%d: sink path enable failed.", port);
+ return EC_ERROR_UNKNOWN;
+ }
+
+ return EC_SUCCESS;
+}
diff --git a/zephyr/projects/rex/usbc.dts b/zephyr/projects/rex/usbc.dts
new file mode 100644
index 0000000000..2657fc81b7
--- /dev/null
+++ b/zephyr/projects/rex/usbc.dts
@@ -0,0 +1,51 @@
+/* Copyright 2022 The ChromiumOS Authors.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+ #include <dt-bindings/usb_pd_tcpm.h>
+
+/ {
+ usbc {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ usbc_port0: port0@0 {
+ compatible = "named-usbc-port";
+ reg = <0>;
+ bc12 = <&i2c_ec_i2c_usb_c0_ppc_b>;
+ ppc_port0_syv: ppc-port0 {
+ compatible = "silergy,syv682x";
+ status = "okay";
+ port = <&i2c_ec_i2c_usb_c0_ppc_b>;
+ i2c-addr-flags = "SYV682X_ADDR1_FLAGS";
+ };
+ tcpc {
+ compatible = "nuvoton,nct38xx";
+ gpio-dev = <&nct3807_C0>;
+ port = <&i2c_ec_i2c_usb_c0_tcp>;
+ i2c-addr-flags = "NCT38XX_I2C_ADDR1_4_FLAGS";
+ tcpc-flags = <(TCPC_FLAGS_TCPCI_REV2_0)>;
+ };
+ chg {
+ compatible = "intersil,isl9241";
+ status = "okay";
+ port = <&i2c_ec_i2c_mi>;
+ };
+ usb-muxes = <&usb_c0_hb_retimer &virtual_mux_c0>;
+ };
+ port0-muxes {
+ usb_c0_hb_retimer: jhl8040r-c0 {
+ compatible = "intel,jhl8040r";
+ port = <&i2c_ec_i2c_usb_c0_rt>;
+ i2c-addr-flags = <0x56>;
+ ls-en-pin = <&gpio_usb_c0_rt_3p3_sx_en>;
+ int-pin = <&gpio_usb_c0_rt_int_odl>;
+ reset-pin = <&ioex_usb_c0_rt_rst_ls_l>;
+ };
+ virtual_mux_c0: virtual-mux-c0 {
+ compatible = "cros-ec,usbc-mux-virtual";
+ };
+ };
+ };
+};