summaryrefslogtreecommitdiff
path: root/zephyr/test/drivers/default/src/integration
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/test/drivers/default/src/integration')
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb.c133
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_20v_3a_pd_charger.c231
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_sink.c255
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_source.c248
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_attach_src_snk.c792
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_pd_bist_shared.c193
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_pd_ctrl_msg.c395
-rw-r--r--zephyr/test/drivers/default/src/integration/usbc/usb_pd_rev3.c358
8 files changed, 2605 insertions, 0 deletions
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb.c b/zephyr/test/drivers/default/src/integration/usbc/usb.c
new file mode 100644
index 0000000000..0436f55e93
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb.c
@@ -0,0 +1,133 @@
+/* Copyright 2021 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/kernel.h>
+#include <zephyr/ztest.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "battery_smart.h"
+#include "ec_commands.h"
+#include "ec_tasks.h"
+#include "driver/tcpm/ps8xxx_public.h"
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_ps8xxx.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_drp.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "host_command.h"
+#include "test/drivers/stubs.h"
+#include "tcpm/tcpci.h"
+#include "test/usb_pe.h"
+#include "test/drivers/utils.h"
+#include "test/drivers/test_state.h"
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+#define GPIO_AC_OK_PATH DT_PATH(named_gpios, acok_od)
+#define GPIO_AC_OK_PIN DT_GPIO_PIN(GPIO_AC_OK_PATH, gpios)
+
+#define GPIO_BATT_PRES_ODL_PATH DT_PATH(named_gpios, ec_batt_pres_odl)
+#define GPIO_BATT_PRES_ODL_PORT DT_GPIO_PIN(GPIO_BATT_PRES_ODL_PATH, gpios)
+
+static void integration_usb_before(void *state)
+{
+ const struct emul *tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ const struct emul *tcpci_emul2 = EMUL_GET_USBC_BINDING(1, tcpc);
+ const struct emul *charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+ /* Reset vbus to 0mV */
+ /* TODO(b/217610871): Remove redundant test state cleanup */
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+ const struct emul *battery_emul = EMUL_DT_GET(BATTERY_NODE);
+ struct sbat_emul_bat_data *bat;
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_AC_OK_PATH, gpios));
+
+ ARG_UNUSED(state);
+ /*
+ * TODO(b/217755888): Refactor to using assume API
+ */
+ zassert_ok(tcpc_config[0].drv->init(0), NULL);
+ zassert_ok(tcpc_config[1].drv->init(1), NULL);
+ tcpc_config[USBC_PORT_C0].flags &= ~TCPC_FLAGS_TCPCI_REV2_0;
+ tcpci_emul_set_rev(tcpci_emul, TCPCI_EMUL_REV1_0_VER1_0);
+ pd_set_suspend(0, 0);
+ pd_set_suspend(1, 0);
+ /* Reset to disconnected state. */
+ /*
+ * TODO(b/217755888): Refactor to using assume API
+ */
+ zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul), NULL);
+ zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul2), NULL);
+
+ /* Battery defaults to charging, so reset to not charging. */
+ bat = sbat_emul_get_bat_data(battery_emul);
+ bat->cur = -5;
+
+ /*
+ * TODO(b/217755888): Refactor to using assume API
+ */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_AC_OK_PIN, 0), NULL);
+}
+
+static void integration_usb_after(void *state)
+{
+ const struct emul *tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ const struct emul *tcpci_emul2 = EMUL_GET_USBC_BINDING(1, tcpc);
+ const struct emul *charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+ ARG_UNUSED(state);
+
+ /* TODO: This function should trigger gpios to signal there is nothing
+ * attached to the port.
+ */
+ /*
+ * TODO(b/217755888): Refactor to using assume API
+ */
+ zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul), NULL);
+ zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul2), NULL);
+ /* Give time to actually disconnect */
+ k_sleep(K_SECONDS(1));
+
+ /* Reset vbus to 0mV */
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+}
+
+ZTEST(integration_usb, test_attach_drp)
+{
+ const struct emul *tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ struct tcpci_partner_data my_drp;
+ struct tcpci_drp_emul_data drp_ext;
+ struct tcpci_src_emul_data src_ext;
+ struct tcpci_snk_emul_data snk_ext;
+
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+
+ /* Attach emulated sink */
+ tcpci_partner_init(&my_drp, PD_REV20);
+ my_drp.extensions = tcpci_drp_emul_init(
+ &drp_ext, &my_drp, PD_ROLE_SINK,
+ tcpci_src_emul_init(&src_ext, &my_drp, NULL),
+ tcpci_snk_emul_init(&snk_ext, &my_drp, NULL));
+
+ zassert_ok(tcpci_partner_connect_to_tcpci(&my_drp, tcpci_emul), NULL);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+
+ /*
+ * Test that SRC ready is achieved
+ * TODO: Change it to examining EC_CMD_TYPEC_STATUS
+ */
+ zassert_equal(PE_SNK_READY, get_state_pe(USBC_PORT_C0), NULL);
+ zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul), NULL);
+}
+
+ZTEST_SUITE(integration_usb, drivers_predicate_post_main, NULL,
+ integration_usb_before, integration_usb_after, NULL);
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_20v_3a_pd_charger.c b/zephyr/test/drivers/default/src/integration/usbc/usb_20v_3a_pd_charger.c
new file mode 100644
index 0000000000..3fc73337b9
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_20v_3a_pd_charger.c
@@ -0,0 +1,231 @@
+/* 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/ztest.h>
+
+#include "battery_smart.h"
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_pd.h"
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+struct usb_attach_20v_3a_pd_charger_fixture {
+ struct tcpci_partner_data charger_20v;
+ struct tcpci_src_emul_data src_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static inline void
+connect_charger_to_port(struct usb_attach_20v_3a_pd_charger_fixture *fixture)
+{
+ set_ac_enabled(true);
+ zassume_ok(tcpci_partner_connect_to_tcpci(&fixture->charger_20v,
+ fixture->tcpci_emul),
+ NULL);
+
+ isl923x_emul_set_adc_vbus(fixture->charger_emul,
+ PDO_FIXED_GET_VOLT(fixture->src_ext.pdo[1]));
+
+ /* Wait for PD negotiation and current ramp.
+ * TODO(b/213906889): Check message timing and contents.
+ */
+ k_sleep(K_SECONDS(10));
+}
+
+static inline void disconnect_charger_from_port(
+ struct usb_attach_20v_3a_pd_charger_fixture *fixture)
+{
+ set_ac_enabled(false);
+ zassume_ok(tcpci_emul_disconnect_partner(fixture->tcpci_emul), NULL);
+ isl923x_emul_set_adc_vbus(fixture->charger_emul, 0);
+ k_sleep(K_SECONDS(1));
+}
+
+static void *usb_attach_20v_3a_pd_charger_setup(void)
+{
+ static struct usb_attach_20v_3a_pd_charger_fixture test_fixture;
+
+ /* Get references for the emulators */
+ test_fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ test_fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ /* Initialized the charger to supply 20V and 3A */
+ tcpci_partner_init(&test_fixture.charger_20v, PD_REV20);
+ test_fixture.charger_20v.extensions = tcpci_src_emul_init(
+ &test_fixture.src_ext, &test_fixture.charger_20v, NULL);
+ test_fixture.src_ext.pdo[1] =
+ PDO_FIXED(20000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &test_fixture;
+}
+
+static void usb_attach_20v_3a_pd_charger_before(void *data)
+{
+ connect_charger_to_port(
+ (struct usb_attach_20v_3a_pd_charger_fixture *)data);
+}
+
+static void usb_attach_20v_3a_pd_charger_after(void *data)
+{
+ disconnect_charger_from_port(
+ (struct usb_attach_20v_3a_pd_charger_fixture *)data);
+}
+
+ZTEST_SUITE(usb_attach_20v_3a_pd_charger, drivers_predicate_post_main,
+ usb_attach_20v_3a_pd_charger_setup,
+ usb_attach_20v_3a_pd_charger_before,
+ usb_attach_20v_3a_pd_charger_after, NULL);
+
+ZTEST(usb_attach_20v_3a_pd_charger, test_battery_is_charging)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ uint16_t battery_status;
+
+ zassume_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, 0,
+ "Battery is discharging: %d", battery_status);
+}
+
+ZTEST(usb_attach_20v_3a_pd_charger, test_charge_state)
+{
+ struct ec_response_charge_state state = host_cmd_charge_state(0);
+
+ zassert_true(state.get_state.ac, "AC_OK not triggered");
+ zassert_true(state.get_state.chg_voltage > 0,
+ "Expected a charge voltage, but got %dmV",
+ state.get_state.chg_voltage);
+ zassert_true(state.get_state.chg_current > 0,
+ "Expected a charge current, but got %dmA",
+ state.get_state.chg_current);
+}
+
+ZTEST(usb_attach_20v_3a_pd_charger, test_typec_status)
+{
+ struct ec_response_typec_status status = host_cmd_typec_status(0);
+
+ zassert_true(status.pd_enabled, "PD is disabled");
+ zassert_true(status.dev_connected, "Device disconnected");
+ zassert_true(status.sop_connected, "Charger is not SOP capable");
+ zassert_equal(status.source_cap_count, 2,
+ "Expected 2 source PDOs, but got %d",
+ status.source_cap_count);
+ zassert_equal(status.power_role, PD_ROLE_SINK,
+ "Expected power role to be %d, but got %d", PD_ROLE_SINK,
+ status.power_role);
+}
+
+ZTEST(usb_attach_20v_3a_pd_charger, test_power_info)
+{
+ struct ec_response_usb_pd_power_info info = host_cmd_power_info(0);
+
+ zassert_equal(info.role, USB_PD_PORT_POWER_SINK,
+ "Expected role to be %d, but got %d",
+ USB_PD_PORT_POWER_SINK, info.role);
+ zassert_equal(info.type, USB_CHG_TYPE_PD,
+ "Expected type to be %d, but got %d", USB_CHG_TYPE_PD,
+ info.type);
+ zassert_equal(info.meas.voltage_max, 20000,
+ "Expected charge voltage max of 20000mV, but got %dmV",
+ info.meas.voltage_max);
+ zassert_within(
+ info.meas.voltage_now, 20000, 2000,
+ "Charging voltage expected to be near 20000mV, but was %dmV",
+ info.meas.voltage_now);
+ zassert_equal(info.meas.current_max, 3000,
+ "Current max expected to be 3000mV, but was %dmV",
+ info.meas.current_max);
+ zassert_true(info.meas.current_lim >= 3000,
+ "VBUS max is set to 3000mA, but PD is reporting %dmA",
+ info.meas.current_lim);
+ zassert_equal(info.max_power, 20000 * 3000,
+ "Charging expected to be at %duW, but PD max is %duW",
+ 20000 * 3000, info.max_power);
+}
+
+ZTEST_F(usb_attach_20v_3a_pd_charger, test_disconnect_battery_not_charging)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ uint16_t battery_status;
+
+ disconnect_charger_from_port(fixture);
+ zassert_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, STATUS_DISCHARGING,
+ "Battery is not discharging: %d", battery_status);
+}
+
+ZTEST_F(usb_attach_20v_3a_pd_charger, test_disconnect_charge_state)
+{
+ struct ec_response_charge_state charge_state;
+
+ disconnect_charger_from_port(fixture);
+ charge_state = host_cmd_charge_state(0);
+
+ zassert_false(charge_state.get_state.ac, "AC_OK not triggered");
+ zassert_equal(charge_state.get_state.chg_current, 0,
+ "Max charge current expected 0mA, but was %dmA",
+ charge_state.get_state.chg_current);
+ zassert_equal(charge_state.get_state.chg_input_current,
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ "Charge input current limit expected %dmA, but was %dmA",
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ charge_state.get_state.chg_input_current);
+}
+
+ZTEST_F(usb_attach_20v_3a_pd_charger, test_disconnect_typec_status)
+{
+ struct ec_response_typec_status typec_status;
+
+ disconnect_charger_from_port(fixture);
+ typec_status = host_cmd_typec_status(0);
+
+ zassert_false(typec_status.pd_enabled, NULL);
+ zassert_false(typec_status.dev_connected, NULL);
+ zassert_false(typec_status.sop_connected, NULL);
+ zassert_equal(typec_status.source_cap_count, 0,
+ "Expected 0 source caps, but got %d",
+ typec_status.source_cap_count);
+ zassert_equal(typec_status.power_role, USB_CHG_TYPE_NONE,
+ "Expected power role to be %d, but got %d",
+ USB_CHG_TYPE_NONE, typec_status.power_role);
+}
+
+ZTEST_F(usb_attach_20v_3a_pd_charger, test_disconnect_power_info)
+{
+ struct ec_response_usb_pd_power_info power_info;
+
+ disconnect_charger_from_port(fixture);
+ power_info = host_cmd_power_info(0);
+
+ zassert_equal(power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Expected power role to be %d, but got %d",
+ USB_PD_PORT_POWER_DISCONNECTED, power_info.role);
+ zassert_equal(power_info.type, USB_CHG_TYPE_NONE,
+ "Expected charger type to be %d, but got %s",
+ USB_CHG_TYPE_NONE, power_info.type);
+ zassert_equal(power_info.max_power, 0,
+ "Expected the maximum power to be 0uW, but got %duW",
+ power_info.max_power);
+ zassert_equal(power_info.meas.voltage_max, 0,
+ "Expected maximum voltage of 0mV, but got %dmV",
+ power_info.meas.voltage_max);
+ zassert_within(power_info.meas.voltage_now, 5, 5,
+ "Expected present voltage near 0mV, but got %dmV",
+ power_info.meas.voltage_now);
+ zassert_equal(power_info.meas.current_max, 0,
+ "Expected maximum current of 0mA, but got %dmA",
+ power_info.meas.current_max);
+ zassert_true(power_info.meas.current_lim >= 0,
+ "Expected the PD current limit to be >= 0, but got %dmA",
+ power_info.meas.current_lim);
+}
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_sink.c b/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_sink.c
new file mode 100644
index 0000000000..5654754838
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_sink.c
@@ -0,0 +1,255 @@
+/* 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 <stdint.h>
+#include <zephyr/ztest.h>
+
+#include "battery_smart.h"
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "tcpm/tcpci.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "timer.h"
+#include "usb_pd.h"
+
+struct usb_attach_5v_3a_pd_sink_fixture {
+ struct tcpci_partner_data sink_5v_3a;
+ struct tcpci_snk_emul_data snk_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+/* Chromebooks only charge PD partners at 5v */
+#define TEST_SRC_PORT_VBUS_MV 5000
+#define TEST_SRC_PORT_TARGET_MA 3000
+
+#define TEST_INITIAL_SINK_CAP \
+ PDO_FIXED(TEST_SRC_PORT_VBUS_MV, TEST_SRC_PORT_TARGET_MA, 0)
+/* Only used to verify sink capabilities being received by SRC port */
+#define TEST_ADDITIONAL_SINK_CAP PDO_FIXED(TEST_SRC_PORT_VBUS_MV, 5000, 0)
+
+static void *usb_attach_5v_3a_pd_sink_setup(void)
+{
+ static struct usb_attach_5v_3a_pd_sink_fixture test_fixture;
+
+ /* Get references for the emulators */
+ test_fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ test_fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ return &test_fixture;
+}
+
+static void usb_attach_5v_3a_pd_sink_before(void *data)
+{
+ struct usb_attach_5v_3a_pd_sink_fixture *test_fixture = data;
+
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+
+ /* Initialized the sink to request 5V and 3A */
+ tcpci_partner_init(&test_fixture->sink_5v_3a, PD_REV20);
+ test_fixture->sink_5v_3a.extensions = tcpci_snk_emul_init(
+ &test_fixture->snk_ext, &test_fixture->sink_5v_3a, NULL);
+ test_fixture->snk_ext.pdo[0] = TEST_INITIAL_SINK_CAP;
+ test_fixture->snk_ext.pdo[1] = TEST_ADDITIONAL_SINK_CAP;
+ connect_sink_to_port(&test_fixture->sink_5v_3a,
+ test_fixture->tcpci_emul,
+ test_fixture->charger_emul);
+}
+
+static void usb_attach_5v_3a_pd_sink_after(void *data)
+{
+ struct usb_attach_5v_3a_pd_sink_fixture *test_fixture = data;
+
+ disconnect_sink_from_port(test_fixture->tcpci_emul);
+}
+
+ZTEST_SUITE(usb_attach_5v_3a_pd_sink, drivers_predicate_post_main,
+ usb_attach_5v_3a_pd_sink_setup, usb_attach_5v_3a_pd_sink_before,
+ usb_attach_5v_3a_pd_sink_after, NULL);
+
+ZTEST_F(usb_attach_5v_3a_pd_sink, test_partner_pd_completed)
+{
+ zassert_true(fixture->snk_ext.pd_completed, NULL);
+}
+
+ZTEST(usb_attach_5v_3a_pd_sink, test_battery_is_discharging)
+{
+ const struct emul *emul = EMUL_DT_GET(DT_NODELABEL(battery));
+ uint16_t battery_status;
+
+ zassume_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, STATUS_DISCHARGING,
+ "Battery is not discharging: %d", battery_status);
+}
+
+ZTEST(usb_attach_5v_3a_pd_sink, test_typec_status)
+{
+ struct ec_response_typec_status status = host_cmd_typec_status(0);
+
+ zassert_true(status.pd_enabled, "PD is disabled");
+ zassert_true(status.dev_connected, "Device disconnected");
+ zassert_true(status.sop_connected, "Charger is not SOP capable");
+ zassert_equal(status.sink_cap_count, 2,
+ "Expected 2 sink PDOs, but got %d",
+ status.sink_cap_count);
+ zassert_equal(status.power_role, PD_ROLE_SOURCE,
+ "Expected power role to be %d, but got %d",
+ PD_ROLE_SOURCE, status.power_role);
+}
+
+ZTEST(usb_attach_5v_3a_pd_sink, test_power_info)
+{
+ struct ec_response_usb_pd_power_info info = host_cmd_power_info(0);
+
+ zassert_equal(info.role, USB_PD_PORT_POWER_SOURCE,
+ "Expected role to be %d, but got %d",
+ USB_PD_PORT_POWER_SOURCE, info.role);
+ zassert_equal(info.type, USB_CHG_TYPE_NONE,
+ "Expected type to be %d, but got %d", USB_CHG_TYPE_NONE,
+ info.type);
+ zassert_equal(info.meas.voltage_max, 0,
+ "Expected charge voltage max of 0mV, but got %dmV",
+ info.meas.voltage_max);
+ zassert_within(
+ info.meas.voltage_now, TEST_SRC_PORT_VBUS_MV, 500,
+ "Charging voltage expected to be near 5000mV, but was %dmV",
+ info.meas.voltage_now);
+ zassert_equal(info.meas.current_max, TEST_SRC_PORT_TARGET_MA,
+ "Current max expected to be 1500mV, but was %dmV",
+ info.meas.current_max);
+ zassert_equal(info.meas.current_lim, 0,
+ "VBUS max is set to 0mA, but PD is reporting %dmA",
+ info.meas.current_lim);
+ zassert_equal(info.max_power, 0,
+ "Charging expected to be at %duW, but PD max is %duW", 0,
+ info.max_power);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_sink, test_disconnect_battery_discharging)
+{
+ const struct emul *emul = EMUL_DT_GET(DT_NODELABEL(battery));
+ uint16_t battery_status;
+
+ disconnect_sink_from_port(fixture->tcpci_emul);
+ zassert_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, STATUS_DISCHARGING,
+ "Battery is not discharging: %d", battery_status);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_sink, test_disconnect_charge_state)
+{
+ struct ec_response_charge_state charge_state;
+
+ disconnect_sink_from_port(fixture->tcpci_emul);
+ charge_state = host_cmd_charge_state(0);
+
+ zassert_false(charge_state.get_state.ac, "AC_OK not triggered");
+ zassert_equal(charge_state.get_state.chg_current, 0,
+ "Max charge current expected 0mA, but was %dmA",
+ charge_state.get_state.chg_current);
+ zassert_equal(charge_state.get_state.chg_input_current,
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ "Charge input current limit expected %dmA, but was %dmA",
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ charge_state.get_state.chg_input_current);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_sink, test_disconnect_typec_status)
+{
+ struct ec_response_typec_status typec_status;
+
+ disconnect_sink_from_port(fixture->tcpci_emul);
+ typec_status = host_cmd_typec_status(0);
+
+ zassert_false(typec_status.pd_enabled, NULL);
+ zassert_false(typec_status.dev_connected, NULL);
+ zassert_false(typec_status.sop_connected, NULL);
+ zassert_equal(typec_status.source_cap_count, 0,
+ "Expected 0 source caps, but got %d",
+ typec_status.source_cap_count);
+ zassert_equal(typec_status.power_role, USB_CHG_TYPE_NONE,
+ "Expected power role to be %d, but got %d",
+ USB_CHG_TYPE_NONE, typec_status.power_role);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_sink, test_disconnect_power_info)
+{
+ struct ec_response_usb_pd_power_info power_info;
+
+ disconnect_sink_from_port(fixture->tcpci_emul);
+ power_info = host_cmd_power_info(0);
+
+ zassert_equal(power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Expected power role to be %d, but got %d",
+ USB_PD_PORT_POWER_DISCONNECTED, power_info.role);
+ zassert_equal(power_info.type, USB_CHG_TYPE_NONE,
+ "Expected charger type to be %d, but got %s",
+ USB_CHG_TYPE_NONE, power_info.type);
+ zassert_equal(power_info.max_power, 0,
+ "Expected the maximum power to be 0uW, but got %duW",
+ power_info.max_power);
+ zassert_equal(power_info.meas.voltage_max, 0,
+ "Expected maximum voltage of 0mV, but got %dmV",
+ power_info.meas.voltage_max);
+ zassert_within(power_info.meas.voltage_now, 5, 5,
+ "Expected present voltage near 0mV, but got %dmV",
+ power_info.meas.voltage_now);
+ zassert_equal(power_info.meas.current_max, 0,
+ "Expected maximum current of 0mA, but got %dmA",
+ power_info.meas.current_max);
+ zassert_true(power_info.meas.current_lim >= 0,
+ "Expected the PD current limit to be >= 0, but got %dmA",
+ power_info.meas.current_lim);
+}
+
+/**
+ * @brief TestPurpose: Verify GotoMin message.
+ *
+ * @details
+ * - TCPM is configured initially as Source
+ * - Initiate Goto_Min request
+ * - Verify emulated sink PD negotiation is completed
+ *
+ * Expected Results
+ * - Sink completes Goto Min PD negotiation
+ */
+ZTEST_F(usb_attach_5v_3a_pd_sink, verify_goto_min)
+{
+ pd_dpm_request(0, DPM_REQUEST_GOTO_MIN);
+ k_sleep(K_SECONDS(1));
+
+ zassert_true(fixture->snk_ext.pd_completed, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify Ping message.
+ *
+ * @details
+ * - TCPM is configured initially as Source
+ * - Initiate Ping request
+ * - Verify emulated sink received ping message
+ *
+ * Expected Results
+ * - Sink received ping message
+ */
+ZTEST_F(usb_attach_5v_3a_pd_sink, verify_ping_msg)
+{
+ tcpci_snk_emul_clear_ping_received(&fixture->snk_ext);
+
+ pd_dpm_request(0, DPM_REQUEST_SEND_PING);
+ k_sleep(K_USEC(PD_T_SOURCE_ACTIVITY));
+
+ zassert_true(fixture->snk_ext.ping_received, NULL);
+}
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_source.c b/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_source.c
new file mode 100644
index 0000000000..4d89e8c0d3
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_5v_3a_pd_source.c
@@ -0,0 +1,248 @@
+/* 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/ztest.h>
+
+#include "battery_smart.h"
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "system.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_pd.h"
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+struct usb_attach_5v_3a_pd_source_fixture {
+ struct tcpci_partner_data source_5v_3a;
+ struct tcpci_src_emul_data src_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static void *usb_attach_5v_3a_pd_source_setup(void)
+{
+ static struct usb_attach_5v_3a_pd_source_fixture test_fixture;
+
+ /* Get references for the emulators */
+ test_fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ test_fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ /* Initialized the charger to supply 5V and 3A */
+ tcpci_partner_init(&test_fixture.source_5v_3a, PD_REV20);
+ test_fixture.source_5v_3a.extensions = tcpci_src_emul_init(
+ &test_fixture.src_ext, &test_fixture.source_5v_3a, NULL);
+ test_fixture.src_ext.pdo[1] =
+ PDO_FIXED(5000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &test_fixture;
+}
+
+static void usb_attach_5v_3a_pd_source_before(void *data)
+{
+ struct usb_attach_5v_3a_pd_source_fixture *fixture = data;
+
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->src_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+}
+
+static void usb_attach_5v_3a_pd_source_after(void *data)
+{
+ struct usb_attach_5v_3a_pd_source_fixture *fixture = data;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+}
+
+ZTEST_SUITE(usb_attach_5v_3a_pd_source, drivers_predicate_post_main,
+ usb_attach_5v_3a_pd_source_setup, usb_attach_5v_3a_pd_source_before,
+ usb_attach_5v_3a_pd_source_after, NULL);
+
+ZTEST(usb_attach_5v_3a_pd_source, test_battery_is_charging)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ uint16_t battery_status;
+
+ zassume_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, 0,
+ "Battery is discharging: %d", battery_status);
+}
+
+ZTEST(usb_attach_5v_3a_pd_source, test_charge_state)
+{
+ struct ec_response_charge_state state = host_cmd_charge_state(0);
+
+ zassert_true(state.get_state.ac, "AC_OK not triggered");
+ zassert_true(state.get_state.chg_voltage > 0,
+ "Expected a charge voltage, but got %dmV",
+ state.get_state.chg_voltage);
+ zassert_true(state.get_state.chg_current > 0,
+ "Expected a charge current, but got %dmA",
+ state.get_state.chg_current);
+}
+
+ZTEST(usb_attach_5v_3a_pd_source, test_typec_status)
+{
+ struct ec_response_typec_status status = host_cmd_typec_status(0);
+
+ zassert_true(status.pd_enabled, "PD is disabled");
+ zassert_true(status.dev_connected, "Device disconnected");
+ zassert_true(status.sop_connected, "Charger is not SOP capable");
+ zassert_equal(status.source_cap_count, 2,
+ "Expected 2 source PDOs, but got %d",
+ status.source_cap_count);
+ zassert_equal(status.power_role, PD_ROLE_SINK,
+ "Expected power role to be %d, but got %d", PD_ROLE_SINK,
+ status.power_role);
+}
+
+ZTEST(usb_attach_5v_3a_pd_source, test_power_info)
+{
+ struct ec_response_usb_pd_power_info info = host_cmd_power_info(0);
+
+ zassert_equal(info.role, USB_PD_PORT_POWER_SINK,
+ "Expected role to be %d, but got %d",
+ USB_PD_PORT_POWER_SINK, info.role);
+ zassert_equal(info.type, USB_CHG_TYPE_PD,
+ "Expected type to be %d, but got %d", USB_CHG_TYPE_PD,
+ info.type);
+ zassert_equal(info.meas.voltage_max, 5000,
+ "Expected charge voltage max of 5000mV, but got %dmV",
+ info.meas.voltage_max);
+ zassert_within(
+ info.meas.voltage_now, 5000, 500,
+ "Charging voltage expected to be near 5000mV, but was %dmV",
+ info.meas.voltage_now);
+ zassert_equal(info.meas.current_max, 3000,
+ "Current max expected to be 3000mV, but was %dmV",
+ info.meas.current_max);
+ zassert_true(info.meas.current_lim >= 3000,
+ "VBUS max is set to 3000mA, but PD is reporting %dmA",
+ info.meas.current_lim);
+ zassert_equal(info.max_power, 5000 * 3000,
+ "Charging expected to be at %duW, but PD max is %duW",
+ 5000 * 3000, info.max_power);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source, test_disconnect_battery_not_charging)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ uint16_t battery_status;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ zassert_ok(sbat_emul_get_word_val(emul, SB_BATTERY_STATUS,
+ &battery_status),
+ NULL);
+ zassert_equal(battery_status & STATUS_DISCHARGING, STATUS_DISCHARGING,
+ "Battery is not discharging: %d", battery_status);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source, test_disconnect_charge_state)
+{
+ struct ec_response_charge_state charge_state;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ charge_state = host_cmd_charge_state(0);
+
+ zassert_false(charge_state.get_state.ac, "AC_OK not triggered");
+ zassert_equal(charge_state.get_state.chg_current, 0,
+ "Max charge current expected 0mA, but was %dmA",
+ charge_state.get_state.chg_current);
+ zassert_equal(charge_state.get_state.chg_input_current,
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ "Charge input current limit expected %dmA, but was %dmA",
+ CONFIG_PLATFORM_EC_CHARGER_INPUT_CURRENT,
+ charge_state.get_state.chg_input_current);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source, test_disconnect_typec_status)
+{
+ struct ec_response_typec_status typec_status;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ typec_status = host_cmd_typec_status(0);
+
+ zassert_false(typec_status.pd_enabled, NULL);
+ zassert_false(typec_status.dev_connected, NULL);
+ zassert_false(typec_status.sop_connected, NULL);
+ zassert_equal(typec_status.source_cap_count, 0,
+ "Expected 0 source caps, but got %d",
+ typec_status.source_cap_count);
+ zassert_equal(typec_status.power_role, USB_CHG_TYPE_NONE,
+ "Expected power role to be %d, but got %d",
+ USB_CHG_TYPE_NONE, typec_status.power_role);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source, test_disconnect_power_info)
+{
+ struct ec_response_usb_pd_power_info power_info;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ power_info = host_cmd_power_info(0);
+
+ zassert_equal(power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Expected power role to be %d, but got %d",
+ USB_PD_PORT_POWER_DISCONNECTED, power_info.role);
+ zassert_equal(power_info.type, USB_CHG_TYPE_NONE,
+ "Expected charger type to be %d, but got %s",
+ USB_CHG_TYPE_NONE, power_info.type);
+ zassert_equal(power_info.max_power, 0,
+ "Expected the maximum power to be 0uW, but got %duW",
+ power_info.max_power);
+ zassert_equal(power_info.meas.voltage_max, 0,
+ "Expected maximum voltage of 0mV, but got %dmV",
+ power_info.meas.voltage_max);
+ zassert_within(power_info.meas.voltage_now, 5, 5,
+ "Expected present voltage near 0mV, but got %dmV",
+ power_info.meas.voltage_now);
+ zassert_equal(power_info.meas.current_max, 0,
+ "Expected maximum current of 0mA, but got %dmA",
+ power_info.meas.current_max);
+ zassert_true(power_info.meas.current_lim >= 0,
+ "Expected the PD current limit to be >= 0, but got %dmA",
+ power_info.meas.current_lim);
+}
+
+ZTEST(usb_attach_5v_3a_pd_source,
+ test_ap_can_boot_on_low_battery_while_charging)
+{
+ const struct emul *smart_batt_emul = EMUL_DT_GET(DT_NODELABEL(battery));
+ struct sbat_emul_bat_data *batt_data =
+ sbat_emul_get_bat_data(smart_batt_emul);
+
+ /* Set capacity to what gives a charge percentage less than required
+ * for booting the AP
+ *
+ * Capacaity is reset by emulator's ZTEST_RULE
+ */
+ batt_data->cap = (CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON *
+ batt_data->design_cap / 100) -
+ 1;
+
+ zassert_true(system_can_boot_ap(), NULL);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source,
+ test_ap_fails_to_boot_on_low_battery_while_not_charging)
+{
+ const struct emul *smart_batt_emul = EMUL_DT_GET(DT_NODELABEL(battery));
+ struct sbat_emul_bat_data *batt_data =
+ sbat_emul_get_bat_data(smart_batt_emul);
+
+ /* Set capacity to what gives a charge percentage less than required
+ * for booting the AP
+ *
+ * Capacaity is reset by emulator's ZTEST_RULE
+ */
+ batt_data->cap = (CONFIG_CHARGER_MIN_BAT_PCT_FOR_POWER_ON *
+ batt_data->design_cap / 100) -
+ 1;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+
+ zassert_false(system_can_boot_ap(), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_attach_src_snk.c b/zephyr/test/drivers/default/src/integration/usbc/usb_attach_src_snk.c
new file mode 100644
index 0000000000..761bb9daf1
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_attach_src_snk.c
@@ -0,0 +1,792 @@
+/* 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/kernel.h>
+#include <zephyr/ztest.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "ec_commands.h"
+#include "ec_tasks.h"
+#include "driver/tcpm/ps8xxx_public.h"
+#include "emul/emul_isl923x.h"
+#include "emul/tcpc/emul_ps8xxx.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "host_command.h"
+#include "test/drivers/stubs.h"
+#include "tcpm/tcpci.h"
+#include "test/usb_pe.h"
+#include "test/drivers/utils.h"
+#include "test/drivers/test_state.h"
+
+#define SNK_PORT USBC_PORT_C0
+#define SRC_PORT USBC_PORT_C1
+
+#define DEFAULT_VBUS_MV 5000
+
+/* Determined by CONFIG_PLATFORM_EC_USB_PD_PULLUP */
+#define DEFAULT_VBUS_SRC_PORT_MA 1500
+
+/* SRC TCPCI Emulator attaches as TYPEC_CC_VOLT_RP_3_0 */
+#define DEFAULT_VBUS_SNK_PORT_MA 3000
+
+#define DEFAULT_SINK_SENT_TO_SOURCE_CAP_COUNT 1
+#define DEFAULT_SOURCE_SENT_TO_SINK_CAP_COUNT 1
+
+struct emul_state {
+ /* TODO(b/217737667): Remove driver specific code. */
+ const struct emul *tcpci_generic_emul;
+ const struct emul *tcpci_ps8xxx_emul;
+ const struct emul *charger_isl923x_emul;
+ struct tcpci_partner_data my_src;
+ struct tcpci_src_emul_data src_ext;
+ struct tcpci_partner_data my_snk;
+ struct tcpci_snk_emul_data snk_ext;
+};
+
+struct integration_usb_attach_src_then_snk_fixture {
+ struct emul_state my_emulator_state;
+};
+
+struct integration_usb_attach_snk_then_src_fixture {
+ struct emul_state my_emulator_state;
+};
+
+static void integration_usb_setup(struct emul_state *fixture)
+{
+ const struct emul *tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ const struct emul *tcpci_emul2 = EMUL_GET_USBC_BINDING(1, tcpc);
+ const struct emul *charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ /* Setting these are required because compiler believes these values are
+ * not compile time constants.
+ */
+ /*
+ * TODO(b/217758708): emuls should be identified at compile-time.
+ */
+ fixture->tcpci_generic_emul = tcpci_emul;
+ fixture->tcpci_ps8xxx_emul = tcpci_emul2;
+ fixture->charger_isl923x_emul = charger_emul;
+
+ tcpci_partner_init(&fixture->my_snk, PD_REV20);
+ fixture->my_snk.extensions =
+ tcpci_snk_emul_init(&fixture->snk_ext, &fixture->my_snk, NULL);
+
+ tcpci_partner_init(&fixture->my_src, PD_REV20);
+ fixture->my_src.extensions =
+ tcpci_src_emul_init(&fixture->src_ext, &fixture->my_src, NULL);
+
+ /*
+ * TODO(b/221288815): TCPCI config flags should be compile-time
+ * constants
+ * TODO(b/209907615): Verify TCPCI rev1 on non-port partner.
+ */
+ /* Turn TCPCI rev 2 ON */
+ tcpc_config[SNK_PORT].flags |= TCPC_FLAGS_TCPCI_REV2_0;
+ tcpc_config[SRC_PORT].flags |= TCPC_FLAGS_TCPCI_REV2_0;
+}
+
+static void *integration_usb_src_snk_setup(void)
+{
+ static struct integration_usb_attach_src_then_snk_fixture fixture_state;
+
+ integration_usb_setup(&fixture_state.my_emulator_state);
+
+ return &fixture_state;
+}
+
+static void *integration_usb_snk_src_setup(void)
+{
+ static struct integration_usb_attach_snk_then_src_fixture fixture_state;
+
+ integration_usb_setup(&fixture_state.my_emulator_state);
+
+ return &fixture_state;
+}
+
+static void attach_src_snk_common_before(struct emul_state *my_emul_state)
+{
+ const struct emul *tcpci_emul_src = my_emul_state->tcpci_generic_emul;
+ const struct emul *tcpci_emul_snk = my_emul_state->tcpci_ps8xxx_emul;
+ const struct emul *charger_emul = my_emul_state->charger_isl923x_emul;
+
+ /* Reset vbus to 0mV */
+ /* TODO(b/217737667): Remove driver specific code. */
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+
+ zassume_ok(tcpc_config[SNK_PORT].drv->init(SNK_PORT), NULL);
+ /*
+ * Arbitrary FW ver. The emulator should really be setting this
+ * during its init.
+ */
+ tcpci_emul_set_reg(tcpci_emul_snk, PS8XXX_REG_FW_REV, 0x31);
+
+ zassume_ok(tcpc_config[SRC_PORT].drv->init(SRC_PORT), NULL);
+
+ pd_set_suspend(SNK_PORT, false);
+ pd_set_suspend(SRC_PORT, false);
+
+ /* Reset to disconnected state. */
+ zassume_ok(tcpci_emul_disconnect_partner(tcpci_emul_src), NULL);
+ zassume_ok(tcpci_emul_disconnect_partner(tcpci_emul_snk), NULL);
+
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+}
+
+static void attach_src_snk_common_after(struct emul_state *my_emul_state)
+{
+ const struct emul *tcpci_generic_emul =
+ my_emul_state->tcpci_generic_emul;
+ const struct emul *tcpci_ps8xxx_emul = my_emul_state->tcpci_ps8xxx_emul;
+ const struct emul *charger_emul = my_emul_state->charger_isl923x_emul;
+
+ tcpci_emul_disconnect_partner(tcpci_generic_emul);
+ tcpci_emul_disconnect_partner(tcpci_ps8xxx_emul);
+
+ /* Give time to actually disconnect */
+ k_sleep(K_SECONDS(1));
+
+ /* Reset vbus to 0mV */
+ /* TODO(b/217737667): Remove driver specific code. */
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+}
+
+static void attach_emulated_snk(struct emul_state *my_emul_state)
+{
+ const struct emul *tcpci_emul_snk = my_emul_state->tcpci_ps8xxx_emul;
+ struct tcpci_partner_data *my_snk = &my_emul_state->my_snk;
+ uint16_t power_reg_val;
+
+ /* Turn on VBUS detection */
+ /*
+ * TODO(b/223901282): integration tests should not be setting vbus
+ * detection via registers, also this should be turned on by default.
+ */
+ tcpci_emul_get_reg(tcpci_emul_snk, TCPC_REG_POWER_STATUS,
+ &power_reg_val);
+ tcpci_emul_set_reg(tcpci_emul_snk, TCPC_REG_POWER_STATUS,
+ power_reg_val | TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ /* Necessary for TCPCIv2 vSave0V detection on VBUS to reach attached
+ * state
+ */
+ tcpci_emul_set_reg(tcpci_emul_snk, TCPC_REG_EXT_STATUS,
+ TCPC_REG_EXT_STATUS_SAFE0V);
+
+ zassume_ok(tcpci_partner_connect_to_tcpci(my_snk, tcpci_emul_snk),
+ NULL);
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+}
+
+static void attach_emulated_src(struct emul_state *my_emul_state)
+{
+ const struct emul *tcpci_emul_src = my_emul_state->tcpci_generic_emul;
+ const struct emul *charger_emul = my_emul_state->charger_isl923x_emul;
+ struct tcpci_partner_data *my_src = &my_emul_state->my_src;
+ uint16_t power_reg_val;
+
+ /* Turn on VBUS detection */
+ /*
+ * TODO(b/223901282): integration tests should not be setting vbus
+ * detection via registers, also this should be turned on by default.
+ */
+ tcpci_emul_get_reg(tcpci_emul_src, TCPC_REG_POWER_STATUS,
+ &power_reg_val);
+ tcpci_emul_set_reg(tcpci_emul_src, TCPC_REG_POWER_STATUS,
+ power_reg_val | TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ /* Necessary for TCPCIv2 vSave0V detection on VBUS to reach attached
+ * state
+ */
+ tcpci_emul_set_reg(tcpci_emul_src, TCPC_REG_EXT_STATUS,
+ TCPC_REG_EXT_STATUS_SAFE0V);
+
+ zassume_ok(tcpci_partner_connect_to_tcpci(my_src, tcpci_emul_src),
+ NULL);
+ isl923x_emul_set_adc_vbus(charger_emul, DEFAULT_VBUS_MV);
+}
+
+static void integration_usb_attach_snk_then_src_before(void *state)
+{
+ struct integration_usb_attach_src_then_snk_fixture *fixture = state;
+ struct emul_state *my_state = &fixture->my_emulator_state;
+
+ attach_src_snk_common_before(my_state);
+
+ /* 1) Attach SINK */
+ attach_emulated_snk(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+
+ /* 2) Attach SOURCE */
+ attach_emulated_src(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+}
+
+static void integration_usb_attach_src_then_snk_before(void *state)
+{
+ struct integration_usb_attach_src_then_snk_fixture *fixture = state;
+ struct emul_state *my_state = &fixture->my_emulator_state;
+
+ attach_src_snk_common_before(my_state);
+
+ /* 1) Attach SOURCE */
+ attach_emulated_src(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+
+ /* 2) Attach SINK */
+ attach_emulated_snk(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+}
+
+static void integration_usb_attach_src_then_snk_after(void *state)
+{
+ struct integration_usb_attach_src_then_snk_fixture *fixture = state;
+
+ attach_src_snk_common_after(&fixture->my_emulator_state);
+}
+
+static void integration_usb_attach_snk_then_src_after(void *state)
+{
+ struct integration_usb_attach_snk_then_src_fixture *fixture = state;
+
+ attach_src_snk_common_after(&fixture->my_emulator_state);
+}
+
+ZTEST_F(integration_usb_attach_src_then_snk, verify_snk_port_pd_info)
+{
+ struct ec_response_usb_pd_power_info response;
+
+ response = host_cmd_power_info(SNK_PORT);
+
+ /* Assert */
+ zassert_equal(response.role, USB_PD_PORT_POWER_SINK,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_SINK, response.role);
+ zassert_equal(response.type, USB_CHG_TYPE_PD,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_PD, response.type);
+
+ zassert_equal(response.meas.voltage_max, DEFAULT_VBUS_MV,
+ "Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_max);
+
+ zassert_within(response.meas.voltage_now, DEFAULT_VBUS_MV,
+ DEFAULT_VBUS_MV / 10,
+ "Actually charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_now);
+
+ zassert_equal(response.meas.current_max, DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging at VBUS max %dmA, but PD reports %dmA",
+ DEFAULT_VBUS_SNK_PORT_MA, response.meas.current_max);
+
+ zassert_true(response.meas.current_lim >= DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging at VBUS max %dmA, but PD current limit %dmA",
+ DEFAULT_VBUS_SNK_PORT_MA, response.meas.current_lim);
+
+ zassert_equal(response.max_power,
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging up to %duW, PD max power %duW",
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ response.max_power);
+}
+
+ZTEST_F(integration_usb_attach_src_then_snk, verify_src_port_pd_info)
+{
+ struct ec_response_usb_pd_power_info response;
+
+ response = host_cmd_power_info(SRC_PORT);
+
+ /* Assert */
+ zassert_equal(response.role, USB_PD_PORT_POWER_SOURCE,
+ "Power role %d, but PD reports role %d", PD_ROLE_SOURCE,
+ response.role);
+
+ zassert_equal(response.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, response.type);
+
+ /* TODO(b/209907615): Confirm measure value requirements */
+ zassert_within(response.meas.voltage_now, DEFAULT_VBUS_MV,
+ DEFAULT_VBUS_MV / 10,
+ "Expected Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_now);
+
+ zassert_equal(response.meas.current_max, DEFAULT_VBUS_SRC_PORT_MA,
+ "Charging at VBUS max %dmA, but PD reports %dmA",
+ DEFAULT_VBUS_SRC_PORT_MA, response.meas.current_max);
+
+ /* Note: We are the source so we skip checking: */
+ /* meas.voltage_max */
+ /* max_power */
+ /* current limit */
+}
+
+ZTEST_F(integration_usb_attach_snk_then_src, verify_snk_port_pd_info)
+{
+ struct ec_response_usb_pd_power_info response;
+
+ response = host_cmd_power_info(SNK_PORT);
+
+ /* Assert */
+ zassert_equal(response.role, USB_PD_PORT_POWER_SINK,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_SINK, response.role);
+ zassert_equal(response.type, USB_CHG_TYPE_PD,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_PD, response.type);
+
+ /* Verify Default 5V and 3A */
+ zassert_equal(response.meas.voltage_max, DEFAULT_VBUS_MV,
+ "Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_max);
+
+ zassert_within(response.meas.voltage_now, DEFAULT_VBUS_MV,
+ DEFAULT_VBUS_MV / 10,
+ "Actually charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_now);
+
+ zassert_equal(response.meas.current_max, DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging at VBUS max %dmA, but PD reports %dmA",
+ DEFAULT_VBUS_SNK_PORT_MA, response.meas.current_max);
+
+ zassert_true(response.meas.current_lim >= DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging at VBUS max %dmA, but PD current limit %dmA",
+ DEFAULT_VBUS_SNK_PORT_MA, response.meas.current_lim);
+
+ zassert_equal(response.max_power,
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging up to %duW, PD max power %duW",
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ response.max_power);
+}
+
+ZTEST_F(integration_usb_attach_snk_then_src, verify_src_port_pd_info)
+{
+ struct ec_response_usb_pd_power_info response;
+
+ response = host_cmd_power_info(SRC_PORT);
+
+ /* Assert */
+ zassert_equal(response.role, USB_PD_PORT_POWER_SOURCE,
+ "Power role %d, but PD reports role %d", PD_ROLE_SOURCE,
+ response.role);
+
+ zassert_equal(response.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, response.type);
+
+ /* Verify Default 5V and 3A */
+ /* TODO(b/209907615): Confirm measure value requirements */
+ zassert_within(response.meas.voltage_now, DEFAULT_VBUS_MV,
+ DEFAULT_VBUS_MV / 10,
+ "Expected Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, response.meas.voltage_now);
+
+ zassert_equal(response.meas.current_max, DEFAULT_VBUS_SRC_PORT_MA,
+ "Charging at VBUS max %dmA, but PD reports %dmA",
+ DEFAULT_VBUS_SRC_PORT_MA, response.meas.current_max);
+
+ /* Note: We are the source so we skip checking: */
+ /* meas.voltage_max */
+ /* max_power */
+ /* current limit */
+}
+
+ZTEST_F(integration_usb_attach_src_then_snk, verify_snk_port_typec_status)
+{
+ struct ec_response_typec_status response =
+ host_cmd_typec_status(SNK_PORT);
+
+ zassert_true(response.pd_enabled, "Source attached but PD disabled");
+
+ zassert_true(response.dev_connected,
+ "Source attached but device disconnected");
+
+ zassert_true(response.sop_connected,
+ "Source attached but not SOP capable");
+
+ zassert_equal(response.source_cap_count,
+ DEFAULT_SOURCE_SENT_TO_SINK_CAP_COUNT,
+ "Source received %d source PDOs",
+ response.source_cap_count);
+
+ /* The source emulator is being attached to a sink port (our policy
+ * engine) so it does not send any sink caps, so sink port received no
+ * sink caps.
+ */
+ zassert_equal(response.sink_cap_count, 0, "Port received %d sink PDOs",
+ response.sink_cap_count);
+
+ zassert_equal(response.power_role, PD_ROLE_SINK,
+ "Source attached, but TCPM power role is %d",
+ response.power_role);
+}
+
+ZTEST_F(integration_usb_attach_src_then_snk, verify_src_port_typec_status)
+{
+ struct ec_response_typec_status response =
+ host_cmd_typec_status(SRC_PORT);
+
+ zassert_true(response.pd_enabled, "Sink attached but PD disabled");
+
+ zassert_true(response.dev_connected,
+ "Sink attached but device disconnected");
+
+ zassert_true(response.sop_connected,
+ "Sink attached but not SOP capable");
+
+ /* The sink emulator is being attached to a source port (our policy
+ * engine) so it does not send any sink caps, so source port received no
+ * sink caps.
+ */
+ zassert_equal(response.source_cap_count, 0,
+ "Port received %d source PDOs",
+ response.source_cap_count);
+
+ zassert_equal(response.sink_cap_count,
+ DEFAULT_SINK_SENT_TO_SOURCE_CAP_COUNT,
+ "Port received %d sink PDOs", response.sink_cap_count);
+
+ zassert_equal(response.power_role, PD_ROLE_SOURCE,
+ "Sink attached, but TCPM power role is %d",
+ response.power_role);
+}
+
+ZTEST_F(integration_usb_attach_snk_then_src, verify_snk_port_typec_status)
+{
+ struct ec_response_typec_status response =
+ host_cmd_typec_status(SNK_PORT);
+
+ zassert_true(response.pd_enabled, "Source attached but PD disabled");
+
+ zassert_true(response.dev_connected,
+ "Source attached but device disconnected");
+
+ zassert_true(response.sop_connected,
+ "Source attached but not SOP capable");
+
+ zassert_equal(response.source_cap_count,
+ DEFAULT_SOURCE_SENT_TO_SINK_CAP_COUNT,
+ "Source received %d source PDOs",
+ response.source_cap_count);
+
+ /* The source emulator is being attached to a sink port (our policy
+ * engine) so it does not send any sink caps, so sink port received no
+ * sink caps.
+ */
+ zassert_equal(response.sink_cap_count, 0, "Port received %d sink PDOs",
+ response.sink_cap_count);
+
+ zassert_equal(response.power_role, PD_ROLE_SINK,
+ "Source attached, but TCPM power role is %d",
+ response.power_role);
+}
+
+ZTEST_F(integration_usb_attach_snk_then_src, verify_src_port_typec_status)
+{
+ struct ec_response_typec_status response =
+ host_cmd_typec_status(SRC_PORT);
+
+ zassert_true(response.pd_enabled, "Sink attached but PD disabled");
+
+ zassert_true(response.dev_connected,
+ "Sink attached but device disconnected");
+
+ zassert_true(response.sop_connected,
+ "Sink attached but not SOP capable");
+
+ /* The sink emulator is being attached to a source port (our policy
+ * engine) so it does not send any sink caps, so source port received no
+ * sink caps.
+ */
+ zassert_equal(response.source_cap_count, 0,
+ "Port received %d source PDOs",
+ response.source_cap_count);
+
+ zassert_equal(response.sink_cap_count,
+ DEFAULT_SINK_SENT_TO_SOURCE_CAP_COUNT,
+ "Port received %d sink PDOs", response.sink_cap_count);
+
+ zassert_equal(response.power_role, PD_ROLE_SOURCE,
+ "Sink attached, but TCPM power role is %d",
+ response.power_role);
+}
+
+ZTEST_SUITE(integration_usb_attach_src_then_snk, drivers_predicate_post_main,
+ integration_usb_src_snk_setup,
+ integration_usb_attach_src_then_snk_before,
+ integration_usb_attach_src_then_snk_after, NULL);
+
+ZTEST_SUITE(integration_usb_attach_snk_then_src, drivers_predicate_post_main,
+ integration_usb_snk_src_setup,
+ integration_usb_attach_snk_then_src_before,
+ integration_usb_attach_snk_then_src_after, NULL);
+
+struct usb_detach_test_fixture {
+ struct emul_state fixture;
+};
+
+static void integration_usb_test_detach(const struct emul *e)
+{
+ zassume_ok(tcpci_emul_disconnect_partner(e), NULL);
+}
+
+static void integration_usb_test_sink_detach(struct emul_state *fixture)
+{
+ integration_usb_test_detach(fixture->tcpci_ps8xxx_emul);
+}
+
+static void integration_usb_test_source_detach(struct emul_state *fixture)
+{
+ integration_usb_test_detach(fixture->tcpci_generic_emul);
+}
+
+void *usb_detach_test_setup(void)
+{
+ static struct usb_detach_test_fixture usb_detach_fixture = { 0 };
+
+ integration_usb_setup(&usb_detach_fixture.fixture);
+
+ return &usb_detach_fixture;
+}
+
+static void usb_detach_test_before(void *state)
+{
+ struct usb_detach_test_fixture *fixture = state;
+ struct emul_state *my_state = &fixture->fixture;
+
+ attach_src_snk_common_before(my_state);
+
+ /* 1) Attach SINK */
+ attach_emulated_snk(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+
+ /* 2) Attach SOURCE */
+ attach_emulated_src(my_state);
+
+ /* Wait for PD negotiation */
+ k_sleep(K_SECONDS(10));
+}
+
+static void usb_detach_test_after(void *state)
+{
+ struct usb_detach_test_fixture *fixture = state;
+
+ attach_src_snk_common_after(&fixture->fixture);
+}
+
+ZTEST_F(usb_detach_test, verify_detach_src_snk)
+{
+ struct emul_state *emul_state = &fixture->fixture;
+ struct ec_response_usb_pd_power_info src_power_info = { 0 };
+ struct ec_response_usb_pd_power_info snk_power_info = { 0 };
+
+ integration_usb_test_source_detach(emul_state);
+ integration_usb_test_sink_detach(emul_state);
+
+ k_sleep(K_SECONDS(10));
+ isl923x_emul_set_adc_vbus(emul_state->charger_isl923x_emul, 0);
+
+ snk_power_info = host_cmd_power_info(SNK_PORT);
+ src_power_info = host_cmd_power_info(SRC_PORT);
+
+ /* Validate Sink power info */
+ zassert_equal(snk_power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_DISCONNECTED, snk_power_info.role);
+ zassert_equal(snk_power_info.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, snk_power_info.type);
+
+ zassert_equal(snk_power_info.meas.voltage_max, 0,
+ "Charging at VBUS %dmV, but PD reports %dmV", 0,
+ snk_power_info.meas.voltage_max);
+
+ zassert_within(snk_power_info.meas.voltage_now, 0, 10,
+ "Actually charging at VBUS %dmV, but PD reports %dmV", 0,
+ snk_power_info.meas.voltage_now);
+
+ zassert_equal(snk_power_info.meas.current_max, 0,
+ "Charging at VBUS max %dmA, but PD reports %dmA", 0,
+ snk_power_info.meas.current_max);
+
+ zassert_true(snk_power_info.meas.current_lim >= 0,
+ "Charging at VBUS max %dmA, but PD current limit %dmA", 0,
+ snk_power_info.meas.current_lim);
+
+ zassert_equal(snk_power_info.max_power, 0,
+ "Charging up to %duW, PD max power %duW", 0,
+ snk_power_info.max_power);
+
+ /* Validate Source power info */
+ zassert_equal(src_power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_DISCONNECTED, src_power_info.role);
+
+ zassert_equal(src_power_info.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, src_power_info.type);
+
+ /* TODO(b/209907615): Confirm measure value requirements */
+ zassert_within(src_power_info.meas.voltage_now, 0, 10,
+ "Expected Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, src_power_info.meas.voltage_now);
+
+ zassert_equal(src_power_info.meas.current_max, 0,
+ "Charging at VBUS max %dmA, but PD reports %dmA", 0,
+ src_power_info.meas.current_max);
+}
+
+ZTEST_F(usb_detach_test, verify_detach_snk_src)
+{
+ struct emul_state *emul_state = &fixture->fixture;
+ struct ec_response_usb_pd_power_info src_power_info = { 0 };
+ struct ec_response_usb_pd_power_info snk_power_info = { 0 };
+
+ integration_usb_test_sink_detach(emul_state);
+ integration_usb_test_source_detach(emul_state);
+
+ k_sleep(K_SECONDS(10));
+ isl923x_emul_set_adc_vbus(emul_state->charger_isl923x_emul, 0);
+
+ snk_power_info = host_cmd_power_info(SNK_PORT);
+ src_power_info = host_cmd_power_info(SRC_PORT);
+
+ /* Validate Sink power info */
+ zassert_equal(snk_power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_DISCONNECTED, snk_power_info.role);
+ zassert_equal(snk_power_info.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, snk_power_info.type);
+
+ zassert_equal(snk_power_info.meas.voltage_max, 0,
+ "Charging at VBUS %dmV, but PD reports %dmV", 0,
+ snk_power_info.meas.voltage_max);
+
+ zassert_within(snk_power_info.meas.voltage_now, 0, 10,
+ "Actually charging at VBUS %dmV, but PD reports %dmV", 0,
+ snk_power_info.meas.voltage_now);
+
+ zassert_equal(snk_power_info.meas.current_max, 0,
+ "Charging at VBUS max %dmA, but PD reports %dmA", 0,
+ snk_power_info.meas.current_max);
+
+ zassert_true(snk_power_info.meas.current_lim >= 0,
+ "Charging at VBUS max %dmA, but PD current limit %dmA", 0,
+ snk_power_info.meas.current_lim);
+
+ zassert_equal(snk_power_info.max_power, 0,
+ "Charging up to %duW, PD max power %duW", 0,
+ snk_power_info.max_power);
+
+ /* Validate Source power info */
+ zassert_equal(src_power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_DISCONNECTED, src_power_info.role);
+
+ zassert_equal(src_power_info.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, src_power_info.type);
+
+ /* TODO(b/209907615): Confirm measure value requirements */
+ zassert_within(src_power_info.meas.voltage_now, 0, 10,
+ "Expected Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, src_power_info.meas.voltage_now);
+
+ zassert_equal(src_power_info.meas.current_max, 0,
+ "Charging at VBUS max %dmA, but PD reports %dmA", 0,
+ src_power_info.meas.current_max);
+}
+
+ZTEST_F(usb_detach_test, verify_detach_sink)
+{
+ struct emul_state *emul_state = &fixture->fixture;
+ struct ec_response_usb_pd_power_info pd_power_info = { 0 };
+
+ integration_usb_test_sink_detach(emul_state);
+ k_sleep(K_SECONDS(10));
+ isl923x_emul_set_adc_vbus(emul_state->charger_isl923x_emul, 0);
+
+ pd_power_info = host_cmd_power_info(SNK_PORT);
+
+ /* Assert */
+ zassert_equal(pd_power_info.role, USB_PD_PORT_POWER_SINK,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_SINK, pd_power_info.role);
+ zassert_equal(pd_power_info.type, USB_CHG_TYPE_PD,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_PD, pd_power_info.type);
+
+ zassert_equal(pd_power_info.meas.voltage_max, DEFAULT_VBUS_MV,
+ "Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, pd_power_info.meas.voltage_max);
+
+ zassert_within(pd_power_info.meas.voltage_now, 0, 10,
+ "Actually charging at VBUS %dmV, but PD reports %dmV", 0,
+ pd_power_info.meas.voltage_now);
+
+ zassert_equal(pd_power_info.meas.current_max, DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging at VBUS max %dmA, but PD reports %dmA",
+ DEFAULT_VBUS_SNK_PORT_MA, pd_power_info.meas.current_max);
+
+ zassert_true(pd_power_info.meas.current_lim >= 500,
+ "Charging at VBUS max %dmA, but PD current limit %dmA",
+ 500, pd_power_info.meas.current_lim);
+
+ zassert_equal(pd_power_info.max_power,
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ "Charging up to %duW, PD max power %duW",
+ DEFAULT_VBUS_MV * DEFAULT_VBUS_SNK_PORT_MA,
+ pd_power_info.max_power);
+}
+
+ZTEST_F(usb_detach_test, verify_detach_source)
+{
+ struct emul_state *emul_state = &fixture->fixture;
+ struct ec_response_usb_pd_power_info pd_power_info = { SNK_PORT };
+
+ integration_usb_test_source_detach(emul_state);
+ k_sleep(K_SECONDS(10));
+ isl923x_emul_set_adc_vbus(emul_state->charger_isl923x_emul, 0);
+
+ pd_power_info = host_cmd_power_info(SNK_PORT);
+
+ /* Assert */
+ zassert_equal(pd_power_info.role, USB_PD_PORT_POWER_DISCONNECTED,
+ "Power role %d, but PD reports role %d",
+ USB_PD_PORT_POWER_DISCONNECTED, pd_power_info.role);
+
+ zassert_equal(pd_power_info.type, USB_CHG_TYPE_NONE,
+ "Charger type %d, but PD reports type %d",
+ USB_CHG_TYPE_NONE, pd_power_info.type);
+
+ /* TODO(b/209907615): Confirm measure value requirements */
+ zassert_within(pd_power_info.meas.voltage_now, 0, 10,
+ "Expected Charging at VBUS %dmV, but PD reports %dmV",
+ DEFAULT_VBUS_MV, pd_power_info.meas.voltage_now);
+
+ zassert_equal(pd_power_info.meas.current_max, 0,
+ "Charging at VBUS max %dmA, but PD reports %dmA", 0,
+ pd_power_info.meas.current_max);
+}
+
+ZTEST_SUITE(usb_detach_test, drivers_predicate_post_main,
+ integration_usb_src_snk_setup, usb_detach_test_before,
+ usb_detach_test_after, NULL);
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_pd_bist_shared.c b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_bist_shared.c
new file mode 100644
index 0000000000..9c76f862f8
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_bist_shared.c
@@ -0,0 +1,193 @@
+/* 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/ztest.h>
+
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_common.h"
+#include "usb_pd.h"
+#include "util.h"
+
+struct usb_pd_bist_shared_fixture {
+ struct tcpci_partner_data sink_5v_500ma;
+ struct tcpci_snk_emul_data snk_ext_500ma;
+ struct tcpci_partner_data src;
+ struct tcpci_src_emul_data src_ext;
+ const struct emul *tcpci_emul; /* USBC_PORT_C0 in dts */
+ const struct emul *tcpci_ps8xxx_emul; /* USBC_PORT_C1 in dts */
+ const struct emul *charger_emul;
+};
+
+static void *usb_pd_bist_shared_setup(void)
+{
+ static struct usb_pd_bist_shared_fixture test_fixture;
+
+ /* Get references for the emulators */
+ test_fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ test_fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+ test_fixture.tcpci_ps8xxx_emul = EMUL_GET_USBC_BINDING(1, tcpc);
+
+ return &test_fixture;
+}
+
+static void usb_pd_bist_shared_before(void *data)
+{
+ struct usb_pd_bist_shared_fixture *test_fixture = data;
+
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+
+ /* Initialized the sink to request 5V and 500mA */
+ tcpci_partner_init(&test_fixture->sink_5v_500ma, PD_REV30);
+ test_fixture->sink_5v_500ma.extensions =
+ tcpci_snk_emul_init(&test_fixture->snk_ext_500ma,
+ &test_fixture->sink_5v_500ma, NULL);
+ test_fixture->snk_ext_500ma.pdo[0] = PDO_FIXED(5000, 500, 0);
+
+ /* Initialized the source */
+ tcpci_partner_init(&test_fixture->src, PD_REV30);
+ test_fixture->src.extensions = tcpci_src_emul_init(
+ &test_fixture->src_ext, &test_fixture->src, NULL);
+
+ /* Initially connect the 5V 500mA partner to C0 */
+ connect_sink_to_port(&test_fixture->sink_5v_500ma,
+ test_fixture->tcpci_emul,
+ test_fixture->charger_emul);
+}
+
+static void usb_pd_bist_shared_after(void *data)
+{
+ struct usb_pd_bist_shared_fixture *test_fixture = data;
+
+ /* Disocnnect C0 as sink, C1 as source */
+ disconnect_sink_from_port(test_fixture->tcpci_emul);
+ disconnect_source_from_port(test_fixture->tcpci_ps8xxx_emul,
+ test_fixture->charger_emul);
+}
+
+ZTEST_SUITE(usb_pd_bist_shared, drivers_predicate_post_main,
+ usb_pd_bist_shared_setup, usb_pd_bist_shared_before,
+ usb_pd_bist_shared_after, NULL);
+
+ZTEST_F(usb_pd_bist_shared, verify_bist_shared_mode)
+{
+ uint32_t bist_data;
+ uint32_t f5v_cap;
+
+ /*
+ * Verify we were offered the 1.5A source cap because of our low current
+ * needs initially
+ */
+ f5v_cap = fixture->snk_ext_500ma.last_5v_source_cap;
+ /* Capability should be 5V fixed, 1.5 A */
+ zassert_equal((f5v_cap & PDO_TYPE_MASK), PDO_TYPE_FIXED,
+ "PDO type wrong");
+ zassert_equal(PDO_FIXED_VOLTAGE(f5v_cap), 5000, "PDO voltage wrong");
+ zassert_equal(PDO_FIXED_CURRENT(f5v_cap), 1500,
+ "PDO initial current wrong");
+
+ /* Start up BIST shared test mode */
+ bist_data = BDO(BDO_MODE_SHARED_ENTER, 0);
+ zassume_ok(tcpci_partner_send_data_msg(&fixture->sink_5v_500ma,
+ PD_DATA_BIST, &bist_data, 1, 0),
+ "Failed to send BIST enter message");
+
+ /* The DUT has tBISTSharedTestMode (1 second) to offer us 3A now */
+ k_sleep(K_SECONDS(1));
+
+ f5v_cap = fixture->snk_ext_500ma.last_5v_source_cap;
+ /* Capability should be 5V fixed, 3.0 A */
+ zassert_equal((f5v_cap & PDO_TYPE_MASK), PDO_TYPE_FIXED,
+ "PDO type wrong");
+ zassert_equal(PDO_FIXED_VOLTAGE(f5v_cap), 5000, "PDO voltage wrong");
+ zassert_equal(PDO_FIXED_CURRENT(f5v_cap), 3000,
+ "PDO current didn't increase in BIST mode");
+
+ /* Leave BIST shared test mode */
+ bist_data = BDO(BDO_MODE_SHARED_EXIT, 0);
+ zassume_ok(tcpci_partner_send_data_msg(&fixture->sink_5v_500ma,
+ PD_DATA_BIST, &bist_data, 1, 0),
+ "Failed to send BIST exit message");
+
+ /*
+ * The DUT may now execute ErrorRecovery or simply send a new
+ * Source_Cap. Either way, we should go back to 1.5 A
+ */
+ k_sleep(K_SECONDS(5));
+
+ f5v_cap = fixture->snk_ext_500ma.last_5v_source_cap;
+ /* Capability should be 5V fixed, 1.5 A */
+ zassert_equal((f5v_cap & PDO_TYPE_MASK), PDO_TYPE_FIXED,
+ "PDO type wrong");
+ zassert_equal(PDO_FIXED_VOLTAGE(f5v_cap), 5000, "PDO voltage wrong");
+ zassert_equal(PDO_FIXED_CURRENT(f5v_cap), 1500,
+ "PDO current didn't decrease after BIST exit");
+}
+
+ZTEST_F(usb_pd_bist_shared, verify_bist_shared_no_snk_entry)
+{
+ uint32_t bist_data;
+ uint32_t f5v_cap;
+
+ /*
+ * Ensure we only enter BIST shared mode when acting as a source. We
+ * must not enter shared mode from PE_SNK_Ready.
+ */
+
+ /* Attach a new source */
+ connect_source_to_port(&fixture->src, &fixture->src_ext, 1,
+ fixture->tcpci_ps8xxx_emul,
+ fixture->charger_emul);
+
+ /* Have the source send the BIST Enter Mode */
+ bist_data = BDO(BDO_MODE_SHARED_ENTER, 0);
+ zassume_ok(tcpci_partner_send_data_msg(&fixture->src, PD_DATA_BIST,
+ &bist_data, 1, 0),
+ "Failed to send BIST enter message");
+
+ /* Wait tBISTSharedTestMode (1 second) */
+ k_sleep(K_SECONDS(1));
+
+ /* Verify our low power sink on C0 still only has 1.5 A */
+ f5v_cap = fixture->snk_ext_500ma.last_5v_source_cap;
+ /* Capability should be 5V fixed, 1.5 A */
+ zassert_equal((f5v_cap & PDO_TYPE_MASK), PDO_TYPE_FIXED,
+ "PDO type wrong");
+ zassert_equal(PDO_FIXED_VOLTAGE(f5v_cap), 5000, "PDO voltage wrong");
+ zassert_equal(PDO_FIXED_CURRENT(f5v_cap), 1500,
+ "PDO current incorrect after bad BIST entry");
+}
+
+ZTEST_F(usb_pd_bist_shared, verify_bist_shared_exit_no_action)
+{
+ uint32_t bist_data;
+ uint32_t f5v_cap;
+
+ /*
+ * Verify that if we receive a BIST shared mode exit with no entry, we
+ * take no action on the port.
+ */
+ tcpci_snk_emul_clear_last_5v_cap(&fixture->snk_ext_500ma);
+
+ bist_data = BDO(BDO_MODE_SHARED_EXIT, 0);
+ zassume_ok(tcpci_partner_send_data_msg(&fixture->sink_5v_500ma,
+ PD_DATA_BIST, &bist_data, 1, 0),
+ "Failed to send BIST exit message");
+
+ /* Wait for the time it would take to settle out exit */
+ k_sleep(K_SECONDS(5));
+
+ /* Verify we didn't receive any new source caps due to the mode exit */
+ f5v_cap = fixture->snk_ext_500ma.last_5v_source_cap;
+ zassert_equal(f5v_cap, 0, "Received unexpected source cap");
+}
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_pd_ctrl_msg.c b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_ctrl_msg.c
new file mode 100644
index 0000000000..894deaed13
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_ctrl_msg.c
@@ -0,0 +1,395 @@
+/* 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 <stdint.h>
+#include <zephyr/ztest.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include "emul/emul_isl923x.h"
+#include "emul/tcpc/emul_tcpci_partner_drp.h"
+#include "tcpm/tcpci.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "test/usb_pe.h"
+#include "usb_pd.h"
+
+#define TEST_USB_PORT 0
+BUILD_ASSERT(TEST_USB_PORT == USBC_PORT_C0);
+
+#define TEST_ADDED_PDO PDO_FIXED(10000, 3000, PDO_FIXED_UNCONSTRAINED)
+
+struct usb_pd_ctrl_msg_test_fixture {
+ struct tcpci_partner_data partner_emul;
+ struct tcpci_snk_emul_data snk_ext;
+ struct tcpci_src_emul_data src_ext;
+ struct tcpci_drp_emul_data drp_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+ enum pd_power_role drp_partner_pd_role;
+};
+
+struct usb_pd_ctrl_msg_test_sink_fixture {
+ struct usb_pd_ctrl_msg_test_fixture fixture;
+};
+
+struct usb_pd_ctrl_msg_test_source_fixture {
+ struct usb_pd_ctrl_msg_test_fixture fixture;
+};
+
+static void
+tcpci_drp_emul_connect_partner(struct tcpci_partner_data *partner_emul,
+ const struct emul *tcpci_emul,
+ const struct emul *charger_emul)
+{
+ /*
+ * TODO(b/221439302) Updating the TCPCI emulator registers, updating the
+ * vbus, as well as alerting should all be a part of the connect
+ * function.
+ */
+ isl923x_emul_set_adc_vbus(charger_emul, 0);
+ tcpci_emul_set_reg(tcpci_emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ tcpci_emul_set_reg(tcpci_emul, TCPC_REG_EXT_STATUS,
+ TCPC_REG_EXT_STATUS_SAFE0V);
+
+ tcpci_tcpc_alert(TEST_USB_PORT);
+
+ zassume_ok(tcpci_partner_connect_to_tcpci(partner_emul, tcpci_emul),
+ NULL);
+}
+
+static void disconnect_partner(struct usb_pd_ctrl_msg_test_fixture *fixture)
+{
+ zassume_ok(tcpci_emul_disconnect_partner(fixture->tcpci_emul), NULL);
+ k_sleep(K_SECONDS(1));
+}
+
+static void *usb_pd_ctrl_msg_setup_emul(void)
+{
+ static struct usb_pd_ctrl_msg_test_fixture fixture;
+
+ /* Get references for the emulators */
+ fixture.tcpci_emul = EMUL_GET_USBC_BINDING(TEST_USB_PORT, tcpc);
+ fixture.charger_emul = EMUL_GET_USBC_BINDING(TEST_USB_PORT, chg);
+
+ return &fixture;
+}
+
+static void *usb_pd_ctrl_msg_sink_setup(void)
+{
+ struct usb_pd_ctrl_msg_test_fixture *fixture =
+ usb_pd_ctrl_msg_setup_emul();
+
+ fixture->drp_partner_pd_role = PD_ROLE_SINK;
+
+ return fixture;
+}
+
+static void *usb_pd_ctrl_msg_source_setup(void)
+{
+ struct usb_pd_ctrl_msg_test_fixture *fixture =
+ usb_pd_ctrl_msg_setup_emul();
+
+ fixture->drp_partner_pd_role = PD_ROLE_SOURCE;
+
+ return fixture;
+}
+
+static void usb_pd_ctrl_msg_before(void *data)
+{
+ struct usb_pd_ctrl_msg_test_fixture *fixture = data;
+
+ set_test_runner_tid();
+
+ test_set_chipset_to_g3();
+ k_sleep(K_SECONDS(1));
+
+ /* Set chipset to ON, this will set TCPM to DRP */
+ test_set_chipset_to_s0();
+
+ /* TODO(b/214401892): Check why need to give time TCPM to spin */
+ k_sleep(K_SECONDS(1));
+
+ /* Initialized DRP */
+ tcpci_partner_init(&fixture->partner_emul, PD_REV20);
+ fixture->partner_emul.extensions = tcpci_drp_emul_init(
+ &fixture->drp_ext, &fixture->partner_emul,
+ fixture->drp_partner_pd_role,
+ tcpci_src_emul_init(&fixture->src_ext, &fixture->partner_emul,
+ NULL),
+ tcpci_snk_emul_init(&fixture->snk_ext, &fixture->partner_emul,
+ NULL));
+ /* Add additional Sink PDO to partner to verify
+ * PE_DR_SNK_Get_Sink_Cap/PE_SRC_Get_Sink_Cap (these are shared PE
+ * states) state was reached
+ */
+ fixture->snk_ext.pdo[1] = TEST_ADDED_PDO;
+
+ /* Turn TCPCI rev 2 ON */
+ tcpc_config[TEST_USB_PORT].flags |= TCPC_FLAGS_TCPCI_REV2_0;
+
+ tcpci_drp_emul_connect_partner(&fixture->partner_emul,
+ fixture->tcpci_emul,
+ fixture->charger_emul);
+
+ k_sleep(K_SECONDS(10));
+}
+
+static void usb_pd_ctrl_msg_after(void *data)
+{
+ struct usb_pd_ctrl_msg_test_fixture *fixture = data;
+
+ disconnect_partner(fixture);
+}
+
+/** ZTEST_SUITE to setup DRP partner_emul as SINK */
+ZTEST_SUITE(usb_pd_ctrl_msg_test_sink, drivers_predicate_post_main,
+ usb_pd_ctrl_msg_sink_setup, usb_pd_ctrl_msg_before,
+ usb_pd_ctrl_msg_after, NULL);
+
+/** ZTEST_SUITE to setup DRP partner_emul as SOURCE */
+ZTEST_SUITE(usb_pd_ctrl_msg_test_source, drivers_predicate_post_main,
+ usb_pd_ctrl_msg_source_setup, usb_pd_ctrl_msg_before,
+ usb_pd_ctrl_msg_after, NULL);
+
+ZTEST_F(usb_pd_ctrl_msg_test_sink, verify_vconn_swap)
+{
+ struct usb_pd_ctrl_msg_test_fixture *super_fixture = &fixture->fixture;
+ struct ec_response_typec_status snk_resp = { 0 };
+ int rv = 0;
+
+ snk_resp = host_cmd_typec_status(TEST_USB_PORT);
+
+ zassert_equal(PD_ROLE_VCONN_SRC, snk_resp.vconn_role,
+ "SNK Returned vconn_role=%u", snk_resp.vconn_role);
+
+ /* Send VCONN_SWAP request */
+ rv = tcpci_partner_send_control_msg(&super_fixture->partner_emul,
+ PD_CTRL_VCONN_SWAP, 0);
+ zassert_ok(rv, "Failed to send VCONN_SWAP request, rv=%d", rv);
+
+ k_sleep(K_SECONDS(1));
+
+ snk_resp = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_VCONN_OFF, snk_resp.vconn_role,
+ "SNK Returned vconn_role=%u", snk_resp.vconn_role);
+}
+
+ZTEST_F(usb_pd_ctrl_msg_test_sink, verify_pr_swap)
+{
+ struct usb_pd_ctrl_msg_test_fixture *super_fixture = &fixture->fixture;
+ struct ec_response_typec_status snk_resp = { 0 };
+ int rv = 0;
+
+ snk_resp = host_cmd_typec_status(TEST_USB_PORT);
+
+ zassert_equal(PD_ROLE_SINK, snk_resp.power_role,
+ "SNK Returned power_role=%u", snk_resp.power_role);
+
+ /* Ignore ACCEPT in common handler for PR Swap request,
+ * causes soft reset
+ */
+ tcpci_partner_common_handler_mask_msg(&super_fixture->partner_emul,
+ PD_CTRL_ACCEPT, true);
+
+ /* Send PR_SWAP request */
+ rv = tcpci_partner_send_control_msg(&super_fixture->partner_emul,
+ PD_CTRL_PR_SWAP, 0);
+ zassert_ok(rv, "Failed to send PR_SWAP request, rv=%d", rv);
+
+ /* Send PS_RDY request */
+ rv = tcpci_partner_send_control_msg(&super_fixture->partner_emul,
+ PD_CTRL_PS_RDY, 15);
+ zassert_ok(rv, "Failed to send PS_RDY request, rv=%d", rv);
+
+ k_sleep(K_MSEC(20));
+
+ snk_resp = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_SOURCE, snk_resp.power_role,
+ "SNK Returned power_role=%u", snk_resp.power_role);
+}
+
+/**
+ * @brief TestPurpose: Verify DR Swap when DRP partner is configured as sink.
+ *
+ * @details
+ * - TCPM is brought up as Sink/UFP
+ * - TCPM over time will evaluate and trigger DR Swap to Sink/DFP
+ *
+ * Expected Results
+ * - TypeC status query returns PD_ROLE_DFP
+ */
+ZTEST_F(usb_pd_ctrl_msg_test_sink, verify_dr_swap)
+{
+ struct ec_response_typec_status typec_status =
+ host_cmd_typec_status(TEST_USB_PORT);
+
+ zassert_equal(PD_ROLE_DFP, typec_status.data_role,
+ "Returned data_role=%u", typec_status.data_role);
+}
+
+/**
+ * @brief TestPurpose: Verify DR Swap is rejected when DRP partner is
+ * configured as source.
+ *
+ * @details
+ * - TCPM is configured initially as Sink/UFP.
+ * - TCPM initiates DR swap according to policy (Sink/DFP)
+ * - Partner requests DR Swap.
+ * - Verify Request is rejected due the TCPM not being UFP.
+ *
+ * Expected Results
+ * - Data role does not change on TEST_USB_PORT after DR Swap request.
+ */
+ZTEST_F(usb_pd_ctrl_msg_test_source, verify_dr_swap_rejected)
+{
+ struct usb_pd_ctrl_msg_test_fixture *super_fixture = &fixture->fixture;
+ struct ec_response_typec_status typec_status = { 0 };
+ int rv = 0;
+
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_DFP, typec_status.data_role,
+ "Returned data_role=%u", typec_status.data_role);
+
+ /* Send DR_SWAP request */
+ rv = tcpci_partner_send_control_msg(&super_fixture->partner_emul,
+ PD_CTRL_DR_SWAP, 0);
+ zassert_ok(rv, "Failed to send DR_SWAP request, rv=%d", rv);
+
+ k_sleep(K_MSEC(20));
+
+ /* Verify DR_Swap request is REJECTED */
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_DFP, typec_status.data_role,
+ "Returned data_role=%u", typec_status.data_role);
+}
+
+/**
+ * @brief TestPurpose: Verify DR Swap via DPM request when DRP is configured
+ * as source
+ *
+ * @details
+ * - TCPM is configured initially as Sink/UFP.
+ * - TCPM initiates DR swap according to policy (Sink/DFP)
+ * - Test case initiates DPM DR Swap.
+ * - Verify DR Swap Request is processed.
+ *
+ * Expected Results
+ * - Data role changes after DPM DR Swap request
+ */
+ZTEST_F(usb_pd_ctrl_msg_test_source, verify_dpm_dr_swap)
+{
+ struct ec_response_typec_status typec_status = { 0 };
+
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_DFP, typec_status.data_role,
+ "Returned data_role=%u", typec_status.data_role);
+
+ pd_dpm_request(TEST_USB_PORT, DPM_REQUEST_DR_SWAP);
+ k_sleep(K_SECONDS(1));
+
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+ zassert_equal(PD_ROLE_UFP, typec_status.data_role,
+ "Returned data_role=%u", typec_status.data_role);
+}
+
+/**
+ * @brief TestPurpose: Verify TCPM initiates Get_Sink_Cap message during a typec
+ * status host command and receives sink_capabilities message.
+ *
+ * @details
+ * - TCPM is configured initially as Sink
+ * - TypeC Status Host Command is Invoked
+ *
+ * Expected Results
+ * - TypeC Status Host Command reveals sink capabilility PDOs.
+ */
+ZTEST(usb_pd_ctrl_msg_test_source, verify_dpm_get_sink_cap)
+{
+ struct ec_response_typec_status typec_status = { 0 };
+
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+
+ zassert_true(typec_status.sink_cap_count > 1, NULL);
+ zassert_equal(typec_status.sink_cap_pdos[1], TEST_ADDED_PDO, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify TCPM initiates Get_Sink_Cap message during a typec
+ * status host command and receives sink_capabilities message.
+ *
+ * @details
+ * - TCPM is configured initially as Source
+ * - TypeC Status Host Command is Invoked
+ *
+ * Expected Results
+ * - TypeC Status Host Command reveals sink capabilility PDOs.
+ */
+ZTEST(usb_pd_ctrl_msg_test_sink, verify_get_sink_cap)
+{
+ struct ec_response_typec_status typec_status = { 0 };
+
+ typec_status = host_cmd_typec_status(TEST_USB_PORT);
+
+ zassert_true(typec_status.sink_cap_count > 1, NULL);
+ zassert_equal(typec_status.sink_cap_pdos[1], TEST_ADDED_PDO, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify BIST TX MODE 2.
+ *
+ * @details
+ * - TCPM is configured initially as Sink
+ * - Initiate BIST TX
+ *
+ * Expected Results
+ * - BIST occurs and we transition back to READY state
+ */
+ZTEST_F(usb_pd_ctrl_msg_test_source, verify_bist_tx_mode2)
+{
+ struct usb_pd_ctrl_msg_test_fixture *super_fixture = &fixture->fixture;
+ uint32_t bdo = BDO(BDO_MODE_CARRIER2, 0);
+
+ tcpci_partner_send_data_msg(&super_fixture->partner_emul, PD_DATA_BIST,
+ &bdo, 1, 0);
+
+ pd_dpm_request(TEST_USB_PORT, DPM_REQUEST_BIST_TX);
+ k_sleep(K_MSEC(10));
+ zassert_equal(get_state_pe(TEST_USB_PORT), PE_BIST_TX, NULL);
+
+ k_sleep(K_SECONDS(5));
+ zassert_equal(get_state_pe(TEST_USB_PORT), PE_SNK_READY, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify BIST TX TEST DATA.
+ *
+ * @details
+ * - TCPM is configured initially as Sink
+ * - Initiate BIST TX
+ * - End testing via signaling a Hard Reset
+ *
+ * Expected Results
+ * - Partner remains in BIST_TX state until hard reset is received.
+ */
+ZTEST_F(usb_pd_ctrl_msg_test_source, verify_bist_tx_test_data)
+{
+ struct usb_pd_ctrl_msg_test_fixture *super_fixture = &fixture->fixture;
+ uint32_t bdo = BDO(BDO_MODE_TEST_DATA, 0);
+
+ tcpci_partner_send_data_msg(&super_fixture->partner_emul, PD_DATA_BIST,
+ &bdo, 1, 0);
+
+ pd_dpm_request(TEST_USB_PORT, DPM_REQUEST_BIST_TX);
+ k_sleep(K_SECONDS(5));
+ zassert_equal(get_state_pe(TEST_USB_PORT), PE_BIST_TX, NULL);
+
+ tcpci_partner_common_send_hard_reset(&super_fixture->partner_emul);
+ k_sleep(K_SECONDS(1));
+ zassert_equal(get_state_pe(TEST_USB_PORT), PE_SNK_READY, NULL);
+}
diff --git a/zephyr/test/drivers/default/src/integration/usbc/usb_pd_rev3.c b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_rev3.c
new file mode 100644
index 0000000000..fbe634a838
--- /dev/null
+++ b/zephyr/test/drivers/default/src/integration/usbc/usb_pd_rev3.c
@@ -0,0 +1,358 @@
+/* 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/ztest.h>
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "chipset.h"
+#include "emul/emul_isl923x.h"
+#include "emul/emul_smart_battery.h"
+#include "emul/tcpc/emul_tcpci_partner_src.h"
+#include "hooks.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_common.h"
+#include "usb_pd.h"
+#include "util.h"
+
+struct usb_attach_5v_3a_pd_source_rev3_fixture {
+ struct tcpci_partner_data source_5v_3a;
+ struct tcpci_src_emul_data src_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static void *usb_attach_5v_3a_pd_source_setup(void)
+{
+ static struct usb_attach_5v_3a_pd_source_rev3_fixture test_fixture;
+
+ /* Get references for the emulators */
+ test_fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ test_fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ /* Initialized the charger to supply 5V and 3A */
+ tcpci_partner_init(&test_fixture.source_5v_3a, PD_REV30);
+ test_fixture.source_5v_3a.extensions = tcpci_src_emul_init(
+ &test_fixture.src_ext, &test_fixture.source_5v_3a, NULL);
+ test_fixture.src_ext.pdo[1] =
+ PDO_FIXED(5000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &test_fixture;
+}
+
+static void usb_attach_5v_3a_pd_source_before(void *data)
+{
+ struct usb_attach_5v_3a_pd_source_rev3_fixture *fixture = data;
+
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->src_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+
+ /* Clear Alert and Status receive checks */
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+
+ /* Initial check on power state */
+ zassume_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+}
+
+static void usb_attach_5v_3a_pd_source_after(void *data)
+{
+ struct usb_attach_5v_3a_pd_source_rev3_fixture *fixture = data;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+}
+
+ZTEST_SUITE(usb_attach_5v_3a_pd_source_rev3, drivers_predicate_post_main,
+ usb_attach_5v_3a_pd_source_setup, usb_attach_5v_3a_pd_source_before,
+ usb_attach_5v_3a_pd_source_after, NULL);
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, test_batt_cap)
+{
+ int battery_index = 0;
+
+ tcpci_partner_common_send_get_battery_capabilities(
+ &fixture->source_5v_3a, battery_index);
+
+ /* Allow some time for TCPC to process and respond */
+ k_sleep(K_SECONDS(1));
+
+ zassert_true(fixture->source_5v_3a.battery_capabilities
+ .have_response[battery_index],
+ "No battery capabilities response stored.");
+
+ /* The response */
+ struct pd_bcdb *bcdb =
+ &fixture->source_5v_3a.battery_capabilities.bcdb[battery_index];
+
+ zassert_equal(USB_VID_GOOGLE, bcdb->vid, "Incorrect battery VID");
+ zassert_equal(CONFIG_USB_PID, bcdb->pid, "Incorrect battery PID");
+ zassert_false((bcdb->battery_type) & BIT(0),
+ "Invalid battery ref bit should not be set");
+
+ /* Verify the battery capacity and last full charge capacity. These
+ * fields require that the battery is present and that we can
+ * access information about the nominal voltage and capacity.
+ *
+ * TODO(b/237427945): Add test for case when battery is not present
+ */
+
+ /* See pe_give_battery_cap_entry() in common/usbc/usb_pe_drp_sm.c */
+
+ zassume_true(battery_is_present(), "Battery must be present");
+ zassume_true(IS_ENABLED(HAS_TASK_HOSTCMD) &&
+ *host_get_memmap(EC_MEMMAP_BATTERY_VERSION) != 0,
+ "Cannot access battery data");
+
+ /* Millivolts */
+ int design_volt = *(int *)host_get_memmap(EC_MEMMAP_BATT_DVLT);
+
+ /* Milliamphours */
+ int design_cap = *(int *)host_get_memmap(EC_MEMMAP_BATT_DCAP);
+ int full_cap = *(int *)host_get_memmap(EC_MEMMAP_BATT_LFCC);
+
+ /* Multiply millivolts by milliamphours and scale to deciwatthours
+ * (0.1 Wh), the unit of energy used in the PD messages.
+ */
+
+ int expected_design_cap =
+ DIV_ROUND_NEAREST((design_cap * design_volt), 1000 * 1000 / 10);
+
+ int expected_last_charge_cap =
+ DIV_ROUND_NEAREST((design_cap * full_cap), 1000 * 1000 / 10);
+
+ zassert_equal(expected_design_cap, bcdb->design_cap,
+ "Design capacity not correct. Expected %d but got %d",
+ expected_design_cap, bcdb->design_cap);
+ zassert_equal(
+ expected_last_charge_cap, bcdb->last_full_charge_cap,
+ "Last full charge capacity not correct. Expected %d but got %d",
+ expected_last_charge_cap, bcdb->last_full_charge_cap);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, test_batt_cap_invalid)
+{
+ /* Request data on a battery that does not exist. The PD stack only
+ * supports battery 0.
+ */
+
+ int battery_index = 5;
+
+ tcpci_partner_common_send_get_battery_capabilities(
+ &fixture->source_5v_3a, battery_index);
+
+ /* Allow some time for TCPC to process and respond */
+ k_sleep(K_SECONDS(1));
+
+ /* Ensure we get a response that says our battery index was invalid */
+
+ zassert_true(fixture->source_5v_3a.battery_capabilities
+ .have_response[battery_index],
+ "No battery capabilities response stored.");
+ zassert_true(
+ (fixture->source_5v_3a.battery_capabilities.bcdb[battery_index]
+ .battery_type) &
+ BIT(0),
+ "Invalid battery ref bit should be set");
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, verify_alert_msg)
+{
+ zassume_equal(pd_broadcast_alert_msg(ADO_OTP_EVENT), EC_SUCCESS, NULL);
+
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, verify_alert_on_power_state_change)
+{
+ /* Suspend and check partner received Alert and Status messages */
+ hook_notify(HOOK_CHIPSET_SUSPEND);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+
+ /* Shutdown and check partner received Alert and Status messages */
+ hook_notify(HOOK_CHIPSET_SHUTDOWN);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+
+ /* Startup and check partner received Alert and Status messages */
+ hook_notify(HOOK_CHIPSET_STARTUP);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+
+ /* Resume and check partner received Alert and Status messages */
+ hook_notify(HOOK_CHIPSET_RESUME);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3,
+ verify_inaction_on_pd_button_press_while_awake)
+{
+ uint32_t ado;
+
+ /* While awake expect nothing on valid press */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_false(fixture->src_ext.alert_received, NULL);
+ zassert_false(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3,
+ verify_inaction_on_invalid_pd_button_press)
+{
+ uint32_t ado;
+
+ /* Shutdown device to test wake from USB PD power button */
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_BUTTON);
+ k_sleep(K_SECONDS(10));
+
+ /* Clear alert and status flags set during shutdown */
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+ zassume_true(chipset_in_state(CHIPSET_STATE_ANY_OFF), NULL);
+
+ /* While in S5/G3 expect nothing on invalid (too long) press */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(10));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_false(fixture->src_ext.alert_received, NULL);
+ zassert_false(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ANY_OFF), NULL);
+
+ /* Wake device to setup for subsequent tests */
+ chipset_power_on();
+ k_sleep(K_SECONDS(10));
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, verify_startup_on_pd_button_press)
+{
+ uint32_t ado;
+
+ /* Shutdown device to test wake from USB PD power button */
+ chipset_force_shutdown(CHIPSET_SHUTDOWN_BUTTON);
+ k_sleep(K_SECONDS(10));
+
+ /* Clear alert and status flags set during shutdown */
+ tcpci_src_emul_clear_alert_received(&fixture->src_ext);
+ tcpci_src_emul_clear_status_received(&fixture->src_ext);
+ zassume_false(fixture->src_ext.alert_received, NULL);
+ zassume_false(fixture->src_ext.status_received, NULL);
+ zassume_true(chipset_in_state(CHIPSET_STATE_ANY_OFF), NULL);
+
+ /* While in S5/G3 expect Alert->Get_Status->Status on valid press */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+}
+
+ZTEST_F(usb_attach_5v_3a_pd_source_rev3, verify_chipset_on_pd_button_behavior)
+{
+ uint32_t ado;
+
+ /* Expect no power state change on short press */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_false(fixture->src_ext.alert_received, NULL);
+ zassert_false(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+
+ /* Expect no change on invalid button press while chipset is on */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(10));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_false(fixture->src_ext.alert_received, NULL);
+ zassert_false(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+
+ /*
+ * Expect no power state change on 6 second press->press->release due
+ * to the timers resetting on the second press.
+ */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(3));
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(3));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_false(fixture->src_ext.alert_received, NULL);
+ zassert_false(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ON), NULL);
+
+ /* Expect power state change on long press */
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_PRESS;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(6));
+ ado = ADO_EXTENDED_ALERT_EVENT | ADO_POWER_BUTTON_RELEASE;
+ tcpci_partner_send_data_msg(&fixture->source_5v_3a, PD_DATA_ALERT, &ado,
+ 1, 0);
+ k_sleep(K_SECONDS(2));
+ zassert_true(fixture->src_ext.alert_received, NULL);
+ zassert_true(fixture->src_ext.status_received, NULL);
+ zassert_true(chipset_in_state(CHIPSET_STATE_ANY_OFF), NULL);
+
+ /* Wake device to setup for subsequent tests */
+ chipset_power_on();
+ k_sleep(K_SECONDS(10));
+}