summaryrefslogtreecommitdiff
path: root/zephyr/test/drivers/default/src
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/test/drivers/default/src')
-rw-r--r--zephyr/test/drivers/default/src/battery.c41
-rw-r--r--zephyr/test/drivers/default/src/bb_retimer.c578
-rw-r--r--zephyr/test/drivers/default/src/bc12.c277
-rw-r--r--zephyr/test/drivers/default/src/bma2x2.c942
-rw-r--r--zephyr/test/drivers/default/src/bmi160.c2188
-rw-r--r--zephyr/test/drivers/default/src/bmi260.c2305
-rw-r--r--zephyr/test/drivers/default/src/charge_manager.c58
-rw-r--r--zephyr/test/drivers/default/src/console.c88
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelinfo.c55
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelinit.c93
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelrange.c118
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelrate.c104
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelread.c124
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelres.c127
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/accelspoof.c97
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/adc.c43
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/battery.c90
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/button.c67
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/cbi.c81
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/charge_manager.c118
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/charge_state.c282
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/charger.c184
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/crash.c34
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/cutoff.c86
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/gpio.c37
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/hcdebug.c49
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/hibdelay.c37
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/hostevent.c193
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/i2c_portmap.c27
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/md.c83
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/panic_output.c71
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/port80.c46
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/power_button.c34
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/powerindebug.c36
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/rtc.c73
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/rw.c98
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/sleepmask.c100
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/sleeptimeout.c44
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/sysinfo.c84
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/tcpci_dump.c46
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/usb_pd_console.c358
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/version.c37
-rw-r--r--zephyr/test/drivers/default/src/console_cmd/waitms.c51
-rw-r--r--zephyr/test/drivers/default/src/cros_cbi.c55
-rw-r--r--zephyr/test/drivers/default/src/espi.c326
-rw-r--r--zephyr/test/drivers/default/src/flash.c444
-rw-r--r--zephyr/test/drivers/default/src/gpio.c421
-rw-r--r--zephyr/test/drivers/default/src/i2c.c145
-rw-r--r--zephyr/test/drivers/default/src/i2c_passthru.c123
-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
-rw-r--r--zephyr/test/drivers/default/src/isl923x.c1076
-rw-r--r--zephyr/test/drivers/default/src/led.c92
-rw-r--r--zephyr/test/drivers/default/src/lid_angle.c70
-rw-r--r--zephyr/test/drivers/default/src/lid_switch.c277
-rw-r--r--zephyr/test/drivers/default/src/lis2dw12.c455
-rw-r--r--zephyr/test/drivers/default/src/ln9310.c685
-rw-r--r--zephyr/test/drivers/default/src/locate_chip.c134
-rw-r--r--zephyr/test/drivers/default/src/motion_sense/motion_sense.c35
-rw-r--r--zephyr/test/drivers/default/src/panic.c108
-rw-r--r--zephyr/test/drivers/default/src/panic_output.c74
-rw-r--r--zephyr/test/drivers/default/src/port80.c191
-rw-r--r--zephyr/test/drivers/default/src/power_common.c696
-rw-r--r--zephyr/test/drivers/default/src/ppc_sn5s330.c689
-rw-r--r--zephyr/test/drivers/default/src/ppc_syv682x.c815
-rw-r--r--zephyr/test/drivers/default/src/ps8xxx.c1311
-rw-r--r--zephyr/test/drivers/default/src/smart.c568
-rw-r--r--zephyr/test/drivers/default/src/stm_mems_common.c338
-rw-r--r--zephyr/test/drivers/default/src/system.c113
-rw-r--r--zephyr/test/drivers/default/src/tablet_mode.c168
-rw-r--r--zephyr/test/drivers/default/src/tcpci.c524
-rw-r--r--zephyr/test/drivers/default/src/tcpci_test_common.c1030
-rw-r--r--zephyr/test/drivers/default/src/tcs3400.c641
-rw-r--r--zephyr/test/drivers/default/src/temp_sensor.c200
-rw-r--r--zephyr/test/drivers/default/src/thermistor.c327
-rw-r--r--zephyr/test/drivers/default/src/uart_hostcmd.c231
-rw-r--r--zephyr/test/drivers/default/src/usb_mux.c912
-rw-r--r--zephyr/test/drivers/default/src/usb_pd_host_cmd.c26
-rw-r--r--zephyr/test/drivers/default/src/vboot_hash.c103
-rw-r--r--zephyr/test/drivers/default/src/virtual_battery.c259
-rw-r--r--zephyr/test/drivers/default/src/vstore.c230
-rw-r--r--zephyr/test/drivers/default/src/watchdog.c142
88 files changed, 26323 insertions, 0 deletions
diff --git a/zephyr/test/drivers/default/src/battery.c b/zephyr/test/drivers/default/src/battery.c
new file mode 100644
index 0000000000..6b01a5ca39
--- /dev/null
+++ b/zephyr/test/drivers/default/src/battery.c
@@ -0,0 +1,41 @@
+/* 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.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "battery.h"
+#include "test/drivers/test_state.h"
+
+#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 battery_after(void *data)
+{
+ const struct device *dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_BATT_PRES_ODL_PATH, gpios));
+
+ /* Set default state (battery is present) */
+ gpio_emul_input_set(dev, GPIO_BATT_PRES_ODL_PORT, 0);
+}
+
+ZTEST_USER(battery, test_battery_is_present_gpio)
+{
+ const struct device *dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_BATT_PRES_ODL_PATH, gpios));
+
+ zassert_not_null(dev, NULL);
+ /* ec_batt_pres_odl = 0 means battery present. */
+ zassert_ok(gpio_emul_input_set(dev, GPIO_BATT_PRES_ODL_PORT, 0), NULL);
+ zassert_equal(BP_YES, battery_is_present(), NULL);
+ /* ec_batt_pres_odl = 1 means battery missing. */
+ zassert_ok(gpio_emul_input_set(dev, GPIO_BATT_PRES_ODL_PORT, 1), NULL);
+ zassert_equal(BP_NO, battery_is_present(), NULL);
+}
+
+ZTEST_SUITE(battery, drivers_predicate_post_main, NULL, NULL, battery_after,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/bb_retimer.c b/zephyr/test/drivers/default/src/bb_retimer.c
new file mode 100644
index 0000000000..74d8fa86a2
--- /dev/null
+++ b/zephyr/test/drivers/default/src/bb_retimer.c
@@ -0,0 +1,578 @@
+/* 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.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include "emul/emul_bb_retimer.h"
+#include "emul/emul_common_i2c.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "test/drivers/stubs.h"
+#include "usb_prl_sm.h"
+#include "usb_tc_sm.h"
+#include "chipset.h"
+
+#include "driver/retimer/bb_retimer.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+#define GPIO_USB_C1_LS_EN_PATH DT_PATH(named_gpios, usb_c1_ls_en)
+#define GPIO_USB_C1_LS_EN_PORT DT_GPIO_PIN(GPIO_USB_C1_LS_EN_PATH, gpios)
+#define GPIO_USB_C1_RT_RST_ODL_PATH DT_PATH(named_gpios, usb_c1_rt_rst_odl)
+#define GPIO_USB_C1_RT_RST_ODL_PORT \
+ DT_GPIO_PIN(GPIO_USB_C1_RT_RST_ODL_PATH, gpios)
+#define BB_RETIMER_NODE DT_NODELABEL(usb_c1_bb_retimer_emul)
+
+/** Test is retimer fw update capable function. */
+ZTEST_USER(bb_retimer, test_bb_is_fw_update_capable)
+{
+ /* BB retimer is fw update capable */
+ zassert_true(bb_usb_retimer.is_retimer_fw_update_capable(), NULL);
+}
+
+/** Test is retimer fw update capable function. */
+ZTEST_USER(bb_retimer_no_tasks, test_bb_set_state)
+{
+ struct pd_discovery *disc;
+ uint32_t conn, exp_conn;
+ const struct emul *emul = EMUL_DT_GET(BB_RETIMER_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bb_retimer_get_i2c_common_data(emul);
+ bool ack_required;
+
+ set_test_runner_tid();
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BB_RETIMER_REG_CONNECTION_STATE);
+
+ /* Test fail on reset register write */
+ zassert_equal(EC_ERROR_INVAL,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_NONE, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set UFP role for whole test */
+ tc_set_data_role(USBC_PORT_C1, PD_ROLE_UFP);
+ zassume_equal(PD_ROLE_UFP, pd_get_data_role(USBC_PORT_C1), NULL);
+
+ /* Test none mode */
+ bb_emul_set_reg(emul, BB_RETIMER_REG_CONNECTION_STATE, 0x12144678);
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_NONE, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ /* Only UFP mode is set */
+ exp_conn = BB_RETIMER_USB_DATA_ROLE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test USB3 gen1 mode */
+ prl_set_rev(USBC_PORT_C1, TCPCI_MSG_SOP_PRIME, PD_REV10);
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_USB_ENABLED, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_USB_3_CONNECTION;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test USB3 gen2 mode */
+ disc = pd_get_am_discovery_and_notify_access(USBC_PORT_C1,
+ TCPCI_MSG_SOP_PRIME);
+ disc->identity.product_t1.p_rev30.ss = USB_R30_SS_U32_U40_GEN2;
+ prl_set_rev(USBC_PORT_C1, TCPCI_MSG_SOP_PRIME, PD_REV30);
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_USB_ENABLED, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_USB_3_CONNECTION | BB_RETIMER_USB_3_SPEED;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test USB4 mode */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_USB4_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_USB4_ENABLED;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test USB4 mode with polarity inverted */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_USB4_ENABLED |
+ USB_PD_MUX_POLARITY_INVERTED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_CONNECTION_ORIENTATION | BB_RETIMER_USB4_ENABLED;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test DP mode */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_DP_ENABLED, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_DP_ENABLED |
+ USB_PD_MUX_HPD_IRQ,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_IRQ_HPD;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_DP_ENABLED |
+ USB_PD_MUX_HPD_LVL,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_USB_DATA_ROLE |
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_HPD_LVL;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+}
+
+/** Test setting different options for DFP role */
+ZTEST_USER(bb_retimer_no_tasks, test_bb_set_dfp_state)
+{
+ union tbt_mode_resp_device device_resp;
+ union tbt_mode_resp_cable cable_resp;
+ struct pd_discovery *disc, *dev_disc;
+ uint32_t conn, exp_conn;
+ const struct emul *emul = EMUL_DT_GET(BB_RETIMER_NODE);
+ bool ack_required;
+
+ set_test_runner_tid();
+
+ tc_set_data_role(USBC_PORT_C1, PD_ROLE_DFP);
+ zassume_equal(PD_ROLE_DFP, pd_get_data_role(USBC_PORT_C1), NULL);
+
+ /* Test PD mux none mode with DFP should clear all bits in state */
+ bb_emul_set_reg(emul, BB_RETIMER_REG_CONNECTION_STATE, 0x12144678);
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_NONE, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = 0;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Set active cable type */
+ disc = pd_get_am_discovery_and_notify_access(USBC_PORT_C1,
+ TCPCI_MSG_SOP_PRIME);
+ disc->identity.idh.product_type = IDH_PTYPE_ACABLE;
+ disc->identity.product_t2.a2_rev30.active_elem = ACTIVE_RETIMER;
+ disc->identity.product_t1.p_rev30.ss = USB_R30_SS_U32_U40_GEN2;
+ prl_set_rev(USBC_PORT_C1, TCPCI_MSG_SOP_PRIME, PD_REV30);
+
+ /* Set cable VDO */
+ disc->svid_cnt = 1;
+ disc->svids[0].svid = USB_VID_INTEL;
+ disc->svids[0].discovery = PD_DISC_COMPLETE;
+ disc->svids[0].mode_cnt = 1;
+ cable_resp.tbt_alt_mode = TBT_ALTERNATE_MODE;
+ cable_resp.tbt_cable_speed = TBT_SS_RES_0;
+ cable_resp.tbt_rounded = TBT_GEN3_NON_ROUNDED;
+ cable_resp.tbt_cable = TBT_CABLE_NON_OPTICAL;
+ cable_resp.retimer_type = USB_NOT_RETIMER;
+ cable_resp.lsrx_comm = BIDIR_LSRX_COMM;
+ cable_resp.tbt_active_passive = TBT_CABLE_PASSIVE;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+
+ /* Set device VDO */
+ dev_disc = pd_get_am_discovery_and_notify_access(USBC_PORT_C1,
+ TCPCI_MSG_SOP);
+ dev_disc->svid_cnt = 1;
+ dev_disc->svids[0].svid = USB_VID_INTEL;
+ dev_disc->svids[0].discovery = PD_DISC_COMPLETE;
+ dev_disc->svids[0].mode_cnt = 1;
+ device_resp.tbt_alt_mode = TBT_ALTERNATE_MODE;
+ device_resp.tbt_adapter = TBT_ADAPTER_TBT3;
+ device_resp.intel_spec_b0 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ device_resp.vendor_spec_b0 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ device_resp.vendor_spec_b1 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ dev_disc->svids[0].mode_vdo[0] = device_resp.raw_value;
+
+ /* Test USB mode with active cable */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_USB_ENABLED, &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_USB_3_CONNECTION | BB_RETIMER_USB_3_SPEED |
+ BB_RETIMER_RE_TIMER_DRIVER | BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with active cable */
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION | BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with retimer */
+ cable_resp.retimer_type = USB_RETIMER;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION | BB_RETIMER_RE_TIMER_DRIVER |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with optical cable */
+ cable_resp.retimer_type = USB_NOT_RETIMER;
+ cable_resp.tbt_cable = TBT_CABLE_OPTICAL;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION | BB_RETIMER_TBT_CABLE_TYPE |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with active link training */
+ cable_resp.tbt_cable = TBT_CABLE_NON_OPTICAL;
+ cable_resp.lsrx_comm = UNIDIR_LSRX_COMM;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn =
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_TBT_ACTIVE_LINK_TRAINING | BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with different cable speeds */
+ cable_resp.lsrx_comm = BIDIR_LSRX_COMM;
+ cable_resp.tbt_cable_speed = TBT_SS_U31_GEN1;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(1) |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ cable_resp.tbt_cable_speed = TBT_SS_U32_GEN1_GEN2;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(2) |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ cable_resp.tbt_cable_speed = TBT_SS_TBT_GEN3;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_USB4_TBT_CABLE_SPEED_SUPPORT(3) |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with TBT gen4 cable */
+ cable_resp.tbt_cable_speed = TBT_SS_RES_0;
+ cable_resp.tbt_rounded = TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn =
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_TBT_CABLE_GENERATION(1) | BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with legacy TBT adapter */
+ cable_resp.tbt_rounded = TBT_GEN3_NON_ROUNDED;
+ disc->svids[0].mode_vdo[0] = cable_resp.raw_value;
+ device_resp.tbt_adapter = TBT_ADAPTER_TBT2_LEGACY;
+ dev_disc->svids[0].mode_vdo[0] = device_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION | BB_RETIMER_TBT_TYPE |
+ BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with Intel specific b0 */
+ device_resp.tbt_adapter = TBT_ADAPTER_TBT3;
+ device_resp.intel_spec_b0 = VENDOR_SPECIFIC_SUPPORTED;
+ dev_disc->svids[0].mode_vdo[0] = device_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn = BB_RETIMER_DATA_CONNECTION_PRESENT |
+ BB_RETIMER_TBT_CONNECTION | BB_RETIMER_ACTIVE_PASSIVE;
+
+ if (IS_ENABLED(CONFIG_USBC_RETIMER_INTEL_BB_VPRO_CAPABLE))
+ exp_conn |= BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE;
+
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+
+ /* Test TBT mode with vendor specific b1 */
+ device_resp.intel_spec_b0 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ device_resp.vendor_spec_b1 = VENDOR_SPECIFIC_SUPPORTED;
+ dev_disc->svids[0].mode_vdo[0] = device_resp.raw_value;
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.set(usb_muxes[USBC_PORT_C1].mux,
+ USB_PD_MUX_TBT_COMPAT_ENABLED,
+ &ack_required),
+ NULL);
+ zassert_false(ack_required, "ACK is never required for BB retimer");
+ conn = bb_emul_get_reg(emul, BB_RETIMER_REG_CONNECTION_STATE);
+ exp_conn =
+ BB_RETIMER_DATA_CONNECTION_PRESENT | BB_RETIMER_TBT_CONNECTION |
+ BB_RETIMER_VPRO_DOCK_DP_OVERDRIVE | BB_RETIMER_ACTIVE_PASSIVE;
+ zassert_equal(exp_conn, conn, "Expected state 0x%lx, got 0x%lx",
+ exp_conn, conn);
+}
+
+/** Test BB retimer init */
+ZTEST_USER(bb_retimer, test_bb_init)
+{
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_USB_C1_LS_EN_PATH, gpios));
+ const struct emul *emul = EMUL_DT_GET(BB_RETIMER_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bb_retimer_get_i2c_common_data(emul);
+
+ zassert_not_null(gpio_dev, "Cannot get GPIO device");
+
+ /* Set AP to normal state and wait for chipset task */
+ test_set_chipset_to_s0();
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BB_RETIMER_REG_VENDOR_ID);
+ /* Test fail on vendor ID read */
+ zassert_equal(EC_ERROR_INVAL,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ /* Enable pins should be set always after init, when AP is on */
+ zassert_equal(1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+ zassert_equal(
+ 1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+
+ /* Setup wrong vendor ID */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bb_emul_set_reg(emul, BB_RETIMER_REG_VENDOR_ID, 0x12144678);
+ /* Test fail on wrong vendor ID */
+ zassert_equal(EC_ERROR_INVAL,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ zassert_equal(1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+ zassert_equal(
+ 1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+
+ /* Setup emulator fail on device ID read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BB_RETIMER_REG_DEVICE_ID);
+ bb_emul_set_reg(emul, BB_RETIMER_REG_VENDOR_ID, BB_RETIMER_VENDOR_ID_1);
+ /* Test fail on device ID read */
+ zassert_equal(EC_ERROR_INVAL,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ zassert_equal(1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+ zassert_equal(
+ 1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+
+ /* Setup wrong device ID */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bb_emul_set_reg(emul, BB_RETIMER_REG_DEVICE_ID, 0x12144678);
+ /* Test fail on wrong device ID */
+ zassert_equal(EC_ERROR_INVAL,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ zassert_equal(1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+ zassert_equal(
+ 1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+
+ /* Test successful init */
+ bb_emul_set_reg(emul, BB_RETIMER_REG_DEVICE_ID, BB_RETIMER_DEVICE_ID);
+ zassert_equal(EC_SUCCESS,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ zassert_equal(1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+ zassert_equal(
+ 1, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+
+ /* Set AP to off state and wait for chipset task */
+ test_set_chipset_to_g3();
+
+ /* With AP off, init should fail and pins should be unset */
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ bb_usb_retimer.init(usb_muxes[USBC_PORT_C1].mux), NULL);
+ zassert_equal(0, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_LS_EN_PORT),
+ NULL);
+
+ msleep(1);
+ zassert_equal(
+ 0, gpio_emul_output_get(gpio_dev, GPIO_USB_C1_RT_RST_ODL_PORT),
+ NULL);
+}
+
+/** Test BB retimer console command */
+ZTEST_USER(bb_retimer, test_bb_console_cmd)
+{
+ int rv;
+
+ /* Validate well formed shell commands */
+ rv = shell_execute_cmd(get_ec_shell(), "bb 1 r 2");
+ zassert_ok(rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb 1 w 2 0");
+ zassert_ok(rv, "rv=%d", rv);
+
+ /* Validate errors for malformed shell commands */
+ rv = shell_execute_cmd(get_ec_shell(), "bb x");
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb x r 2");
+ zassert_equal(EC_ERROR_PARAM1, rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb 0 r 2");
+ zassert_equal(EC_ERROR_PARAM1, rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb 1 x 2");
+ zassert_equal(EC_ERROR_PARAM2, rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb 1 r x");
+ zassert_equal(EC_ERROR_PARAM3, rv, "rv=%d", rv);
+ rv = shell_execute_cmd(get_ec_shell(), "bb 1 w 2 x");
+ zassert_equal(EC_ERROR_PARAM4, rv, "rv=%d", rv);
+}
+
+ZTEST_SUITE(bb_retimer_no_tasks, drivers_predicate_pre_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_SUITE(bb_retimer, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/bc12.c b/zephyr/test/drivers/default/src/bc12.c
new file mode 100644
index 0000000000..a8d23e73ce
--- /dev/null
+++ b/zephyr/test/drivers/default/src/bc12.c
@@ -0,0 +1,277 @@
+/* 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.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "emul/emul_pi3usb9201.h"
+
+#include "timer.h"
+#include "usb_charge.h"
+#include "battery.h"
+#include "extpower.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+#include <zephyr/logging/log.h>
+LOG_MODULE_REGISTER(test_drivers_bc12, LOG_LEVEL_DBG);
+
+#define EMUL_NODE DT_NODELABEL(pi3usb9201_emul)
+
+/* Control_1 register bit definitions */
+#define PI3USB9201_REG_CTRL_1_INT_MASK BIT(0)
+#define PI3USB9201_REG_CTRL_1_MODE_SHIFT 1
+#define PI3USB9201_REG_CTRL_1_MODE_MASK \
+ (0x7 << PI3USB9201_REG_CTRL_1_MODE_SHIFT)
+
+/* Control_2 register bit definitions */
+#define PI3USB9201_REG_CTRL_2_AUTO_SW BIT(1)
+#define PI3USB9201_REG_CTRL_2_START_DET BIT(3)
+
+/* Host status register bit definitions */
+#define PI3USB9201_REG_HOST_STS_BC12_DET BIT(0)
+#define PI3USB9201_REG_HOST_STS_DEV_PLUG BIT(1)
+#define PI3USB9201_REG_HOST_STS_DEV_UNPLUG BIT(2)
+
+enum pi3usb9201_mode {
+ PI3USB9201_POWER_DOWN,
+ PI3USB9201_SDP_HOST_MODE,
+ PI3USB9201_DCP_HOST_MODE,
+ PI3USB9201_CDP_HOST_MODE,
+ PI3USB9201_CLIENT_MODE,
+ PI3USB9201_RESERVED_1,
+ PI3USB9201_RESERVED_2,
+ PI3USB9201_USB_PATH_ON,
+};
+
+enum pi3usb9201_client_sts {
+ CHG_OTHER = 0,
+ CHG_2_4A,
+ CHG_2_0A,
+ CHG_1_0A,
+ CHG_RESERVED,
+ CHG_CDP,
+ CHG_SDP,
+ CHG_DCP,
+};
+
+struct bc12_status {
+ enum charge_supplier supplier;
+ int current_limit;
+};
+
+static const struct bc12_status bc12_chg_limits[] = {
+ [CHG_OTHER] = { .supplier = CHARGE_SUPPLIER_OTHER,
+ .current_limit = 500 },
+ [CHG_2_4A] = { .supplier = CHARGE_SUPPLIER_PROPRIETARY,
+ .current_limit = USB_CHARGER_MAX_CURR_MA },
+ [CHG_2_0A] = { .supplier = CHARGE_SUPPLIER_PROPRIETARY,
+ .current_limit = USB_CHARGER_MAX_CURR_MA },
+ [CHG_1_0A] = { .supplier = CHARGE_SUPPLIER_PROPRIETARY,
+ .current_limit = 1000 },
+ [CHG_RESERVED] = { .supplier = CHARGE_SUPPLIER_NONE,
+ .current_limit = 0 },
+ [CHG_CDP] = { .supplier = CHARGE_SUPPLIER_BC12_CDP,
+ .current_limit = USB_CHARGER_MAX_CURR_MA },
+ [CHG_SDP] = { .supplier = CHARGE_SUPPLIER_BC12_SDP,
+ .current_limit = 500 },
+#if defined(CONFIG_CHARGE_RAMP_SW) || defined(CONFIG_CHARGE_RAMP_HW)
+ [CHG_DCP] = { .supplier = CHARGE_SUPPLIER_BC12_DCP,
+ .current_limit = USB_CHARGER_MAX_CURR_MA },
+#else
+ [CHG_DCP] = { .supplier = CHARGE_SUPPLIER_BC12_DCP,
+ .current_limit = 500 },
+#endif
+};
+
+#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 test_bc12_pi3usb9201_host_mode(void)
+{
+ const struct emul *emul = EMUL_DT_GET(EMUL_NODE);
+ uint8_t a, b;
+
+ /*
+ * Pretend that the USB-C Port Manager (TCPMv2) has set the port data
+ * role to DFP.
+ */
+ usb_charger_task_set_event(0, USB_CHG_EVENT_DR_DFP);
+ msleep(1);
+ /*
+ * Expect the pi3usb9201 driver to configure CDP host mode and unmask
+ * interrupts.
+ */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_CDP_HOST_MODE << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ zassert_equal(a, b, NULL);
+
+ /* Pretend that a device has been plugged in. */
+ msleep(500);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_HOST_STS,
+ PI3USB9201_REG_HOST_STS_DEV_PLUG);
+ usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
+ msleep(1);
+ /* Expect the pi3usb9201 driver to configure SDP host mode. */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_SDP_HOST_MODE << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ zassert_equal(a, b, NULL);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_HOST_STS, 0);
+
+ /* Pretend that a device has been unplugged. */
+ msleep(500);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_HOST_STS,
+ PI3USB9201_REG_HOST_STS_DEV_UNPLUG);
+ usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
+ msleep(1);
+ /* Expect the pi3usb9201 driver to configure CDP host mode. */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_CDP_HOST_MODE << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ zassert_equal(a, b, NULL);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_HOST_STS, 0);
+}
+
+static void
+test_bc12_pi3usb9201_client_mode(enum pi3usb9201_client_sts detect_result,
+ enum charge_supplier supplier,
+ int current_limit)
+{
+ const struct emul *emul = EMUL_DT_GET(EMUL_NODE);
+ uint8_t a, b;
+ int port, voltage;
+
+ /*
+ * Pretend that the USB-C Port Manager (TCPMv2) has set the port data
+ * role to UFP and decided charging from the port is allowed.
+ */
+ msleep(500);
+ usb_charger_task_set_event(0, USB_CHG_EVENT_DR_UFP);
+ charge_manager_update_dualrole(USBC_PORT_C0, CAP_DEDICATED);
+ msleep(1);
+ /*
+ * Expect the pi3usb9201 driver to configure client mode and start
+ * detection.
+ */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_CLIENT_MODE << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ zassert_equal(a, b, NULL);
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_2, &a);
+ b = PI3USB9201_REG_CTRL_2_START_DET;
+ zassert_equal(a, b, NULL);
+
+ /* Pretend that detection completed. */
+ msleep(500);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_CLIENT_STS,
+ 1 << detect_result);
+ usb_charger_task_set_event(0, USB_CHG_EVENT_BC12);
+ msleep(1);
+ /* Expect the pi3usb9201 driver to clear the start bit. */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_2, &a);
+ zassert_equal(a, 0, NULL);
+ pi3usb9201_emul_set_reg(emul, PI3USB9201_REG_CLIENT_STS, 0);
+ /*
+ * Expect the charge manager to select the detected BC1.2 supplier.
+ */
+ port = CHARGE_PORT_NONE;
+ voltage = 0;
+ if (supplier != CHARGE_SUPPLIER_NONE) {
+ port = USBC_PORT_C0;
+ voltage = USB_CHARGER_VOLTAGE_MV;
+ }
+ /* Wait for the charge port to update. */
+ msleep(500);
+ zassert_equal(charge_manager_get_active_charge_port(), port, NULL);
+ zassert_equal(charge_manager_get_supplier(), supplier, NULL);
+ zassert_equal(charge_manager_get_charger_current(), current_limit,
+ NULL);
+ zassert_equal(charge_manager_get_charger_voltage(), voltage, NULL);
+
+ /*
+ * Pretend that the USB-C Port Manager (TCPMv2) has set the port data
+ * role to disconnected.
+ */
+ msleep(500);
+ usb_charger_task_set_event(0, USB_CHG_EVENT_CC_OPEN);
+ msleep(1);
+ /*
+ * Expect the pi3usb9201 driver to configure power down mode and mask
+ * interrupts.
+ */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_POWER_DOWN << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ b |= PI3USB9201_REG_CTRL_1_INT_MASK;
+ zassert_equal(a, b, NULL);
+ /* Expect the charge manager to have no active supplier. */
+ zassert_equal(charge_manager_get_active_charge_port(), CHARGE_PORT_NONE,
+ NULL);
+ zassert_equal(charge_manager_get_supplier(), CHARGE_SUPPLIER_NONE,
+ NULL);
+ zassert_equal(charge_manager_get_charger_current(), 0, NULL);
+ zassert_equal(charge_manager_get_charger_voltage(), 0, NULL);
+}
+
+/*
+ * PI3USB9201 is a dual-role BC1.2 charger detector/advertiser used on USB
+ * ports. It can be programmed to operate in host mode or client mode through
+ * I2C. When operating as a host, PI3USB9201 enables BC1.2 SDP/CDP/DCP
+ * advertisement to the attached USB devices via the D+/- connection. When
+ * operating as a client, PI3USB9201 starts BC1.2 detection to detect the
+ * attached host type. In both host mode and client mode, the detection results
+ * are reported through I2C to the controller.
+ */
+ZTEST_USER(bc12, test_bc12_pi3usb9201)
+{
+ const struct device *batt_pres_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_BATT_PRES_ODL_PATH, gpios));
+ const struct emul *emul = EMUL_DT_GET(EMUL_NODE);
+ uint8_t a, b;
+
+ /* Pretend we have battery and AC so charging works normally. */
+ zassert_ok(gpio_emul_input_set(batt_pres_dev, GPIO_BATT_PRES_ODL_PORT,
+ 0),
+ NULL);
+ zassert_equal(BP_YES, battery_is_present(), NULL);
+ set_ac_enabled(true);
+
+ /* Wait long enough for TCPMv2 to be idle. */
+ msleep(2000);
+
+ /*
+ * Pretend that the USB-C Port Manager (TCPMv2) has set the port data
+ * role to disconnected.
+ */
+ usb_charger_task_set_event(0, USB_CHG_EVENT_CC_OPEN);
+ usb_charger_task_set_event(1, USB_CHG_EVENT_CC_OPEN);
+ msleep(1);
+ /*
+ * Expect the pi3usb9201 driver to configure power down mode and mask
+ * interrupts.
+ */
+ pi3usb9201_emul_get_reg(emul, PI3USB9201_REG_CTRL_1, &a);
+ b = PI3USB9201_POWER_DOWN << PI3USB9201_REG_CTRL_1_MODE_SHIFT;
+ b |= PI3USB9201_REG_CTRL_1_INT_MASK;
+ zassert_equal(a, b, NULL);
+
+ test_bc12_pi3usb9201_host_mode();
+
+ for (int c = CHG_OTHER; c <= CHG_DCP; c++) {
+ test_bc12_pi3usb9201_client_mode(
+ c, bc12_chg_limits[c].supplier,
+ bc12_chg_limits[c].current_limit);
+ }
+}
+
+/*
+ * TODO(b/216660795): Cleanup state using a teardown_fn
+ */
+static void bc12_after(void *unused)
+{
+ set_ac_enabled(false);
+}
+
+ZTEST_SUITE(bc12, drivers_predicate_post_main, NULL, NULL, bc12_after, NULL);
diff --git a/zephyr/test/drivers/default/src/bma2x2.c b/zephyr/test/drivers/default/src/bma2x2.c
new file mode 100644
index 0000000000..e848a265fd
--- /dev/null
+++ b/zephyr/test/drivers/default/src/bma2x2.c
@@ -0,0 +1,942 @@
+/* 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 "common.h"
+#include "i2c.h"
+#include "emul/emul_bma255.h"
+#include "emul/emul_common_i2c.h"
+
+#include "accelgyro.h"
+#include "motion_sense.h"
+#include "driver/accel_bma2x2.h"
+#include "test/drivers/test_state.h"
+
+/** How accurate comparision of vectors should be. */
+#define V_EPS 8
+
+#define BMA_NODE DT_NODELABEL(bma_emul)
+
+/** Mutex for test motion sensor */
+static mutex_t sensor_mutex;
+
+/** Rotation used in some tests */
+static const mat33_fp_t test_rotation = { { 0, FLOAT_TO_FP(1), 0 },
+ { FLOAT_TO_FP(-1), 0, 0 },
+ { 0, 0, FLOAT_TO_FP(-1) } };
+
+/** Rotate given vector by test rotation */
+void rotate_int3v_by_test_rotation(int16_t *v)
+{
+ int16_t t;
+
+ t = v[0];
+ v[0] = -v[1];
+ v[1] = t;
+ v[2] = -v[2];
+}
+
+static struct accelgyro_saved_data_t acc_data;
+
+/** Mock minimal motion sensor setup required for bma2x2 driver test */
+static struct motion_sensor_t ms = {
+ .name = "bma_emul",
+ .type = MOTIONSENSE_TYPE_ACCEL,
+ .drv = &bma2x2_accel_drv,
+ .mutex = &sensor_mutex,
+ .drv_data = &acc_data,
+ .port = I2C_PORT_NODELABEL(i2c0),
+ .i2c_spi_addr_flags = DT_REG_ADDR(BMA_NODE),
+ .rot_standard_ref = NULL,
+ .current_range = 0,
+};
+
+/** Set emulator offset values to vector of three int16_t */
+static void set_emul_offset(const struct emul *emul, int16_t *offset)
+{
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_X, offset[0]);
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_Y, offset[1]);
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_Z, offset[2]);
+}
+
+/** Save emulator offset values to vector of three int16_t */
+static void get_emul_offset(const struct emul *emul, int16_t *offset)
+{
+ offset[0] = bma_emul_get_off(emul, BMA_EMUL_AXIS_X);
+ offset[1] = bma_emul_get_off(emul, BMA_EMUL_AXIS_Y);
+ offset[2] = bma_emul_get_off(emul, BMA_EMUL_AXIS_Z);
+}
+
+/** Set emulator accelerometer values to vector of three int16_t */
+static void set_emul_acc(const struct emul *emul, int16_t *acc)
+{
+ bma_emul_set_acc(emul, BMA_EMUL_AXIS_X, acc[0]);
+ bma_emul_set_acc(emul, BMA_EMUL_AXIS_Y, acc[1]);
+ bma_emul_set_acc(emul, BMA_EMUL_AXIS_Z, acc[2]);
+}
+
+/** Convert accelerometer read to units used by emulator */
+static void drv_acc_to_emul(intv3_t drv, int range, int16_t *out)
+{
+ const int scale = MOTION_SCALING_FACTOR / BMA_EMUL_1G;
+
+ out[0] = drv[0] * range / scale;
+ out[1] = drv[1] * range / scale;
+ out[2] = drv[2] * range / scale;
+}
+
+/** Compare two vectors of three int16_t */
+static void compare_int3v_f(int16_t *exp_v, int16_t *v, int line)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ zassert_within(
+ exp_v[i], v[i], V_EPS,
+ "Expected [%d; %d; %d], got [%d; %d; %d]; line: %d",
+ exp_v[0], exp_v[1], exp_v[2], v[0], v[1], v[2], line);
+ }
+}
+#define compare_int3v(exp_v, v) compare_int3v_f(exp_v, v, __LINE__)
+
+/** Data for reset fail function */
+struct reset_func_data {
+ /** Fail for given attempts */
+ int fail_attempts;
+ /** Do not fail for given attempts */
+ int ok_before_fail;
+ /** Reset register value after given attempts */
+ int reset_value;
+};
+
+/**
+ * Custom emulator function used in init test. It returns cmd soft when reset
+ * register is accessed data.reset_value times. Error is returned after
+ * accessing register data.ok_before_fail times. Error is returned during next
+ * data.fail_attempts times.
+ */
+static int emul_read_reset(const struct emul *emul, int reg, uint8_t *buf,
+ int bytes, void *data)
+{
+ struct reset_func_data *d = data;
+
+ reg = bma_emul_access_reg(emul, reg, bytes, true /* = read */);
+ if (reg != BMA2x2_RST_ADDR) {
+ return 1;
+ }
+
+ if (d->reset_value > 0) {
+ d->reset_value--;
+ bma_emul_set_reg(emul, BMA2x2_RST_ADDR, BMA2x2_CMD_SOFT_RESET);
+ } else {
+ bma_emul_set_reg(emul, BMA2x2_RST_ADDR, 0);
+ }
+
+ if (d->ok_before_fail > 0) {
+ d->ok_before_fail--;
+ return 1;
+ }
+
+ if (d->fail_attempts > 0) {
+ d->fail_attempts--;
+ return -EIO;
+ }
+
+ return 1;
+}
+
+/**
+ * Test get offset with and without rotation. Also test behaviour on I2C error.
+ */
+ZTEST_USER(bma2x2, test_bma_get_offset)
+{
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int16_t ret_offset[3];
+ int16_t exp_offset[3];
+ int16_t temp;
+
+ /* Test fail on each axis */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BMA2x2_OFFSET_X_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL,
+ ms.drv->get_offset(&ms, ret_offset, &temp), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BMA2x2_OFFSET_Y_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL,
+ ms.drv->get_offset(&ms, ret_offset, &temp), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BMA2x2_OFFSET_Z_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL,
+ ms.drv->get_offset(&ms, ret_offset, &temp), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set emulator offset */
+ exp_offset[0] = BMA_EMUL_1G / 10;
+ exp_offset[1] = BMA_EMUL_1G / 20;
+ exp_offset[2] = -(int)BMA_EMUL_1G / 30;
+ set_emul_offset(emul, exp_offset);
+ /* Disable rotation */
+ ms.rot_standard_ref = NULL;
+
+ /* Test get offset without rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->get_offset(&ms, ret_offset, &temp),
+ NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ compare_int3v(exp_offset, ret_offset);
+
+ /* Setup rotation and rotate expected offset */
+ ms.rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_offset);
+
+ /* Test get offset with rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->get_offset(&ms, ret_offset, &temp),
+ NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ compare_int3v(exp_offset, ret_offset);
+}
+
+/**
+ * Test set offset with and without rotation. Also test behaviour on I2C error.
+ */
+ZTEST_USER(bma2x2, test_bma_set_offset)
+{
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int16_t ret_offset[3];
+ int16_t exp_offset[3] = { 0, 0, 0 };
+ int16_t temp = 0;
+
+ /* Test fail on each axis */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMA2x2_OFFSET_X_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_offset(&ms, exp_offset, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMA2x2_OFFSET_Y_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_offset(&ms, exp_offset, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMA2x2_OFFSET_Z_AXIS_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_offset(&ms, exp_offset, temp),
+ NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set input offset */
+ exp_offset[0] = BMA_EMUL_1G / 10;
+ exp_offset[1] = BMA_EMUL_1G / 20;
+ exp_offset[2] = -(int)BMA_EMUL_1G / 30;
+ /* Disable rotation */
+ ms.rot_standard_ref = NULL;
+
+ /* Test set offset without rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->set_offset(&ms, exp_offset, temp),
+ NULL);
+ get_emul_offset(emul, ret_offset);
+ compare_int3v(exp_offset, ret_offset);
+
+ /* Setup rotation and rotate input for set_offset function */
+ ms.rot_standard_ref = &test_rotation;
+ ret_offset[0] = exp_offset[0];
+ ret_offset[1] = exp_offset[1];
+ ret_offset[2] = exp_offset[2];
+ rotate_int3v_by_test_rotation(ret_offset);
+
+ /* Test set offset with rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->set_offset(&ms, ret_offset, temp),
+ NULL);
+ get_emul_offset(emul, ret_offset);
+ compare_int3v(exp_offset, ret_offset);
+}
+
+/*
+ * Try to set range and check if expected range was set in driver and in
+ * emulator.
+ */
+static void check_set_range_f(const struct emul *emul, int range, int rnd,
+ int exp_range, int line)
+{
+ uint8_t exp_range_reg;
+ uint8_t range_reg;
+
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, range, rnd),
+ "set_range failed; line: %d", line);
+ zassert_equal(exp_range, ms.current_range,
+ "Expected range %d, got %d; line %d", exp_range,
+ ms.current_range, line);
+ range_reg = bma_emul_get_reg(emul, BMA2x2_RANGE_SELECT_ADDR);
+ range_reg &= BMA2x2_RANGE_SELECT_MSK;
+
+ switch (exp_range) {
+ case 2:
+ exp_range_reg = BMA2x2_RANGE_2G;
+ break;
+ case 4:
+ exp_range_reg = BMA2x2_RANGE_4G;
+ break;
+ case 8:
+ exp_range_reg = BMA2x2_RANGE_8G;
+ break;
+ case 16:
+ exp_range_reg = BMA2x2_RANGE_16G;
+ break;
+ default:
+ /* Unknown expected range */
+ zassert_unreachable(
+ "Expected range %d not supported by device; line %d",
+ exp_range, line);
+ return;
+ }
+
+ zassert_equal(exp_range_reg, range_reg,
+ "Expected range reg 0x%x, got 0x%x; line %d",
+ exp_range_reg, range_reg, line);
+}
+#define check_set_range(emul, range, rnd, exp_range) \
+ check_set_range_f(emul, range, rnd, exp_range, __LINE__)
+
+/** Test set range with and without I2C errors. */
+ZTEST_USER(bma2x2, test_bma_set_range)
+{
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int start_range;
+
+ /* Setup starting range, shouldn't be changed on error */
+ start_range = 2;
+ ms.current_range = start_range;
+ bma_emul_set_reg(emul, BMA2x2_RANGE_SELECT_ADDR, BMA2x2_RANGE_2G);
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BMA2x2_RANGE_SELECT_ADDR);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_range(&ms, 12, 0), NULL);
+ zassert_equal(start_range, ms.current_range, NULL);
+ zassert_equal(BMA2x2_RANGE_2G,
+ bma_emul_get_reg(emul, BMA2x2_RANGE_SELECT_ADDR), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_range(&ms, 12, 1), NULL);
+ zassert_equal(start_range, ms.current_range, NULL);
+ zassert_equal(BMA2x2_RANGE_2G,
+ bma_emul_get_reg(emul, BMA2x2_RANGE_SELECT_ADDR), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMA2x2_RANGE_SELECT_ADDR);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_range(&ms, 12, 0), NULL);
+ zassert_equal(start_range, ms.current_range, NULL);
+ zassert_equal(BMA2x2_RANGE_2G,
+ bma_emul_get_reg(emul, BMA2x2_RANGE_SELECT_ADDR), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_range(&ms, 12, 1), NULL);
+ zassert_equal(start_range, ms.current_range, NULL);
+ zassert_equal(BMA2x2_RANGE_2G,
+ bma_emul_get_reg(emul, BMA2x2_RANGE_SELECT_ADDR), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting range with rounding down */
+ check_set_range(emul, 1, 0, 2);
+ check_set_range(emul, 2, 0, 2);
+ check_set_range(emul, 3, 0, 2);
+ check_set_range(emul, 4, 0, 4);
+ check_set_range(emul, 5, 0, 4);
+ check_set_range(emul, 6, 0, 4);
+ check_set_range(emul, 7, 0, 4);
+ check_set_range(emul, 8, 0, 8);
+ check_set_range(emul, 9, 0, 8);
+ check_set_range(emul, 15, 0, 8);
+ check_set_range(emul, 16, 0, 16);
+ check_set_range(emul, 17, 0, 16);
+
+ /* Test setting range with rounding up */
+ check_set_range(emul, 1, 1, 2);
+ check_set_range(emul, 2, 1, 2);
+ check_set_range(emul, 3, 1, 4);
+ check_set_range(emul, 4, 1, 4);
+ check_set_range(emul, 5, 1, 8);
+ check_set_range(emul, 6, 1, 8);
+ check_set_range(emul, 7, 1, 8);
+ check_set_range(emul, 8, 1, 8);
+ check_set_range(emul, 9, 1, 16);
+ check_set_range(emul, 15, 1, 16);
+ check_set_range(emul, 16, 1, 16);
+ check_set_range(emul, 17, 1, 16);
+}
+
+/** Test init with and without I2C errors. */
+ZTEST_USER(bma2x2, test_bma_init)
+{
+ struct reset_func_data reset_func_data;
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+
+ /* Setup emulator fail read function */
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_CHIP_ID_ADDR);
+
+ /* Test fail on chip id read */
+ zassert_equal(EC_ERROR_UNKNOWN, ms.drv->init(&ms), NULL);
+
+ /* Disable failing on chip id read, but set wrong value */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bma_emul_set_reg(emul, BMA2x2_CHIP_ID_ADDR, 23);
+
+ /* Test wrong chip id */
+ zassert_equal(EC_ERROR_ACCESS_DENIED, ms.drv->init(&ms), NULL);
+
+ /* Set correct chip id, but fail on reset reg read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_RST_ADDR);
+ bma_emul_set_reg(emul, BMA2x2_CHIP_ID_ADDR, BMA255_CHIP_ID_MAJOR);
+
+ /* Test fail on reset register read */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->init(&ms), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMA2x2_RST_ADDR);
+
+ /* Test fail on reset register write */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->init(&ms), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail reset read function */
+ reset_func_data.ok_before_fail = 1;
+ reset_func_data.fail_attempts = 100;
+ reset_func_data.reset_value = 0;
+ i2c_common_emul_set_read_func(common_data, emul_read_reset,
+ &reset_func_data);
+
+ /* Test fail on too many reset read errors */
+ zassert_equal(EC_ERROR_TIMEOUT, ms.drv->init(&ms), NULL);
+
+ /* Test success after reset read errors */
+ reset_func_data.ok_before_fail = 1;
+ reset_func_data.fail_attempts = 3;
+ zassert_equal(EC_RES_SUCCESS, ms.drv->init(&ms), NULL);
+
+ /* Test success without read errors */
+ reset_func_data.fail_attempts = 0;
+ zassert_equal(EC_RES_SUCCESS, ms.drv->init(&ms), NULL);
+
+ /* Test fail on too many reset read wrong value */
+ reset_func_data.fail_attempts = 0;
+ reset_func_data.reset_value = 100;
+ zassert_equal(EC_ERROR_TIMEOUT, ms.drv->init(&ms), NULL);
+
+ /* Test success on few reset read wrong value */
+ reset_func_data.fail_attempts = 0;
+ reset_func_data.reset_value = 4;
+ zassert_equal(EC_RES_SUCCESS, ms.drv->init(&ms), NULL);
+
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+/*
+ * Try to set data rate and check if expected rate was set in driver and in
+ * emulator.
+ */
+static void check_set_rate_f(const struct emul *emul, int rate, int rnd,
+ int exp_rate, int line)
+{
+ uint8_t exp_rate_reg;
+ uint8_t rate_reg;
+ int drv_rate;
+
+ zassert_equal(EC_SUCCESS, ms.drv->set_data_rate(&ms, rate, rnd),
+ "set_data_rate failed; line: %d", line);
+ drv_rate = ms.drv->get_data_rate(&ms);
+ zassert_equal(exp_rate, drv_rate, "Expected rate %d, got %d; line %d",
+ exp_rate, drv_rate, line);
+ rate_reg = bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR);
+ rate_reg &= BMA2x2_BW_MSK;
+
+ switch (exp_rate) {
+ case 7812:
+ exp_rate_reg = BMA2x2_BW_7_81HZ;
+ break;
+ case 15625:
+ exp_rate_reg = BMA2x2_BW_15_63HZ;
+ break;
+ case 31250:
+ exp_rate_reg = BMA2x2_BW_31_25HZ;
+ break;
+ case 62500:
+ exp_rate_reg = BMA2x2_BW_62_50HZ;
+ break;
+ case 125000:
+ exp_rate_reg = BMA2x2_BW_125HZ;
+ break;
+ case 250000:
+ exp_rate_reg = BMA2x2_BW_250HZ;
+ break;
+ case 500000:
+ exp_rate_reg = BMA2x2_BW_500HZ;
+ break;
+ case 1000000:
+ exp_rate_reg = BMA2x2_BW_1000HZ;
+ break;
+ default:
+ /* Unknown expected rate */
+ zassert_unreachable(
+ "Expected rate %d not supported by device; line %d",
+ exp_rate, line);
+ return;
+ }
+
+ zassert_equal(exp_rate_reg, rate_reg,
+ "Expected rate reg 0x%x, got 0x%x; line %d", exp_rate_reg,
+ rate_reg, line);
+}
+#define check_set_rate(emul, rate, rnd, exp_rate) \
+ check_set_rate_f(emul, rate, rnd, exp_rate, __LINE__)
+
+/** Test set and get rate with and without I2C errors. */
+ZTEST_USER(bma2x2, test_bma_rate)
+{
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ uint8_t reg_rate;
+ int drv_rate;
+
+ /* Test setting rate with rounding down */
+ check_set_rate(emul, 1, 0, 7812);
+ check_set_rate(emul, 1, 0, 7812);
+ check_set_rate(emul, 7811, 0, 7812);
+ check_set_rate(emul, 7812, 0, 7812);
+ check_set_rate(emul, 7813, 0, 7812);
+ check_set_rate(emul, 15624, 0, 7812);
+ check_set_rate(emul, 15625, 0, 15625);
+ check_set_rate(emul, 15626, 0, 15625);
+ check_set_rate(emul, 31249, 0, 15625);
+ check_set_rate(emul, 31250, 0, 31250);
+ check_set_rate(emul, 31251, 0, 31250);
+ check_set_rate(emul, 62499, 0, 31250);
+ check_set_rate(emul, 62500, 0, 62500);
+ check_set_rate(emul, 62501, 0, 62500);
+ check_set_rate(emul, 124999, 0, 62500);
+ check_set_rate(emul, 125000, 0, 125000);
+ check_set_rate(emul, 125001, 0, 125000);
+ check_set_rate(emul, 249999, 0, 125000);
+ check_set_rate(emul, 250000, 0, 250000);
+ check_set_rate(emul, 250001, 0, 250000);
+ check_set_rate(emul, 499999, 0, 250000);
+ check_set_rate(emul, 500000, 0, 500000);
+ check_set_rate(emul, 500001, 0, 500000);
+ check_set_rate(emul, 999999, 0, 500000);
+ check_set_rate(emul, 1000000, 0, 1000000);
+ check_set_rate(emul, 1000001, 0, 1000000);
+ check_set_rate(emul, 2000000, 0, 1000000);
+
+ /* Test setting rate with rounding up */
+ check_set_rate(emul, 1, 1, 7812);
+ check_set_rate(emul, 1, 1, 7812);
+ check_set_rate(emul, 7811, 1, 7812);
+ check_set_rate(emul, 7812, 1, 7812);
+ check_set_rate(emul, 7813, 1, 15625);
+ check_set_rate(emul, 15624, 1, 15625);
+ check_set_rate(emul, 15625, 1, 15625);
+ check_set_rate(emul, 15626, 1, 31250);
+ check_set_rate(emul, 31249, 1, 31250);
+ check_set_rate(emul, 31250, 1, 31250);
+ check_set_rate(emul, 31251, 1, 62500);
+ check_set_rate(emul, 62499, 1, 62500);
+ check_set_rate(emul, 62500, 1, 62500);
+ check_set_rate(emul, 62501, 1, 125000);
+ check_set_rate(emul, 124999, 1, 125000);
+ check_set_rate(emul, 125000, 1, 125000);
+ check_set_rate(emul, 125001, 1, 250000);
+ check_set_rate(emul, 249999, 1, 250000);
+ check_set_rate(emul, 250000, 1, 250000);
+ check_set_rate(emul, 250001, 1, 500000);
+ check_set_rate(emul, 499999, 1, 500000);
+ check_set_rate(emul, 500000, 1, 500000);
+ check_set_rate(emul, 500001, 1, 1000000);
+ check_set_rate(emul, 999999, 1, 1000000);
+ check_set_rate(emul, 1000000, 1, 1000000);
+ check_set_rate(emul, 1000001, 1, 1000000);
+ check_set_rate(emul, 2000000, 1, 1000000);
+
+ /* Current rate shouldn't be changed on error */
+ drv_rate = ms.drv->get_data_rate(&ms);
+ reg_rate = bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR);
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_BW_SELECT_ADDR);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_data_rate(&ms, 15625, 0),
+ NULL);
+ zassert_equal(drv_rate, ms.drv->get_data_rate(&ms), NULL);
+ zassert_equal(reg_rate, bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_data_rate(&ms, 15625, 1),
+ NULL);
+ zassert_equal(drv_rate, ms.drv->get_data_rate(&ms), NULL);
+ zassert_equal(reg_rate, bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR),
+ NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMA2x2_BW_SELECT_ADDR);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_data_rate(&ms, 15625, 0),
+ NULL);
+ zassert_equal(drv_rate, ms.drv->get_data_rate(&ms), NULL);
+ zassert_equal(reg_rate, bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->set_data_rate(&ms, 15625, 1),
+ NULL);
+ zassert_equal(drv_rate, ms.drv->get_data_rate(&ms), NULL);
+ zassert_equal(reg_rate, bma_emul_get_reg(emul, BMA2x2_BW_SELECT_ADDR),
+ NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+/** Test read with and without I2C errors. */
+ZTEST_USER(bma2x2, test_bma_read)
+{
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int16_t ret_acc[3];
+ int16_t exp_acc[3];
+ intv3_t ret_acc_v;
+
+ /* Set offset 0 to simplify test */
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_X, 0);
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_Y, 0);
+ bma_emul_set_off(emul, BMA_EMUL_AXIS_Z, 0);
+
+ /* Test fail on each axis */
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_X_AXIS_LSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_X_AXIS_MSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_Y_AXIS_LSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_Y_AXIS_MSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_Z_AXIS_LSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMA2x2_Z_AXIS_MSB_ADDR);
+ zassert_equal(EC_ERROR_INVAL, ms.drv->read(&ms, ret_acc_v), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set input accelerometer values */
+ exp_acc[0] = BMA_EMUL_1G / 10;
+ exp_acc[1] = BMA_EMUL_1G / 20;
+ exp_acc[2] = -(int)BMA_EMUL_1G / 30;
+ set_emul_acc(emul, exp_acc);
+ /* Disable rotation */
+ ms.rot_standard_ref = NULL;
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, 2, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->read(&ms, ret_acc_v), NULL);
+ drv_acc_to_emul(ret_acc_v, 2, ret_acc);
+ compare_int3v(exp_acc, ret_acc);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, 4, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->read(&ms, ret_acc_v), NULL);
+ drv_acc_to_emul(ret_acc_v, 4, ret_acc);
+ compare_int3v(exp_acc, ret_acc);
+
+ /* Setup rotation and rotate expected vector */
+ ms.rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_acc);
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, 2, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->read(&ms, ret_acc_v), NULL);
+ drv_acc_to_emul(ret_acc_v, 2, ret_acc);
+ compare_int3v(exp_acc, ret_acc);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, 4, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->read(&ms, ret_acc_v), NULL);
+ drv_acc_to_emul(ret_acc_v, 4, ret_acc);
+ compare_int3v(exp_acc, ret_acc);
+}
+
+/** Data for functions used in perform_calib test */
+struct calib_func_data {
+ /** Time when offset compensation where triggered */
+ int calib_start;
+ /** Time how long offset cal ready should be unset */
+ int time;
+ /** Flag indicate if read should fail after compensation is triggered */
+ int read_fail;
+};
+
+/**
+ * Custom emulator read function used in perform_calib test. It controls if
+ * cal ready bit in offset control register should be set. It is set after
+ * data.time miliseconds passed from data.calib_start time. Function returns
+ * error when offset control register is accessed when cal ready bit is not set
+ * and data.read_fail is not zero.
+ */
+static int emul_read_calib_func(const struct emul *emul, int reg, uint8_t *val,
+ int bytes, void *data)
+{
+ struct calib_func_data *d = data;
+ uint8_t reg_val;
+ int cur_time;
+
+ reg = bma_emul_access_reg(emul, reg, bytes, true /* = read */);
+ if (reg != BMA2x2_OFFSET_CTRL_ADDR) {
+ return 1;
+ }
+
+ reg_val = bma_emul_get_reg(emul, BMA2x2_OFFSET_CTRL_ADDR);
+ cur_time = k_uptime_get_32();
+ if (cur_time - d->calib_start < d->time) {
+ if (d->read_fail) {
+ return -EIO;
+ }
+ reg_val &= ~BMA2x2_OFFSET_CAL_READY;
+ } else {
+ reg_val |= BMA2x2_OFFSET_CAL_READY;
+ }
+ bma_emul_set_reg(emul, BMA2x2_OFFSET_CTRL_ADDR, reg_val);
+
+ return 1;
+}
+
+/**
+ * Custom emulator write function used in perform_calib test. It sets
+ * calib_start field in data with time when offset compensation process was
+ * triggerd.
+ */
+static int emul_write_calib_func(const struct emul *emul, int reg, uint8_t val,
+ int bytes, void *data)
+{
+ struct calib_func_data *d = data;
+
+ reg = bma_emul_access_reg(emul, reg, bytes, false /* = read */);
+ if (reg != BMA2x2_OFFSET_CTRL_ADDR) {
+ return 1;
+ }
+
+ if (val & BMA2x2_OFFSET_TRIGGER_MASK) {
+ d->calib_start = k_uptime_get_32();
+ }
+
+ return 1;
+}
+
+/** Test offset compensation with and without I2C errors. */
+ZTEST_USER(bma2x2, test_bma_perform_calib)
+{
+ struct calib_func_data func_data;
+ const struct emul *emul = EMUL_DT_GET(BMA_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int16_t start_off[3];
+ int16_t exp_off[3];
+ int16_t ret_off[3];
+ int range;
+ int rate;
+ mat33_fp_t rot = { { FLOAT_TO_FP(1), 0, 0 },
+ { 0, FLOAT_TO_FP(1), 0 },
+ { 0, 0, FLOAT_TO_FP(-1) } };
+
+ /* Range and rate cannot change after calibration */
+ range = 4;
+ rate = 125000;
+ zassert_equal(EC_SUCCESS, ms.drv->set_range(&ms, range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms.drv->set_data_rate(&ms, rate, 0), NULL);
+
+ /* Set offset 0 */
+ start_off[0] = 0;
+ start_off[1] = 0;
+ start_off[2] = 0;
+ set_emul_offset(emul, start_off);
+
+ /* Set input accelerometer values */
+ exp_off[0] = BMA_EMUL_1G / 10;
+ exp_off[1] = BMA_EMUL_1G / 20;
+ exp_off[2] = -(int)BMA_EMUL_1G / 30;
+ set_emul_acc(emul, exp_off);
+
+ /*
+ * Expected offset is [-X, -Y, 1G - Z] for no rotation or positive
+ * rotation on Z axis
+ */
+ exp_off[0] = -exp_off[0];
+ exp_off[1] = -exp_off[1];
+ exp_off[2] = BMA_EMUL_1G - exp_off[2];
+
+ /* Setup emulator calibration functions */
+ i2c_common_emul_set_read_func(common_data, emul_read_calib_func,
+ &func_data);
+ i2c_common_emul_set_write_func(common_data, emul_write_calib_func,
+ &func_data);
+
+ /* Setup emulator to fail on first access to offset control register */
+ func_data.calib_start = k_uptime_get_32();
+ func_data.read_fail = 1;
+ func_data.time = 1000000;
+
+ /* Test success on disabling calibration */
+ zassert_equal(EC_SUCCESS, ms.drv->perform_calib(&ms, 0), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+
+ /* Test fail on first access to offset control register */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+
+ /* Setup emulator to return cal not ready */
+ func_data.calib_start = k_uptime_get_32();
+ func_data.read_fail = 0;
+ func_data.time = 1000000;
+
+ /* Test fail on cal not ready */
+ zassert_equal(EC_ERROR_ACCESS_DENIED, ms.drv->perform_calib(&ms, 1),
+ NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+
+ /*
+ * Setup emulator to fail on access to offset control register after
+ * triggering offset compensation
+ */
+ func_data.calib_start = 0;
+ func_data.read_fail = 1;
+ func_data.time = 160;
+
+ /* Test fail on read during offset compensation */
+ zassert_equal(EC_ERROR_INVAL, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+
+ /*
+ * Setup emulator to return cal not ready for 1s after triggering
+ * offset compensation
+ */
+ func_data.calib_start = 0;
+ func_data.read_fail = 0;
+ func_data.time = 1000;
+
+ zassert_equal(EC_RES_TIMEOUT, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+
+ /*
+ * Setup emulator to return cal not ready for 160ms after triggering
+ * offset compensation
+ */
+ func_data.calib_start = 0;
+ func_data.read_fail = 0;
+ func_data.time = 160;
+ /* Disable rotation */
+ ms.rot_standard_ref = NULL;
+
+ /* Test successful offset compenastion without rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+ get_emul_offset(emul, ret_off);
+ compare_int3v(exp_off, ret_off);
+
+ func_data.calib_start = 0;
+ /* Enable rotation with negative value on Z axis */
+ ms.rot_standard_ref = &rot;
+ /* Expected offset -1G - accelerometer[Z] */
+ exp_off[2] =
+ -((int)BMA_EMUL_1G) - bma_emul_get_acc(emul, BMA_EMUL_AXIS_Z);
+
+ /* Test successful offset compenastion with negative Z rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+ get_emul_offset(emul, ret_off);
+ compare_int3v(exp_off, ret_off);
+
+ func_data.calib_start = 0;
+ /* Set positive rotation on Z axis */
+ rot[2][2] = FLOAT_TO_FP(1);
+ /* Expected offset 1G - accelerometer[Z] */
+ exp_off[2] = BMA_EMUL_1G - bma_emul_get_acc(emul, BMA_EMUL_AXIS_Z);
+
+ /* Test successful offset compenastion with positive Z rotation */
+ zassert_equal(EC_SUCCESS, ms.drv->perform_calib(&ms, 1), NULL);
+ zassert_equal(range, ms.current_range, NULL);
+ zassert_equal(rate, ms.drv->get_data_rate(&ms), NULL);
+ get_emul_offset(emul, ret_off);
+ compare_int3v(exp_off, ret_off);
+
+ /* Remove custom emulator functions */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+/** Test get resolution. */
+ZTEST_USER(bma2x2, test_bma_get_resolution)
+{
+ /* Resolution should be always 12 bits */
+ zassert_equal(12, ms.drv->get_resolution(&ms), NULL);
+}
+
+static void *bma2x2_setup(void)
+{
+ k_mutex_init(&sensor_mutex);
+
+ return NULL;
+}
+
+static void bma2x2_after(void *data)
+{
+ ms.rot_standard_ref = NULL;
+}
+
+ZTEST_SUITE(bma2x2, drivers_predicate_post_main, bma2x2_setup, NULL,
+ bma2x2_after, NULL);
diff --git a/zephyr/test/drivers/default/src/bmi160.c b/zephyr/test/drivers/default/src/bmi160.c
new file mode 100644
index 0000000000..3f06e7f0fd
--- /dev/null
+++ b/zephyr/test/drivers/default/src/bmi160.c
@@ -0,0 +1,2188 @@
+/* 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 "common.h"
+#include "i2c.h"
+#include "emul/emul_bmi.h"
+#include "emul/emul_common_i2c.h"
+#include "test/drivers/test_mocks.h"
+
+#include "motion_sense_fifo.h"
+#include "driver/accelgyro_bmi160.h"
+#include "driver/accelgyro_bmi_common.h"
+#include "test/drivers/test_state.h"
+
+#define BMI_NODE DT_NODELABEL(accel_bmi160)
+#define BMI_ACC_SENSOR_ID SENSOR_ID(DT_NODELABEL(ms_bmi160_accel))
+#define BMI_GYR_SENSOR_ID SENSOR_ID(DT_NODELABEL(ms_bmi160_gyro))
+#define BMI_INT_EVENT \
+ TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(bmi160_int)))
+
+/** How accurate comparision of vectors should be */
+#define V_EPS 8
+
+/** Convert from one type of vector to another */
+#define convert_int3v_int16(v, r) \
+ do { \
+ r[0] = v[0]; \
+ r[1] = v[1]; \
+ r[2] = v[2]; \
+ } while (0)
+
+/** Rotation used in some tests */
+static const mat33_fp_t test_rotation = { { 0, FLOAT_TO_FP(1), 0 },
+ { FLOAT_TO_FP(-1), 0, 0 },
+ { 0, 0, FLOAT_TO_FP(-1) } };
+/** Rotate given vector by test rotation */
+static void rotate_int3v_by_test_rotation(intv3_t v)
+{
+ int16_t t;
+
+ t = v[0];
+ v[0] = -v[1];
+ v[1] = t;
+ v[2] = -v[2];
+}
+
+/** Set emulator accelerometer offset values to intv3_t vector */
+static void set_emul_acc_offset(const struct emul *emul, intv3_t offset)
+{
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_X, offset[0]);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Y, offset[1]);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Z, offset[2]);
+}
+
+/** Save emulator accelerometer offset values to intv3_t vector */
+static void get_emul_acc_offset(const struct emul *emul, intv3_t offset)
+{
+ offset[0] = bmi_emul_get_off(emul, BMI_EMUL_ACC_X);
+ offset[1] = bmi_emul_get_off(emul, BMI_EMUL_ACC_Y);
+ offset[2] = bmi_emul_get_off(emul, BMI_EMUL_ACC_Z);
+}
+
+/** Set emulator accelerometer values to intv3_t vector */
+static void set_emul_acc(const struct emul *emul, intv3_t acc)
+{
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_X, acc[0]);
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Y, acc[1]);
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Z, acc[2]);
+}
+
+/** Set emulator gyroscope offset values to intv3_t vector */
+static void set_emul_gyr_offset(const struct emul *emul, intv3_t offset)
+{
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_X, offset[0]);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Y, offset[1]);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Z, offset[2]);
+}
+
+/** Save emulator gyroscope offset values to intv3_t vector */
+static void get_emul_gyr_offset(const struct emul *emul, intv3_t offset)
+{
+ offset[0] = bmi_emul_get_off(emul, BMI_EMUL_GYR_X);
+ offset[1] = bmi_emul_get_off(emul, BMI_EMUL_GYR_Y);
+ offset[2] = bmi_emul_get_off(emul, BMI_EMUL_GYR_Z);
+}
+
+/** Set emulator gyroscope values to vector of three int16_t */
+static void set_emul_gyr(const struct emul *emul, intv3_t gyr)
+{
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_X, gyr[0]);
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_Y, gyr[1]);
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_Z, gyr[2]);
+}
+
+/** Convert accelerometer read to units used by emulator */
+static void drv_acc_to_emul(intv3_t drv, int range, intv3_t out)
+{
+ const int scale = MOTION_SCALING_FACTOR / BMI_EMUL_1G;
+
+ out[0] = drv[0] * range / scale;
+ out[1] = drv[1] * range / scale;
+ out[2] = drv[2] * range / scale;
+}
+
+/** Convert gyroscope read to units used by emulator */
+static void drv_gyr_to_emul(intv3_t drv, int range, intv3_t out)
+{
+ const int scale = MOTION_SCALING_FACTOR / BMI_EMUL_125_DEG_S;
+
+ range /= 125;
+ out[0] = drv[0] * range / scale;
+ out[1] = drv[1] * range / scale;
+ out[2] = drv[2] * range / scale;
+}
+
+/** Compare two vectors of intv3_t type */
+static void compare_int3v_f(intv3_t exp_v, intv3_t v, int eps, int line)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ zassert_within(
+ exp_v[i], v[i], eps,
+ "Expected [%d; %d; %d], got [%d; %d; %d]; line: %d",
+ exp_v[0], exp_v[1], exp_v[2], v[0], v[1], v[2], line);
+ }
+}
+#define compare_int3v_eps(exp_v, v, e) compare_int3v_f(exp_v, v, e, __LINE__)
+#define compare_int3v(exp_v, v) compare_int3v_eps(exp_v, v, V_EPS)
+
+/** Test get accelerometer offset with and without rotation */
+ZTEST_USER(bmi160, test_bmi_acc_get_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int16_t ret[3];
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t temp;
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Set emulator offset */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ set_emul_acc_offset(emul, exp_v);
+ /* BMI driver returns value in mg units */
+ exp_v[0] = 1000 / 10;
+ exp_v[1] = 1000 / 20;
+ exp_v[2] = -1000 / 30;
+
+ /* Test fail on offset read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test get offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected offset */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+
+ /* Test get offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v(exp_v, ret_v);
+}
+
+/** Test get gyroscope offset with and without rotation */
+ZTEST_USER(bmi160, test_bmi_gyr_get_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int16_t ret[3];
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t temp;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set emulator offset */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ set_emul_gyr_offset(emul, exp_v);
+ /* BMI driver returns value in mdeg/s units */
+ exp_v[0] = 125000 / 100;
+ exp_v[1] = 125000 / 200;
+ exp_v[2] = -125000 / 300;
+
+ /* Test fail on offset read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test get offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+
+ /* Setup rotation and rotate expected offset */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+
+ /* Test get offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+}
+
+/**
+ * Test set accelerometer offset with and without rotation. Also test behaviour
+ * on I2C error.
+ */
+ZTEST_USER(bmi160, test_bmi_acc_set_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int16_t input_v[3];
+ int16_t temp = 0;
+ intv3_t ret_v;
+ intv3_t exp_v;
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Test fail on OFFSET EN GYR98 register read and write */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on offset write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_OFFSET_ACC70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_ACC70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_ACC70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set input offset */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ /* BMI driver accept value in mg units */
+ input_v[0] = 1000 / 10;
+ input_v[1] = 1000 / 20;
+ input_v[2] = -1000 / 30;
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test set offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_acc_offset(emul, ret_v);
+ /*
+ * Depending on used range, accelerometer values may be up to 6 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_v, ret_v, 64);
+ /* Accelerometer offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_ACC_EN,
+ NULL);
+
+ /* Setup rotation and rotate input for set_offset function */
+ ms->rot_standard_ref = &test_rotation;
+ convert_int3v_int16(input_v, ret_v);
+ rotate_int3v_by_test_rotation(ret_v);
+ convert_int3v_int16(ret_v, input_v);
+
+ /* Test set offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_acc_offset(emul, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+ /* Accelerometer offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_ACC_EN,
+ NULL);
+}
+
+/**
+ * Test set gyroscope offset with and without rotation. Also test behaviour
+ * on I2C error.
+ */
+ZTEST_USER(bmi160, test_bmi_gyr_set_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int16_t input_v[3];
+ int16_t temp = 0;
+ intv3_t ret_v;
+ intv3_t exp_v;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Test fail on OFFSET EN GYR98 register read and write */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on offset write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_OFFSET_GYR70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_GYR70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_GYR70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set input offset */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ /* BMI driver accept value in mdeg/s units */
+ input_v[0] = 125000 / 100;
+ input_v[1] = 125000 / 200;
+ input_v[2] = -125000 / 300;
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test set offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_gyr_offset(emul, ret_v);
+ compare_int3v(exp_v, ret_v);
+ /* Gyroscope offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_GYRO_EN,
+ NULL);
+
+ /* Setup rotation and rotate input for set_offset function */
+ ms->rot_standard_ref = &test_rotation;
+ convert_int3v_int16(input_v, ret_v);
+ rotate_int3v_by_test_rotation(ret_v);
+ convert_int3v_int16(ret_v, input_v);
+
+ /* Test set offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_gyr_offset(emul, ret_v);
+ compare_int3v(exp_v, ret_v);
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_GYRO_EN,
+ NULL);
+}
+
+/**
+ * Try to set accelerometer range and check if expected range was set
+ * in driver and in emulator.
+ */
+static void check_set_acc_range_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int range,
+ int rnd, int exp_range, int line)
+{
+ uint8_t exp_range_reg;
+ uint8_t range_reg;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, rnd),
+ "set_range failed; line: %d", line);
+ zassert_equal(exp_range, ms->current_range,
+ "Expected range %d, got %d; line %d", exp_range,
+ ms->current_range, line);
+ range_reg = bmi_emul_get_reg(emul, BMI160_ACC_RANGE);
+
+ switch (exp_range) {
+ case 2:
+ exp_range_reg = BMI160_GSEL_2G;
+ break;
+ case 4:
+ exp_range_reg = BMI160_GSEL_4G;
+ break;
+ case 8:
+ exp_range_reg = BMI160_GSEL_8G;
+ break;
+ case 16:
+ exp_range_reg = BMI160_GSEL_16G;
+ break;
+ default:
+ /* Unknown expected range */
+ zassert_unreachable(
+ "Expected range %d not supported by device; line %d",
+ exp_range, line);
+ return;
+ }
+
+ zassert_equal(exp_range_reg, range_reg,
+ "Expected range reg 0x%x, got 0x%x; line %d",
+ exp_range_reg, range_reg, line);
+}
+#define check_set_acc_range(emul, ms, range, rnd, exp_range) \
+ check_set_acc_range_f(emul, ms, range, rnd, exp_range, __LINE__)
+
+/** Test set accelerometer range with and without I2C errors */
+ZTEST_USER(bmi160, test_bmi_acc_set_range)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int start_range;
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Setup starting range, shouldn't be changed on error */
+ start_range = 2;
+ ms->current_range = start_range;
+ bmi_emul_set_reg(emul, BMI160_ACC_RANGE, BMI160_GSEL_2G);
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_ACC_RANGE);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 12, 0), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI160_GSEL_2G, bmi_emul_get_reg(emul, BMI160_ACC_RANGE),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 12, 1), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI160_GSEL_2G, bmi_emul_get_reg(emul, BMI160_ACC_RANGE),
+ NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting range with rounding down */
+ check_set_acc_range(emul, ms, 1, 0, 2);
+ check_set_acc_range(emul, ms, 2, 0, 2);
+ check_set_acc_range(emul, ms, 3, 0, 2);
+ check_set_acc_range(emul, ms, 4, 0, 4);
+ check_set_acc_range(emul, ms, 5, 0, 4);
+ check_set_acc_range(emul, ms, 6, 0, 4);
+ check_set_acc_range(emul, ms, 7, 0, 4);
+ check_set_acc_range(emul, ms, 8, 0, 8);
+ check_set_acc_range(emul, ms, 9, 0, 8);
+ check_set_acc_range(emul, ms, 15, 0, 8);
+ check_set_acc_range(emul, ms, 16, 0, 16);
+ check_set_acc_range(emul, ms, 17, 0, 16);
+
+ /* Test setting range with rounding up */
+ check_set_acc_range(emul, ms, 1, 1, 2);
+ check_set_acc_range(emul, ms, 2, 1, 2);
+ check_set_acc_range(emul, ms, 3, 1, 4);
+ check_set_acc_range(emul, ms, 4, 1, 4);
+ check_set_acc_range(emul, ms, 5, 1, 8);
+ check_set_acc_range(emul, ms, 6, 1, 8);
+ check_set_acc_range(emul, ms, 7, 1, 8);
+ check_set_acc_range(emul, ms, 8, 1, 8);
+ check_set_acc_range(emul, ms, 9, 1, 16);
+ check_set_acc_range(emul, ms, 15, 1, 16);
+ check_set_acc_range(emul, ms, 16, 1, 16);
+ check_set_acc_range(emul, ms, 17, 1, 16);
+}
+
+/**
+ * Try to set gyroscope range and check if expected range was set in driver and
+ * in emulator.
+ */
+static void check_set_gyr_range_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int range,
+ int rnd, int exp_range, int line)
+{
+ uint8_t exp_range_reg;
+ uint8_t range_reg;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, rnd),
+ "set_range failed; line: %d", line);
+ zassert_equal(exp_range, ms->current_range,
+ "Expected range %d, got %d; line %d", exp_range,
+ ms->current_range, line);
+ range_reg = bmi_emul_get_reg(emul, BMI160_GYR_RANGE);
+
+ switch (exp_range) {
+ case 125:
+ exp_range_reg = BMI160_DPS_SEL_125;
+ break;
+ case 250:
+ exp_range_reg = BMI160_DPS_SEL_250;
+ break;
+ case 500:
+ exp_range_reg = BMI160_DPS_SEL_500;
+ break;
+ case 1000:
+ exp_range_reg = BMI160_DPS_SEL_1000;
+ break;
+ case 2000:
+ exp_range_reg = BMI160_DPS_SEL_2000;
+ break;
+ default:
+ /* Unknown expected range */
+ zassert_unreachable(
+ "Expected range %d not supported by device; line %d",
+ exp_range, line);
+ return;
+ }
+
+ zassert_equal(exp_range_reg, range_reg,
+ "Expected range reg 0x%x, got 0x%x; line %d",
+ exp_range_reg, range_reg, line);
+}
+#define check_set_gyr_range(emul, ms, range, rnd, exp_range) \
+ check_set_gyr_range_f(emul, ms, range, rnd, exp_range, __LINE__)
+
+/** Test set gyroscope range with and without I2C errors */
+ZTEST_USER(bmi160, test_bmi_gyr_set_range)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int start_range;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Setup starting range, shouldn't be changed on error */
+ start_range = 250;
+ ms->current_range = start_range;
+ bmi_emul_set_reg(emul, BMI160_GYR_RANGE, BMI160_DPS_SEL_250);
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_GYR_RANGE);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 125, 0), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI160_DPS_SEL_250,
+ bmi_emul_get_reg(emul, BMI160_GYR_RANGE), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 125, 1), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI160_DPS_SEL_250,
+ bmi_emul_get_reg(emul, BMI160_GYR_RANGE), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting range with rounding down */
+ check_set_gyr_range(emul, ms, 1, 0, 125);
+ check_set_gyr_range(emul, ms, 124, 0, 125);
+ check_set_gyr_range(emul, ms, 125, 0, 125);
+ check_set_gyr_range(emul, ms, 126, 0, 125);
+ check_set_gyr_range(emul, ms, 249, 0, 125);
+ check_set_gyr_range(emul, ms, 250, 0, 250);
+ check_set_gyr_range(emul, ms, 251, 0, 250);
+ check_set_gyr_range(emul, ms, 499, 0, 250);
+ check_set_gyr_range(emul, ms, 500, 0, 500);
+ check_set_gyr_range(emul, ms, 501, 0, 500);
+ check_set_gyr_range(emul, ms, 999, 0, 500);
+ check_set_gyr_range(emul, ms, 1000, 0, 1000);
+ check_set_gyr_range(emul, ms, 1001, 0, 1000);
+ check_set_gyr_range(emul, ms, 1999, 0, 1000);
+ check_set_gyr_range(emul, ms, 2000, 0, 2000);
+ check_set_gyr_range(emul, ms, 2001, 0, 2000);
+
+ /* Test setting range with rounding up */
+ check_set_gyr_range(emul, ms, 1, 1, 125);
+ check_set_gyr_range(emul, ms, 124, 1, 125);
+ check_set_gyr_range(emul, ms, 125, 1, 125);
+ check_set_gyr_range(emul, ms, 126, 1, 250);
+ check_set_gyr_range(emul, ms, 249, 1, 250);
+ check_set_gyr_range(emul, ms, 250, 1, 250);
+ check_set_gyr_range(emul, ms, 251, 1, 500);
+ check_set_gyr_range(emul, ms, 499, 1, 500);
+ check_set_gyr_range(emul, ms, 500, 1, 500);
+ check_set_gyr_range(emul, ms, 501, 1, 1000);
+ check_set_gyr_range(emul, ms, 999, 1, 1000);
+ check_set_gyr_range(emul, ms, 1000, 1, 1000);
+ check_set_gyr_range(emul, ms, 1001, 1, 2000);
+ check_set_gyr_range(emul, ms, 1999, 1, 2000);
+ check_set_gyr_range(emul, ms, 2000, 1, 2000);
+ check_set_gyr_range(emul, ms, 2001, 1, 2000);
+}
+
+/** Test get resolution of acclerometer and gyroscope sensor */
+ZTEST_USER(bmi160, test_bmi_get_resolution)
+{
+ struct motion_sensor_t *ms;
+
+ /* Test accelerometer */
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Resolution should be always 16 bits */
+ zassert_equal(16, ms->drv->get_resolution(ms), NULL);
+
+ /* Test gyroscope */
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Resolution should be always 16 bits */
+ zassert_equal(16, ms->drv->get_resolution(ms), NULL);
+}
+
+/**
+ * Try to set accelerometer data rate and check if expected rate was set
+ * in driver and in emulator.
+ */
+static void check_set_acc_rate_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int rate, int rnd,
+ int exp_rate, int line)
+{
+ uint8_t exp_rate_reg;
+ uint8_t rate_reg;
+ int drv_rate;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, rnd),
+ "set_data_rate failed; line: %d", line);
+ drv_rate = ms->drv->get_data_rate(ms);
+ zassert_equal(exp_rate, drv_rate, "Expected rate %d, got %d; line %d",
+ exp_rate, drv_rate, line);
+ rate_reg = bmi_emul_get_reg(emul, BMI160_ACC_CONF);
+ rate_reg &= BMI_ODR_MASK;
+
+ switch (exp_rate) {
+ case 12500:
+ exp_rate_reg = 0x5;
+ break;
+ case 25000:
+ exp_rate_reg = 0x6;
+ break;
+ case 50000:
+ exp_rate_reg = 0x7;
+ break;
+ case 100000:
+ exp_rate_reg = 0x8;
+ break;
+ case 200000:
+ exp_rate_reg = 0x9;
+ break;
+ case 400000:
+ exp_rate_reg = 0xa;
+ break;
+ case 800000:
+ exp_rate_reg = 0xb;
+ break;
+ case 1600000:
+ exp_rate_reg = 0xc;
+ break;
+ default:
+ /* Unknown expected rate */
+ zassert_unreachable(
+ "Expected rate %d not supported by device; line %d",
+ exp_rate, line);
+ return;
+ }
+
+ zassert_equal(exp_rate_reg, rate_reg,
+ "Expected rate reg 0x%x, got 0x%x; line %d", exp_rate_reg,
+ rate_reg, line);
+}
+#define check_set_acc_rate(emul, ms, rate, rnd, exp_rate) \
+ check_set_acc_rate_f(emul, ms, rate, rnd, exp_rate, __LINE__)
+
+/** Test set and get accelerometer rate with and without I2C errors */
+ZTEST_USER(bmi160, test_bmi_acc_rate)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ uint8_t reg_rate;
+ int pmu_status;
+ int drv_rate;
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Test setting rate with rounding down */
+ check_set_acc_rate(emul, ms, 12500, 0, 12500);
+ check_set_acc_rate(emul, ms, 12501, 0, 12500);
+ check_set_acc_rate(emul, ms, 24999, 0, 12500);
+ check_set_acc_rate(emul, ms, 25000, 0, 25000);
+ check_set_acc_rate(emul, ms, 25001, 0, 25000);
+ check_set_acc_rate(emul, ms, 49999, 0, 25000);
+ check_set_acc_rate(emul, ms, 50000, 0, 50000);
+ check_set_acc_rate(emul, ms, 50001, 0, 50000);
+ check_set_acc_rate(emul, ms, 99999, 0, 50000);
+ check_set_acc_rate(emul, ms, 100000, 0, 100000);
+ check_set_acc_rate(emul, ms, 100001, 0, 100000);
+ check_set_acc_rate(emul, ms, 199999, 0, 100000);
+ check_set_acc_rate(emul, ms, 200000, 0, 200000);
+ check_set_acc_rate(emul, ms, 200001, 0, 200000);
+ check_set_acc_rate(emul, ms, 399999, 0, 200000);
+ /*
+ * We cannot test frequencies from 400000 to 1600000 because
+ * CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ is set to 250000
+ */
+
+ /* Test setting rate with rounding up */
+ check_set_acc_rate(emul, ms, 6251, 1, 12500);
+ check_set_acc_rate(emul, ms, 12499, 1, 12500);
+ check_set_acc_rate(emul, ms, 12500, 1, 12500);
+ check_set_acc_rate(emul, ms, 12501, 1, 25000);
+ check_set_acc_rate(emul, ms, 24999, 1, 25000);
+ check_set_acc_rate(emul, ms, 25000, 1, 25000);
+ check_set_acc_rate(emul, ms, 25001, 1, 50000);
+ check_set_acc_rate(emul, ms, 49999, 1, 50000);
+ check_set_acc_rate(emul, ms, 50000, 1, 50000);
+ check_set_acc_rate(emul, ms, 50001, 1, 100000);
+ check_set_acc_rate(emul, ms, 99999, 1, 100000);
+ check_set_acc_rate(emul, ms, 100000, 1, 100000);
+ check_set_acc_rate(emul, ms, 100001, 1, 200000);
+ check_set_acc_rate(emul, ms, 199999, 1, 200000);
+ check_set_acc_rate(emul, ms, 200000, 1, 200000);
+
+ /* Test out of range rate with rounding down */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 0),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 12499, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 2000000, 0), NULL);
+
+ /* Test out of range rate with rounding up */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 6250, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 200001, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 2000000, 1), NULL);
+
+ /* Current rate shouldn't be changed on error */
+ drv_rate = ms->drv->get_data_rate(ms);
+ reg_rate = bmi_emul_get_reg(emul, BMI160_ACC_CONF);
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_CONF);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_ACC_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_ACC_CONF), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_ACC_CONF);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_ACC_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_ACC_CONF), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test disabling sensor */
+ pmu_status = BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET;
+ pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET;
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, pmu_status);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL);
+
+ bmi_read8(ms->port, ms->i2c_spi_addr_flags, BMI160_PMU_STATUS,
+ &pmu_status);
+ zassert_equal(BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET, pmu_status,
+ "Gyroscope should be still enabled");
+
+ /* Test enabling sensor */
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ bmi_read8(ms->port, ms->i2c_spi_addr_flags, BMI160_PMU_STATUS,
+ &pmu_status);
+ zassert_equal(BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET, pmu_status,
+ "Accelerometer should be enabled");
+}
+
+/**
+ * Try to set gyroscope data rate and check if expected rate was set
+ * in driver and in emulator.
+ */
+static void check_set_gyr_rate_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int rate, int rnd,
+ int exp_rate, int line)
+{
+ uint8_t exp_rate_reg;
+ uint8_t rate_reg;
+ int drv_rate;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, rnd),
+ "set_data_rate failed; line: %d", line);
+ drv_rate = ms->drv->get_data_rate(ms);
+ zassert_equal(exp_rate, drv_rate, "Expected rate %d, got %d; line %d",
+ exp_rate, drv_rate, line);
+ rate_reg = bmi_emul_get_reg(emul, BMI160_GYR_CONF);
+ rate_reg &= BMI_ODR_MASK;
+
+ switch (exp_rate) {
+ case 25000:
+ exp_rate_reg = 0x6;
+ break;
+ case 50000:
+ exp_rate_reg = 0x7;
+ break;
+ case 100000:
+ exp_rate_reg = 0x8;
+ break;
+ case 200000:
+ exp_rate_reg = 0x9;
+ break;
+ case 400000:
+ exp_rate_reg = 0xa;
+ break;
+ case 800000:
+ exp_rate_reg = 0xb;
+ break;
+ case 1600000:
+ exp_rate_reg = 0xc;
+ break;
+ case 3200000:
+ exp_rate_reg = 0xc;
+ break;
+ default:
+ /* Unknown expected rate */
+ zassert_unreachable(
+ "Expected rate %d not supported by device; line %d",
+ exp_rate, line);
+ return;
+ }
+
+ zassert_equal(exp_rate_reg, rate_reg,
+ "Expected rate reg 0x%x, got 0x%x; line %d", exp_rate_reg,
+ rate_reg, line);
+}
+#define check_set_gyr_rate(emul, ms, rate, rnd, exp_rate) \
+ check_set_gyr_rate_f(emul, ms, rate, rnd, exp_rate, __LINE__)
+
+/** Test set and get gyroscope rate with and without I2C errors */
+ZTEST_USER(bmi160, test_bmi_gyr_rate)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ uint8_t reg_rate;
+ int pmu_status;
+ int drv_rate;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Test setting rate with rounding down */
+ check_set_gyr_rate(emul, ms, 25000, 0, 25000);
+ check_set_gyr_rate(emul, ms, 25001, 0, 25000);
+ check_set_gyr_rate(emul, ms, 49999, 0, 25000);
+ check_set_gyr_rate(emul, ms, 50000, 0, 50000);
+ check_set_gyr_rate(emul, ms, 50001, 0, 50000);
+ check_set_gyr_rate(emul, ms, 99999, 0, 50000);
+ check_set_gyr_rate(emul, ms, 100000, 0, 100000);
+ check_set_gyr_rate(emul, ms, 100001, 0, 100000);
+ check_set_gyr_rate(emul, ms, 199999, 0, 100000);
+ check_set_gyr_rate(emul, ms, 200000, 0, 200000);
+ check_set_gyr_rate(emul, ms, 200001, 0, 200000);
+ check_set_gyr_rate(emul, ms, 399999, 0, 200000);
+ /*
+ * We cannot test frequencies from 400000 to 3200000 because
+ * CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ is set to 250000
+ */
+
+ /* Test setting rate with rounding up */
+ check_set_gyr_rate(emul, ms, 12501, 1, 25000);
+ check_set_gyr_rate(emul, ms, 24999, 1, 25000);
+ check_set_gyr_rate(emul, ms, 25000, 1, 25000);
+ check_set_gyr_rate(emul, ms, 25001, 1, 50000);
+ check_set_gyr_rate(emul, ms, 49999, 1, 50000);
+ check_set_gyr_rate(emul, ms, 50000, 1, 50000);
+ check_set_gyr_rate(emul, ms, 50001, 1, 100000);
+ check_set_gyr_rate(emul, ms, 99999, 1, 100000);
+ check_set_gyr_rate(emul, ms, 100000, 1, 100000);
+ check_set_gyr_rate(emul, ms, 100001, 1, 200000);
+ check_set_gyr_rate(emul, ms, 199999, 1, 200000);
+ check_set_gyr_rate(emul, ms, 200000, 1, 200000);
+
+ /* Test out of range rate with rounding down */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 0),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 24999, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 4000000, 0), NULL);
+
+ /* Test out of range rate with rounding up */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 12499, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 200001, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 4000000, 1), NULL);
+
+ /* Current rate shouldn't be changed on error */
+ drv_rate = ms->drv->get_data_rate(ms);
+ reg_rate = bmi_emul_get_reg(emul, BMI160_GYR_CONF);
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_CONF);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_GYR_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_GYR_CONF), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_GYR_CONF);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_GYR_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI160_GYR_CONF), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test disabling sensor */
+ pmu_status = BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET;
+ pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET;
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, pmu_status);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL);
+
+ bmi_read8(ms->port, ms->i2c_spi_addr_flags, BMI160_PMU_STATUS,
+ &pmu_status);
+ zassert_equal(BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET, pmu_status,
+ "Accelerometer should be still enabled");
+
+ /* Test enabling sensor */
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ bmi_read8(ms->port, ms->i2c_spi_addr_flags, BMI160_PMU_STATUS,
+ &pmu_status);
+ zassert_equal(BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET, pmu_status,
+ "Gyroscope should be enabled");
+}
+
+/**
+ * Test setting and getting scale in accelerometer and gyroscope sensors.
+ * Correct appling scale to results is checked in "read" test.
+ */
+ZTEST_USER(bmi160, test_bmi_scale)
+{
+ struct motion_sensor_t *ms;
+ int16_t ret_scale[3];
+ int16_t exp_scale[3] = { 100, 231, 421 };
+ int16_t t;
+
+ /* Test accelerometer */
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, exp_scale, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->get_scale(ms, ret_scale, &t), NULL);
+
+ zassert_equal(t, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ zassert_equal(exp_scale[0], ret_scale[0], NULL);
+ zassert_equal(exp_scale[1], ret_scale[1], NULL);
+ zassert_equal(exp_scale[2], ret_scale[2], NULL);
+
+ /* Test gyroscope */
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, exp_scale, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->get_scale(ms, ret_scale, &t), NULL);
+
+ zassert_equal(t, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ zassert_equal(exp_scale[0], ret_scale[0], NULL);
+ zassert_equal(exp_scale[1], ret_scale[1], NULL);
+ zassert_equal(exp_scale[2], ret_scale[2], NULL);
+}
+
+/** Test reading temperature using accelerometer and gyroscope sensors */
+ZTEST_USER(bmi160, test_bmi_read_temp)
+{
+ struct motion_sensor_t *ms_acc, *ms_gyr;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int ret_temp;
+ int exp_temp;
+
+ ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_TEMPERATURE_0);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_TEMPERATURE_1);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Fail on invalid temperature */
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, 0x80);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+
+ /*
+ * Test correct values. Both motion sensors should return the same
+ * temperature.
+ */
+ exp_temp = C_TO_K(23);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, 0x00);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(87);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, 0xff);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, 0x7f);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(-41);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, 0x01);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, 0x80);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(47);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, 0x30);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+}
+
+/** Test reading accelerometer sensor data */
+ZTEST_USER(bmi160, test_bmi_acc_read)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t scale[3] = { MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE };
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Set offset 0 to simplify test */
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_X, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Y, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Z, 0);
+
+ /* Fail on read status */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* When not ready, driver should return saved raw value */
+ exp_v[0] = 100;
+ exp_v[1] = 200;
+ exp_v[2] = 300;
+ ms->raw_xyz[0] = exp_v[0];
+ ms->raw_xyz[1] = exp_v[1];
+ ms->raw_xyz[2] = exp_v[2];
+
+ /* Status not ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status only GYR ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, BMI160_DRDY_GYR);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status ACC ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, BMI160_DRDY_ACC);
+
+ /* Set input accelerometer values */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ set_emul_acc(emul, exp_v);
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+ /* Set scale */
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, scale, 0), NULL);
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 2, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 2, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 4, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 4, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected vector */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 2, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 2, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 4, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 4, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Fail on read of data registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_X_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_Y_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_Y_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_Z_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_Z_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ ms->rot_standard_ref = NULL;
+}
+
+/** Test reading gyroscope sensor data */
+ZTEST_USER(bmi160, test_bmi_gyr_read)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t scale[3] = { MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE };
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Set offset 0 to simplify test */
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_X, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Y, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Z, 0);
+
+ /* Fail on read status */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* When not ready, driver should return saved raw value */
+ exp_v[0] = 100;
+ exp_v[1] = 200;
+ exp_v[2] = 300;
+ ms->raw_xyz[0] = exp_v[0];
+ ms->raw_xyz[1] = exp_v[1];
+ ms->raw_xyz[2] = exp_v[2];
+
+ /* Status not ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status only ACC ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, BMI160_DRDY_ACC);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status GYR ready */
+ bmi_emul_set_reg(emul, BMI160_STATUS, BMI160_DRDY_GYR);
+
+ /* Set input accelerometer values */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 10;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 20;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 30;
+ set_emul_gyr(emul, exp_v);
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+ /* Set scale */
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, scale, 0), NULL);
+ /* Set range to 125°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 125, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 125, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 1000°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 1000, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 1000, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected vector */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+ /* Set range to 125°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 125, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 125, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 1000°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 1000, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 1000, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Fail on read of data registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_X_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_Y_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_Y_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_Z_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_Z_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ ms->rot_standard_ref = NULL;
+}
+
+/**
+ * Custom emulatro read function which always return not ready STATUS register.
+ * Used in calibration test.
+ */
+static int emul_nrdy(const struct emul *emul, int reg, uint8_t *val, int byte,
+ void *data)
+{
+ if (reg == BMI160_STATUS) {
+ bmi_emul_set_reg(emul, BMI160_STATUS, 0);
+ *val = 0;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+/** Test acceleromtere calibration */
+ZTEST_USER(bmi160, test_bmi_acc_perform_calib)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ uint8_t pmu_status;
+ intv3_t start_off;
+ intv3_t exp_off;
+ intv3_t ret_off;
+ int range;
+ int rate;
+ mat33_fp_t rot = { { FLOAT_TO_FP(1), 0, 0 },
+ { 0, FLOAT_TO_FP(1), 0 },
+ { 0, 0, FLOAT_TO_FP(-1) } };
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Enable sensors */
+ pmu_status = BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET;
+ pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET;
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, pmu_status);
+
+ /* Range and rate cannot change after calibration */
+ range = 4;
+ rate = 50000;
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, 0), NULL);
+
+ /* Set offset 0 */
+ start_off[0] = 0;
+ start_off[1] = 0;
+ start_off[2] = 0;
+ set_emul_acc_offset(emul, start_off);
+
+ /* Set input accelerometer values */
+ exp_off[0] = BMI_EMUL_1G / 10;
+ exp_off[1] = BMI_EMUL_1G / 20;
+ exp_off[2] = BMI_EMUL_1G - (int)BMI_EMUL_1G / 30;
+ set_emul_acc(emul, exp_off);
+
+ /*
+ * Expected offset is [-X, -Y, 1G - Z] for no rotation or positive
+ * rotation on Z axis
+ */
+ exp_off[0] = -exp_off[0];
+ exp_off[1] = -exp_off[1];
+ exp_off[2] = BMI_EMUL_1G - exp_off[2];
+
+ /* Test fail on rate set */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_ACC_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on status read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ /* Stop fast offset compensation before next test */
+ bmi_emul_set_reg(emul, BMI160_CMD_REG, BMI160_CMD_NOOP);
+
+ /* Test fail on data not ready */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_read_func(common_data, emul_nrdy, NULL);
+ zassert_equal(EC_RES_TIMEOUT, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+ /* Stop fast offset compensation before next test */
+ bmi_emul_set_reg(emul, BMI160_CMD_REG, BMI160_CMD_NOOP);
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+ /* Test successful offset compenastion without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_acc_offset(emul, ret_off);
+ /*
+ * Depending on used range, accelerometer values may be up to 6 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_off, ret_off, 64);
+ /* Acelerometer offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_ACC_EN,
+ NULL);
+
+ /* Enable rotation with negative value on Z axis */
+ ms->rot_standard_ref = &rot;
+ /* Expected offset -1G - accelerometer[Z] */
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Z, -(int)BMI_EMUL_1G - 1234);
+ exp_off[2] = 1234;
+
+ /* Test successful offset compenastion with negative Z rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_acc_offset(emul, ret_off);
+ compare_int3v_eps(exp_off, ret_off, 64);
+ /* Acelerometer offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_ACC_EN,
+ NULL);
+
+ /* Set positive rotation on Z axis */
+ rot[2][2] = FLOAT_TO_FP(1);
+ /* Expected offset 1G - accelerometer[Z] */
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Z, BMI_EMUL_1G - 1234);
+ exp_off[2] = 1234;
+
+ /* Test successful offset compenastion with positive Z rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_acc_offset(emul, ret_off);
+ compare_int3v_eps(exp_off, ret_off, 64);
+ /* Acelerometer offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_ACC_EN,
+ NULL);
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+}
+
+/** Test gyroscope calibration */
+ZTEST_USER(bmi160, test_bmi_gyr_perform_calib)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ uint8_t pmu_status;
+ intv3_t start_off;
+ intv3_t exp_off;
+ intv3_t ret_off;
+ int range;
+ int rate;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Enable sensors */
+ pmu_status = BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET;
+ pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET;
+ bmi_emul_set_reg(emul, BMI160_PMU_STATUS, pmu_status);
+
+ /* Range and rate cannot change after calibration */
+ range = 250;
+ rate = 50000;
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, 0), NULL);
+
+ /* Set offset 0 */
+ start_off[0] = 0;
+ start_off[1] = 0;
+ start_off[2] = 0;
+ set_emul_gyr_offset(emul, start_off);
+
+ /* Set input accelerometer values */
+ exp_off[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_off[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_off[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ set_emul_gyr(emul, exp_off);
+
+ /* Expected offset is [-X, -Y, -Z] */
+ exp_off[0] = -exp_off[0];
+ exp_off[1] = -exp_off[1];
+ exp_off[2] = -exp_off[2];
+
+ /* Test success on disabling calibration */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on rate set */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_GYR_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on status read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ /* Stop fast offset compensation before next test */
+ bmi_emul_set_reg(emul, BMI160_CMD_REG, BMI160_CMD_NOOP);
+
+ /* Test fail on data not ready */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_read_func(common_data, emul_nrdy, NULL);
+ zassert_equal(EC_RES_TIMEOUT, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+ /* Stop fast offset compensation before next test */
+ bmi_emul_set_reg(emul, BMI160_CMD_REG, BMI160_CMD_NOOP);
+
+ /* Test successful offset compenastion */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_gyr_offset(emul, ret_off);
+ /*
+ * Depending on used range, gyroscope values may be up to 4 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_off, ret_off, 32);
+ /* Gyroscope offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI160_OFFSET_EN_GYR98) &
+ BMI160_OFFSET_GYRO_EN,
+ NULL);
+}
+
+/** Test init function of BMI160 accelerometer and gyroscope sensors */
+ZTEST_USER(bmi160, test_bmi_init)
+{
+ struct motion_sensor_t *ms_acc, *ms_gyr;
+
+ ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Test successful init */
+ zassert_equal(EC_RES_SUCCESS, ms_acc->drv->init(ms_acc), NULL);
+
+ zassert_equal(EC_RES_SUCCESS, ms_gyr->drv->init(ms_gyr), NULL);
+}
+
+/** Data for custom emulator read function used in FIFO test */
+struct fifo_func_data {
+ uint16_t interrupts;
+};
+
+/**
+ * Custom emulator read function used in FIFO test. It sets interrupt registers
+ * to value passed as additional data. It sets interrupt registers to 0 after
+ * access.
+ */
+static int emul_fifo_func(const struct emul *emul, int reg, uint8_t *val,
+ int byte, void *data)
+{
+ struct fifo_func_data *d = data;
+
+ if (reg + byte == BMI160_INT_STATUS_0) {
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_0,
+ d->interrupts & 0xff);
+ d->interrupts &= 0xff00;
+ } else if (reg + byte == BMI160_INT_STATUS_1) {
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_1,
+ (d->interrupts >> 8) & 0xff);
+ d->interrupts &= 0xff;
+ }
+
+ return 1;
+}
+
+/**
+ * Run irq handler on accelerometer sensor and check if committed data in FIFO
+ * match what was set in FIFO frames in emulator.
+ */
+static void check_fifo_f(struct motion_sensor_t *ms_acc,
+ struct motion_sensor_t *ms_gyr,
+ struct bmi_emul_frame *frame, int acc_range,
+ int gyr_range, int line)
+{
+ struct ec_response_motion_sensor_data vector;
+ struct bmi_emul_frame *f_acc, *f_gyr;
+ uint32_t event = BMI_INT_EVENT;
+ uint16_t size;
+ intv3_t exp_v;
+ intv3_t ret_v;
+
+ /* Find first frame of acc and gyr type */
+ f_acc = frame;
+ while (f_acc != NULL && !(f_acc->type & BMI_EMUL_FRAME_ACC)) {
+ f_acc = f_acc->next;
+ }
+
+ f_gyr = frame;
+ while (f_gyr != NULL && !(f_gyr->type & BMI_EMUL_FRAME_GYR)) {
+ f_gyr = f_gyr->next;
+ }
+
+ /* Read FIFO in driver */
+ zassert_equal(EC_SUCCESS, ms_acc->drv->irq_handler(ms_acc, &event),
+ "Failed to read FIFO in irq handler, line %d", line);
+
+ /* Read all data committed to FIFO */
+ while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) {
+ /* Ignore timestamp frames */
+ if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) {
+ continue;
+ }
+
+ /* Check acclerometer frames */
+ if (ms_acc - motion_sensors == vector.sensor_num) {
+ if (f_acc == NULL) {
+ zassert_unreachable(
+ "Not expected acclerometer data in FIFO, line %d",
+ line);
+ }
+
+ convert_int3v_int16(vector.data, ret_v);
+ drv_acc_to_emul(ret_v, acc_range, ret_v);
+ exp_v[0] = f_acc->acc_x;
+ exp_v[1] = f_acc->acc_y;
+ exp_v[2] = f_acc->acc_z;
+ compare_int3v_f(exp_v, ret_v, V_EPS, line);
+ f_acc = f_acc->next;
+ }
+
+ /* Check gyroscope frames */
+ if (ms_gyr - motion_sensors == vector.sensor_num) {
+ if (f_gyr == NULL) {
+ zassert_unreachable(
+ "Not expected gyroscope data in FIFO, line %d",
+ line);
+ }
+
+ convert_int3v_int16(vector.data, ret_v);
+ drv_gyr_to_emul(ret_v, gyr_range, ret_v);
+ exp_v[0] = f_gyr->gyr_x;
+ exp_v[1] = f_gyr->gyr_y;
+ exp_v[2] = f_gyr->gyr_z;
+ compare_int3v_f(exp_v, ret_v, V_EPS, line);
+ f_gyr = f_gyr->next;
+ }
+ }
+
+ /* Skip frames of different type at the end */
+ while (f_acc != NULL && !(f_acc->type & BMI_EMUL_FRAME_ACC)) {
+ f_acc = f_acc->next;
+ }
+
+ while (f_gyr != NULL && !(f_gyr->type & BMI_EMUL_FRAME_GYR)) {
+ f_gyr = f_gyr->next;
+ }
+
+ /* All frames are readed */
+ zassert_is_null(f_acc, "Not all accelerometer frames are read, line %d",
+ line);
+ zassert_is_null(f_gyr, "Not all gyroscope frames are read, line %d",
+ line);
+}
+#define check_fifo(ms_acc, ms_gyr, frame, acc_range, gyr_range) \
+ check_fifo_f(ms_acc, ms_gyr, frame, acc_range, gyr_range, __LINE__)
+
+/** Test irq handler of accelerometer sensor */
+ZTEST_USER(bmi160, test_bmi_acc_fifo)
+{
+ struct motion_sensor_t *ms, *ms_gyr;
+ struct fifo_func_data func_data;
+ struct bmi_emul_frame f[3];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int gyr_range = 125;
+ int acc_range = 2;
+ int event;
+
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* init bmi before test */
+ zassert_equal(EC_RES_SUCCESS, ms->drv->init(ms), NULL);
+ zassert_equal(EC_RES_SUCCESS, ms_gyr->drv->init(ms_gyr), NULL);
+
+ /* Need to be set to collect all data in FIFO */
+ ms->oversampling_ratio = 1;
+ ms_gyr->oversampling_ratio = 1;
+ /* Only BMI event should be handled */
+ event = 0x1234 & ~BMI_INT_EVENT;
+ zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event),
+ NULL);
+
+ event = BMI_INT_EVENT;
+
+ /* Test fail to read interrupt status registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_INT_STATUS_0);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_INT_STATUS_1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test no interrupt */
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_0, 0);
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_1, 0);
+
+ /* Enable sensor FIFO */
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, NULL, acc_range, gyr_range);
+
+ /* Set custom function for FIFO test */
+ i2c_common_emul_set_read_func(common_data, emul_fifo_func, &func_data);
+ /* Set range */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, acc_range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->set_range(ms_gyr, gyr_range, 0),
+ NULL);
+ /* Setup single accelerometer frame */
+ f[0].type = BMI_EMUL_FRAME_ACC;
+ f[0].acc_x = BMI_EMUL_1G / 10;
+ f[0].acc_y = BMI_EMUL_1G / 20;
+ f[0].acc_z = -(int)BMI_EMUL_1G / 30;
+ f[0].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second accelerometer frame */
+ f[1].type = BMI_EMUL_FRAME_ACC;
+ f[1].acc_x = -(int)BMI_EMUL_1G / 40;
+ f[1].acc_y = BMI_EMUL_1G / 50;
+ f[1].acc_z = BMI_EMUL_1G / 60;
+ f[0].next = &(f[1]);
+ f[1].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Enable sensor FIFO */
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->set_data_rate(ms_gyr, 50000, 0),
+ NULL);
+
+ /* Setup first gyroscope frame (after two accelerometer frames) */
+ f[2].type = BMI_EMUL_FRAME_GYR;
+ f[2].gyr_x = -(int)BMI_EMUL_125_DEG_S / 100;
+ f[2].gyr_y = BMI_EMUL_125_DEG_S / 200;
+ f[2].gyr_z = BMI_EMUL_125_DEG_S / 300;
+ f[1].next = &(f[2]);
+ f[2].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second accelerometer frame to by gyroscope frame too */
+ f[1].type |= BMI_EMUL_FRAME_GYR;
+ f[1].gyr_x = -(int)BMI_EMUL_125_DEG_S / 300;
+ f[1].gyr_y = BMI_EMUL_125_DEG_S / 400;
+ f[1].gyr_z = BMI_EMUL_125_DEG_S / 500;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Skip frame should be ignored by driver */
+ bmi_emul_set_skipped_frames(emul, 8);
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second frame as an config frame */
+ f[1].type = BMI_EMUL_FRAME_CONFIG;
+ /* Indicate that accelerometer range changed */
+ f[1].config = 0x1;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI160_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+/** Test irq handler of gyroscope sensor */
+ZTEST_USER(bmi160, test_bmi_gyr_fifo)
+{
+ struct motion_sensor_t *ms;
+ uint32_t event;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Interrupt shuldn't be triggered for gyroscope motion sense */
+ event = BMI_INT_EVENT;
+ zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event),
+ NULL);
+}
+
+/** Test reading from compass via `bmi160_sec_raw_read8()` */
+ZTEST_USER(bmi160, test_bmi_sec_raw_read8)
+{
+ struct motion_sensor_t *ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ uint8_t expected_read_value = 0xAA;
+ uint8_t requested_reg_addr = 0x55;
+ uint8_t actual_reg_addr;
+ int actual_read_value;
+ int ret;
+
+ bmi_emul_set_reg(emul, BMI160_MAG_I2C_READ_DATA, expected_read_value);
+
+ ret = bmi160_sec_raw_read8(ms->port, ms->i2c_spi_addr_flags,
+ requested_reg_addr, &actual_read_value);
+
+ /* Verify return value */
+ zassert_equal(ret, EC_RES_SUCCESS, "Expected return code %d but got %d",
+ EC_RES_SUCCESS, ret);
+
+ /* Verify the correct value was read */
+ zassert_equal(expected_read_value, actual_read_value,
+ "Read value $%02x but expected to read $%02x",
+ actual_read_value, expected_read_value);
+
+ /* Verify the intended register address was read */
+ actual_reg_addr = bmi_emul_get_reg(emul, BMI160_MAG_I2C_READ_ADDR);
+ zassert_equal(requested_reg_addr, actual_reg_addr,
+ "Read reg $%02x but expected to read $%02x",
+ actual_reg_addr, requested_reg_addr);
+}
+
+/** Test writing to compass via `bmi160_sec_raw_write8()` */
+ZTEST_USER(bmi160, test_bmi_sec_raw_write8)
+{
+ struct motion_sensor_t *ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ uint8_t expected_write_value = 0xAB;
+ uint8_t requested_reg_addr = 0x56;
+ uint8_t actual_reg_addr;
+ int actual_written_value;
+ int ret;
+
+ ret = bmi160_sec_raw_write8(ms->port, ms->i2c_spi_addr_flags,
+ requested_reg_addr, expected_write_value);
+
+ /* Verify return value */
+ zassert_equal(ret, EC_RES_SUCCESS, "Expected return code %d but got %d",
+ EC_RES_SUCCESS, ret);
+
+ /* Verify the correct value was written */
+ actual_written_value =
+ bmi_emul_get_reg(emul, BMI160_MAG_I2C_WRITE_DATA);
+ zassert_equal(expected_write_value, actual_written_value,
+ "Wrote value $%02x but expected to write $%02x",
+ actual_written_value, expected_write_value);
+
+ /* Verify the intended register address was used */
+ actual_reg_addr = bmi_emul_get_reg(emul, BMI160_MAG_I2C_WRITE_ADDR);
+ zassert_equal(requested_reg_addr, actual_reg_addr,
+ "Wrote reg $%02x but expected to write $%02x",
+ actual_reg_addr, requested_reg_addr);
+}
+
+/** Test setting an offset on an invalid sensor type */
+ZTEST_USER(bmi160, test_bmi_set_offset_invalid_type)
+{
+ struct motion_sensor_t ms_fake;
+ int ret;
+ int16_t unused_offset = 0;
+ int16_t temp = 0;
+
+ /* make a copy of the accel motion sensor so we modify its type */
+ memcpy(&ms_fake, &motion_sensors[BMI_ACC_SENSOR_ID], sizeof(ms_fake));
+ ms_fake.type = MOTIONSENSE_TYPE_MAX;
+
+ ret = ms_fake.drv->set_offset(&ms_fake, &unused_offset, temp);
+
+ zassert_equal(ret, EC_RES_INVALID_PARAM,
+ "Expected return code of %d but got %d",
+ EC_RES_INVALID_PARAM, ret);
+}
+
+/** Test performing a calibration on a magnetometer, which is not supported */
+ZTEST_USER(bmi160, test_bmi_perform_calib_invalid_type)
+{
+ struct motion_sensor_t ms_fake;
+ int ret;
+
+ /* make a copy of the accel motion sensor so we modify its type */
+ memcpy(&ms_fake, &motion_sensors[BMI_ACC_SENSOR_ID], sizeof(ms_fake));
+ ms_fake.type = MOTIONSENSE_TYPE_MAG;
+
+ ret = ms_fake.drv->perform_calib(&ms_fake, 1);
+
+ zassert_equal(ret, EC_RES_INVALID_PARAM,
+ "Expected return code of %d but got %d",
+ EC_RES_INVALID_PARAM, ret);
+}
+
+/** Test reading the onboard temperature sensor */
+ZTEST_USER(bmi160, test_bmi_temp_sensor)
+{
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ int ret;
+
+ /* Part 1:
+ * Set up the register so we read 300 Kelvin. 0x0000 is 23 deg C, and
+ * each LSB is 0.5^9 deg C. See BMI160 datasheet for more details.
+ */
+ int actual_read_temp_k, expected_temp_k = 300;
+ uint16_t temp_reg_value = (K_TO_C(expected_temp_k) - 23) << 9;
+
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, temp_reg_value & 0xFF);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, temp_reg_value >> 8);
+
+ /* The output will be in Kelvin */
+ ret = bmi160_get_sensor_temp(BMI_ACC_SENSOR_ID, &actual_read_temp_k);
+
+ zassert_equal(ret, EC_RES_SUCCESS, "Expected %d but got %d",
+ EC_RES_SUCCESS, ret);
+ zassert_equal(expected_temp_k, actual_read_temp_k,
+ "Expected %dK but got %dK", expected_temp_k,
+ actual_read_temp_k);
+
+ /* Part 2:
+ * Have the chip return an invalid reading.
+ */
+ temp_reg_value = BMI_INVALID_TEMP;
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_0, temp_reg_value & 0xFF);
+ bmi_emul_set_reg(emul, BMI160_TEMPERATURE_1, temp_reg_value >> 8);
+
+ ret = bmi160_get_sensor_temp(BMI_ACC_SENSOR_ID, &actual_read_temp_k);
+
+ zassert_equal(ret, EC_ERROR_NOT_POWERED, "Expected %d but got %d",
+ EC_ERROR_NOT_POWERED, ret);
+}
+
+ZTEST_USER(bmi160, test_bmi_interrupt_handler)
+{
+ /* The accelerometer interrupt handler simply sets an event flag for the
+ * motion sensing task. Make sure that flag starts cleared, fire the
+ * interrupt, and ensure the flag is set.
+ */
+
+ atomic_t *mask;
+
+ mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE);
+ zassert_true(mask != NULL,
+ "Got a null pointer when getting event bitmap.");
+ zassert_true((*mask & CONFIG_ACCELGYRO_BMI160_INT_EVENT) == 0,
+ "Event flag is set before firing interrupt");
+
+ bmi160_interrupt(0);
+
+ mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE);
+ zassert_true(mask != NULL,
+ "Got a null pointer when getting event bitmap.");
+ zassert_true(*mask & CONFIG_ACCELGYRO_BMI160_INT_EVENT,
+ "Event flag is not set after firing interrupt");
+}
+
+/* Make an I2C emulator mock wrapped in FFF for use with test_bmi_init_chip_id()
+ */
+FAKE_VALUE_FUNC(int, bmi_init_chip_id_mock_write_fn, const struct emul *, int,
+ uint8_t, int, void *);
+
+/** Test handling of invalid or unreadable chip IDs in init() */
+ZTEST_USER(bmi160, test_bmi_init_chip_id)
+{
+ struct motion_sensor_t *ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ int ret;
+
+ /* Part 1: Cannot read the Chip ID register */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_CHIP_ID);
+ ret = ms->drv->init(ms);
+
+ zassert_equal(ret, EC_ERROR_UNKNOWN, "Expected %d but got %d",
+ EC_ERROR_UNKNOWN, ret);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Part 2: Incorrect chip ID - this triggers a series of writes in an
+ * attempt to 'unlock' the chip.
+ */
+
+ /* Have the mocked write function return 1 so everything is passed
+ * through. We only care about using FFF to capture the argument
+ * history.
+ */
+
+ RESET_FAKE(bmi_init_chip_id_mock_write_fn);
+ bmi_init_chip_id_mock_write_fn_fake.return_val = 1;
+ i2c_common_emul_set_write_func(common_data,
+ bmi_init_chip_id_mock_write_fn, NULL);
+
+ /* Return a phony chip ID */
+ bmi_emul_set_reg(emul, BMI160_CHIP_ID, 0xFF);
+
+ ret = ms->drv->init(ms);
+
+ /* Verify return value */
+ zassert_equal(ret, EC_ERROR_ACCESS_DENIED, "Expected %d but got %d",
+ EC_ERROR_ACCESS_DENIED, ret);
+
+ /* Verify that all expected I2C writes were completed, in order */
+ MOCK_ASSERT_I2C_WRITE(bmi_init_chip_id_mock_write_fn, 0, BMI160_CMD_REG,
+ BMI160_CMD_EXT_MODE_EN_B0);
+ MOCK_ASSERT_I2C_WRITE(bmi_init_chip_id_mock_write_fn, 1, BMI160_CMD_REG,
+ BMI160_CMD_EXT_MODE_EN_B1);
+ MOCK_ASSERT_I2C_WRITE(bmi_init_chip_id_mock_write_fn, 2, BMI160_CMD_REG,
+ BMI160_CMD_EXT_MODE_EN_B2);
+ MOCK_ASSERT_I2C_WRITE(bmi_init_chip_id_mock_write_fn, 3,
+ BMI160_CMD_EXT_MODE_ADDR, BMI160_CMD_PAGING_EN);
+ MOCK_ASSERT_I2C_WRITE(bmi_init_chip_id_mock_write_fn, 4,
+ BMI160_CMD_EXT_MODE_ADDR, 0);
+
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+static void bmi160_before(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ struct motion_sensor_t *acc_ms;
+ struct motion_sensor_t *gyr_ms;
+
+ acc_ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ gyr_ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bmi_emul_set_reg(emul, BMI160_CHIP_ID, 0xd1);
+
+ /* Disable rotation */
+ gyr_ms->rot_standard_ref = NULL;
+ acc_ms->rot_standard_ref = NULL;
+
+ zassume_equal(EC_SUCCESS, acc_ms->drv->set_data_rate(acc_ms, 50000, 0),
+ NULL);
+ zassume_equal(EC_SUCCESS, gyr_ms->drv->set_data_rate(gyr_ms, 50000, 0),
+ NULL);
+}
+
+static void bmi160_after(void *state)
+{
+ ARG_UNUSED(state);
+ struct motion_sensor_t *acc_ms, *gyr_ms;
+
+ acc_ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ gyr_ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ acc_ms->drv->set_data_rate(acc_ms, 0, 0);
+ gyr_ms->drv->set_data_rate(gyr_ms, 0, 0);
+}
+
+ZTEST_SUITE(bmi160, drivers_predicate_pre_main, NULL, bmi160_before,
+ bmi160_after, NULL);
+
+/** Cause an interrupt and verify the motion_sense task handled it. */
+ZTEST_USER(bmi160_tasks, test_irq_handling)
+{
+ struct bmi_emul_frame f[3];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+
+ f[0].type = BMI_EMUL_FRAME_ACC;
+ f[0].acc_x = BMI_EMUL_1G / 10;
+ f[0].acc_y = BMI_EMUL_1G / 20;
+ f[0].acc_z = -(int)BMI_EMUL_1G / 30;
+ f[0].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_0, BMI160_FWM_INT & 0xff);
+ bmi_emul_set_reg(emul, BMI160_INT_STATUS_1,
+ (BMI160_FWM_INT >> 8) & 0xff);
+
+ bmi160_interrupt(0);
+ k_sleep(K_SECONDS(10));
+
+ /* Verify that the motion_sense_task read it. */
+ zassert_equal(bmi_emul_get_reg(emul, BMI160_INT_STATUS_0), 0, NULL);
+ zassert_equal(bmi_emul_get_reg(emul, BMI160_INT_STATUS_1), 0, NULL);
+}
+
+ZTEST_SUITE(bmi160_tasks, drivers_predicate_post_main, NULL, bmi160_before,
+ bmi160_after, NULL);
diff --git a/zephyr/test/drivers/default/src/bmi260.c b/zephyr/test/drivers/default/src/bmi260.c
new file mode 100644
index 0000000000..9295d631ca
--- /dev/null
+++ b/zephyr/test/drivers/default/src/bmi260.c
@@ -0,0 +1,2305 @@
+/* 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/fff.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "common.h"
+#include "i2c.h"
+#include "emul/emul_bmi.h"
+#include "emul/emul_common_i2c.h"
+
+#include "motion_sense_fifo.h"
+#include "driver/accelgyro_bmi260.h"
+#include "driver/accelgyro_bmi_common.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+#define BMI_NODE DT_NODELABEL(accel_bmi260)
+#define BMI_ACC_SENSOR_ID SENSOR_ID(DT_NODELABEL(ms_bmi260_accel))
+#define BMI_GYR_SENSOR_ID SENSOR_ID(DT_NODELABEL(ms_bmi260_gyro))
+#define BMI_INT_EVENT \
+ TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(bmi260_int)))
+
+/** How accurate comparision of vectors should be */
+#define V_EPS 8
+
+/** Convert from one type of vector to another */
+#define convert_int3v_int16(v, r) \
+ do { \
+ r[0] = v[0]; \
+ r[1] = v[1]; \
+ r[2] = v[2]; \
+ } while (0)
+
+/** Rotation used in some tests */
+static const mat33_fp_t test_rotation = { { 0, FLOAT_TO_FP(1), 0 },
+ { FLOAT_TO_FP(-1), 0, 0 },
+ { 0, 0, FLOAT_TO_FP(-1) } };
+/** Rotate given vector by test rotation */
+static void rotate_int3v_by_test_rotation(intv3_t v)
+{
+ int16_t t;
+
+ t = v[0];
+ v[0] = -v[1];
+ v[1] = t;
+ v[2] = -v[2];
+}
+
+/** Set emulator accelerometer offset values to intv3_t vector */
+static void set_emul_acc_offset(const struct emul *emul, intv3_t offset)
+{
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_X, offset[0]);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Y, offset[1]);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Z, offset[2]);
+}
+
+/** Save emulator accelerometer offset values to intv3_t vector */
+static void get_emul_acc_offset(const struct emul *emul, intv3_t offset)
+{
+ offset[0] = bmi_emul_get_off(emul, BMI_EMUL_ACC_X);
+ offset[1] = bmi_emul_get_off(emul, BMI_EMUL_ACC_Y);
+ offset[2] = bmi_emul_get_off(emul, BMI_EMUL_ACC_Z);
+}
+
+/** Set emulator accelerometer values to intv3_t vector */
+static void set_emul_acc(const struct emul *emul, intv3_t acc)
+{
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_X, acc[0]);
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Y, acc[1]);
+ bmi_emul_set_value(emul, BMI_EMUL_ACC_Z, acc[2]);
+}
+
+/** Set emulator gyroscope offset values to intv3_t vector */
+static void set_emul_gyr_offset(const struct emul *emul, intv3_t offset)
+{
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_X, offset[0]);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Y, offset[1]);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Z, offset[2]);
+}
+
+/** Save emulator gyroscope offset values to intv3_t vector */
+static void get_emul_gyr_offset(const struct emul *emul, intv3_t offset)
+{
+ offset[0] = bmi_emul_get_off(emul, BMI_EMUL_GYR_X);
+ offset[1] = bmi_emul_get_off(emul, BMI_EMUL_GYR_Y);
+ offset[2] = bmi_emul_get_off(emul, BMI_EMUL_GYR_Z);
+}
+
+/** Set emulator gyroscope values to vector of three int16_t */
+static void set_emul_gyr(const struct emul *emul, intv3_t gyr)
+{
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_X, gyr[0]);
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_Y, gyr[1]);
+ bmi_emul_set_value(emul, BMI_EMUL_GYR_Z, gyr[2]);
+}
+
+/** Convert accelerometer read to units used by emulator */
+static void drv_acc_to_emul(intv3_t drv, int range, intv3_t out)
+{
+ const int scale = MOTION_SCALING_FACTOR / BMI_EMUL_1G;
+
+ out[0] = drv[0] * range / scale;
+ out[1] = drv[1] * range / scale;
+ out[2] = drv[2] * range / scale;
+}
+
+/** Convert gyroscope read to units used by emulator */
+static void drv_gyr_to_emul(intv3_t drv, int range, intv3_t out)
+{
+ const int scale = MOTION_SCALING_FACTOR / BMI_EMUL_125_DEG_S;
+
+ range /= 125;
+ out[0] = drv[0] * range / scale;
+ out[1] = drv[1] * range / scale;
+ out[2] = drv[2] * range / scale;
+}
+
+/** Compare two vectors of intv3_t type */
+static void compare_int3v_f(intv3_t exp_v, intv3_t v, int eps, int line)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ zassert_within(
+ exp_v[i], v[i], eps,
+ "Expected [%d; %d; %d], got [%d; %d; %d]; line: %d",
+ exp_v[0], exp_v[1], exp_v[2], v[0], v[1], v[2], line);
+ }
+}
+#define compare_int3v_eps(exp_v, v, e) compare_int3v_f(exp_v, v, e, __LINE__)
+#define compare_int3v(exp_v, v) compare_int3v_eps(exp_v, v, V_EPS)
+
+/**
+ * Custom emulator read function which always return INIT OK status in
+ * INTERNAL STATUS register. Used in init test.
+ */
+static int emul_init_ok(const struct emul *emul, int reg, uint8_t *val,
+ int byte, void *data)
+{
+ bmi_emul_set_reg(emul, BMI260_INTERNAL_STATUS, BMI260_INIT_OK);
+
+ return 1;
+}
+
+/** Init BMI260 before test */
+static void bmi_init_emul(void)
+{
+ struct motion_sensor_t *ms_acc;
+ struct motion_sensor_t *ms_gyr;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int ret;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /*
+ * Init BMI before test. It is needed custom function to set value of
+ * BMI260_INTERNAL_STATUS register, because init function triggers reset
+ * which clears value set in this register before test.
+ */
+ i2c_common_emul_set_read_func(common_data, emul_init_ok, NULL);
+
+ ret = ms_acc->drv->init(ms_acc);
+ zassert_equal(EC_RES_SUCCESS, ret, "Got accel init error %d", ret);
+
+ ret = ms_gyr->drv->init(ms_gyr);
+ zassert_equal(EC_RES_SUCCESS, ret, "Got gyro init error %d", ret);
+
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+/** Test get accelerometer offset with and without rotation */
+ZTEST_USER(bmi260, test_bmi_acc_get_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int16_t ret[3];
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t temp;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Set emulator offset */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ set_emul_acc_offset(emul, exp_v);
+ /* BMI driver returns value in mg units */
+ exp_v[0] = 1000 / 10;
+ exp_v[1] = 1000 / 20;
+ exp_v[2] = -1000 / 30;
+
+ /* Test fail on offset read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_ACC70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test get offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected offset */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+
+ /* Test get offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v(exp_v, ret_v);
+}
+
+/** Test get gyroscope offset with and without rotation */
+ZTEST_USER(bmi260, test_bmi_gyr_get_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int16_t ret[3];
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t temp;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set emulator offset */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ set_emul_gyr_offset(emul, exp_v);
+ /* BMI driver returns value in mdeg/s units */
+ exp_v[0] = 125000 / 100;
+ exp_v[1] = 125000 / 200;
+ exp_v[2] = -125000 / 300;
+
+ /* Test fail on offset read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_GYR70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI160_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->get_offset(ms, ret, &temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test get offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+
+ /* Setup rotation and rotate expected offset */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+
+ /* Test get offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->get_offset(ms, ret, &temp), NULL);
+ zassert_equal(temp, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ convert_int3v_int16(ret, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+}
+
+/**
+ * Test set accelerometer offset with and without rotation. Also test behaviour
+ * on I2C error.
+ */
+ZTEST_USER(bmi260, test_bmi_acc_set_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int16_t input_v[3] = { 0, 0, 0 };
+ int16_t temp = 0;
+ intv3_t ret_v;
+ intv3_t exp_v;
+ uint8_t nv_c;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Test fail on NV CONF register read and write */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_NV_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_NV_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on offset write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI160_OFFSET_ACC70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_ACC70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI160_OFFSET_ACC70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup NV_CONF register value */
+ bmi_emul_set_reg(emul, BMI260_NV_CONF, 0x7);
+ /* Set input offset */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ /* BMI driver accept value in mg units */
+ input_v[0] = 1000 / 10;
+ input_v[1] = 1000 / 20;
+ input_v[2] = -1000 / 30;
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test set offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_acc_offset(emul, ret_v);
+ /*
+ * Depending on used range, accelerometer values may be up to 6 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_v, ret_v, 64);
+ nv_c = bmi_emul_get_reg(emul, BMI260_NV_CONF);
+ /* Only ACC_OFFSET_EN bit should be changed */
+ zassert_equal(0x7 | BMI260_ACC_OFFSET_EN, nv_c,
+ "Expected 0x%x, got 0x%x", 0x7 | BMI260_ACC_OFFSET_EN,
+ nv_c);
+
+ /* Setup NV_CONF register value */
+ bmi_emul_set_reg(emul, BMI260_NV_CONF, 0);
+ /* Setup rotation and rotate input for set_offset function */
+ ms->rot_standard_ref = &test_rotation;
+ convert_int3v_int16(input_v, ret_v);
+ rotate_int3v_by_test_rotation(ret_v);
+ convert_int3v_int16(ret_v, input_v);
+
+ /* Test set offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_acc_offset(emul, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 64);
+ nv_c = bmi_emul_get_reg(emul, BMI260_NV_CONF);
+ /* Only ACC_OFFSET_EN bit should be changed */
+ zassert_equal(BMI260_ACC_OFFSET_EN, nv_c, "Expected 0x%x, got 0x%x",
+ BMI260_ACC_OFFSET_EN, nv_c);
+}
+
+/**
+ * Test set gyroscope offset with and without rotation. Also test behaviour
+ * on I2C error.
+ */
+ZTEST_USER(bmi260, test_bmi_gyr_set_offset)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int16_t input_v[3];
+ int16_t temp = 0;
+ intv3_t ret_v;
+ intv3_t exp_v;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Test fail on OFFSET EN GYR98 register read and write */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on offset write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_OFFSET_GYR70);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI260_OFFSET_GYR70 + 1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ BMI260_OFFSET_GYR70 + 2);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_offset(ms, input_v, temp),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set input offset */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ /* BMI driver accept value in mdeg/s units */
+ input_v[0] = 125000 / 100;
+ input_v[1] = 125000 / 200;
+ input_v[2] = -125000 / 300;
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Test set offset without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_gyr_offset(emul, ret_v);
+ /*
+ * Depending on used range, gyroscope values may be up to 4 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_v, ret_v, 32);
+ /* Gyroscope offset should be enabled */
+ zassert_true(bmi_emul_get_reg(emul, BMI260_OFFSET_EN_GYR98) &
+ BMI260_OFFSET_GYRO_EN,
+ NULL);
+
+ /* Setup rotation and rotate input for set_offset function */
+ ms->rot_standard_ref = &test_rotation;
+ convert_int3v_int16(input_v, ret_v);
+ rotate_int3v_by_test_rotation(ret_v);
+ convert_int3v_int16(ret_v, input_v);
+
+ /* Test set offset with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->set_offset(ms, input_v, temp), NULL);
+ get_emul_gyr_offset(emul, ret_v);
+ compare_int3v_eps(exp_v, ret_v, 32);
+ zassert_true(bmi_emul_get_reg(emul, BMI260_OFFSET_EN_GYR98) &
+ BMI260_OFFSET_GYRO_EN,
+ NULL);
+}
+
+/**
+ * Try to set accelerometer range and check if expected range was set
+ * in driver and in emulator.
+ */
+static void check_set_acc_range_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int range,
+ int rnd, int exp_range, int line)
+{
+ uint8_t exp_range_reg;
+ uint8_t range_reg;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, rnd),
+ "set_range failed; line: %d", line);
+ zassert_equal(exp_range, ms->current_range,
+ "Expected range %d, got %d; line %d", exp_range,
+ ms->current_range, line);
+ range_reg = bmi_emul_get_reg(emul, BMI260_ACC_RANGE);
+
+ switch (exp_range) {
+ case 2:
+ exp_range_reg = BMI260_GSEL_2G;
+ break;
+ case 4:
+ exp_range_reg = BMI260_GSEL_4G;
+ break;
+ case 8:
+ exp_range_reg = BMI260_GSEL_8G;
+ break;
+ case 16:
+ exp_range_reg = BMI260_GSEL_16G;
+ break;
+ default:
+ /* Unknown expected range */
+ zassert_unreachable(
+ "Expected range %d not supported by device; line %d",
+ exp_range, line);
+ return;
+ }
+
+ zassert_equal(exp_range_reg, range_reg,
+ "Expected range reg 0x%x, got 0x%x; line %d",
+ exp_range_reg, range_reg, line);
+}
+#define check_set_acc_range(emul, ms, range, rnd, exp_range) \
+ check_set_acc_range_f(emul, ms, range, rnd, exp_range, __LINE__)
+
+/** Test set accelerometer range with and without I2C errors */
+ZTEST_USER(bmi260, test_bmi_acc_set_range)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int start_range;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Setup starting range, shouldn't be changed on error */
+ start_range = 2;
+ ms->current_range = start_range;
+ bmi_emul_set_reg(emul, BMI260_ACC_RANGE, BMI260_GSEL_2G);
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_ACC_RANGE);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 12, 0), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI260_GSEL_2G, bmi_emul_get_reg(emul, BMI260_ACC_RANGE),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 12, 1), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI260_GSEL_2G, bmi_emul_get_reg(emul, BMI260_ACC_RANGE),
+ NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting range with rounding down */
+ check_set_acc_range(emul, ms, 1, 0, 2);
+ check_set_acc_range(emul, ms, 2, 0, 2);
+ check_set_acc_range(emul, ms, 3, 0, 2);
+ check_set_acc_range(emul, ms, 4, 0, 4);
+ check_set_acc_range(emul, ms, 5, 0, 4);
+ check_set_acc_range(emul, ms, 6, 0, 4);
+ check_set_acc_range(emul, ms, 7, 0, 4);
+ check_set_acc_range(emul, ms, 8, 0, 8);
+ check_set_acc_range(emul, ms, 9, 0, 8);
+ check_set_acc_range(emul, ms, 15, 0, 8);
+ check_set_acc_range(emul, ms, 16, 0, 16);
+ check_set_acc_range(emul, ms, 17, 0, 16);
+
+ /* Test setting range with rounding up */
+ check_set_acc_range(emul, ms, 1, 1, 2);
+ check_set_acc_range(emul, ms, 2, 1, 2);
+ check_set_acc_range(emul, ms, 3, 1, 4);
+ check_set_acc_range(emul, ms, 4, 1, 4);
+ check_set_acc_range(emul, ms, 5, 1, 8);
+ check_set_acc_range(emul, ms, 6, 1, 8);
+ check_set_acc_range(emul, ms, 7, 1, 8);
+ check_set_acc_range(emul, ms, 8, 1, 8);
+ check_set_acc_range(emul, ms, 9, 1, 16);
+ check_set_acc_range(emul, ms, 15, 1, 16);
+ check_set_acc_range(emul, ms, 16, 1, 16);
+ check_set_acc_range(emul, ms, 17, 1, 16);
+}
+
+/**
+ * Try to set gyroscope range and check if expected range was set in driver and
+ * in emulator.
+ */
+static void check_set_gyr_range_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int range,
+ int rnd, int exp_range, int line)
+{
+ uint8_t exp_range_reg;
+ uint8_t range_reg;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, rnd),
+ "set_range failed; line: %d", line);
+ zassert_equal(exp_range, ms->current_range,
+ "Expected range %d, got %d; line %d", exp_range,
+ ms->current_range, line);
+ range_reg = bmi_emul_get_reg(emul, BMI260_GYR_RANGE);
+
+ switch (exp_range) {
+ case 125:
+ exp_range_reg = BMI260_DPS_SEL_125;
+ break;
+ case 250:
+ exp_range_reg = BMI260_DPS_SEL_250;
+ break;
+ case 500:
+ exp_range_reg = BMI260_DPS_SEL_500;
+ break;
+ case 1000:
+ exp_range_reg = BMI260_DPS_SEL_1000;
+ break;
+ case 2000:
+ exp_range_reg = BMI260_DPS_SEL_2000;
+ break;
+ default:
+ /* Unknown expected range */
+ zassert_unreachable(
+ "Expected range %d not supported by device; line %d",
+ exp_range, line);
+ return;
+ }
+
+ zassert_equal(exp_range_reg, range_reg,
+ "Expected range reg 0x%x, got 0x%x; line %d",
+ exp_range_reg, range_reg, line);
+}
+#define check_set_gyr_range(emul, ms, range, rnd, exp_range) \
+ check_set_gyr_range_f(emul, ms, range, rnd, exp_range, __LINE__)
+
+/** Test set gyroscope range with and without I2C errors */
+ZTEST_USER(bmi260, test_bmi_gyr_set_range)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int start_range;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Setup starting range, shouldn't be changed on error */
+ start_range = 250;
+ ms->current_range = start_range;
+ bmi_emul_set_reg(emul, BMI260_GYR_RANGE, BMI260_DPS_SEL_250);
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_GYR_RANGE);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 125, 0), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI260_DPS_SEL_250,
+ bmi_emul_get_reg(emul, BMI260_GYR_RANGE), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_range(ms, 125, 1), NULL);
+ zassert_equal(start_range, ms->current_range, NULL);
+ zassert_equal(BMI260_DPS_SEL_250,
+ bmi_emul_get_reg(emul, BMI260_GYR_RANGE), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting range with rounding down */
+ check_set_gyr_range(emul, ms, 1, 0, 125);
+ check_set_gyr_range(emul, ms, 124, 0, 125);
+ check_set_gyr_range(emul, ms, 125, 0, 125);
+ check_set_gyr_range(emul, ms, 126, 0, 125);
+ check_set_gyr_range(emul, ms, 249, 0, 125);
+ check_set_gyr_range(emul, ms, 250, 0, 250);
+ check_set_gyr_range(emul, ms, 251, 0, 250);
+ check_set_gyr_range(emul, ms, 499, 0, 250);
+ check_set_gyr_range(emul, ms, 500, 0, 500);
+ check_set_gyr_range(emul, ms, 501, 0, 500);
+ check_set_gyr_range(emul, ms, 999, 0, 500);
+ check_set_gyr_range(emul, ms, 1000, 0, 1000);
+ check_set_gyr_range(emul, ms, 1001, 0, 1000);
+ check_set_gyr_range(emul, ms, 1999, 0, 1000);
+ check_set_gyr_range(emul, ms, 2000, 0, 2000);
+ check_set_gyr_range(emul, ms, 2001, 0, 2000);
+
+ /* Test setting range with rounding up */
+ check_set_gyr_range(emul, ms, 1, 1, 125);
+ check_set_gyr_range(emul, ms, 124, 1, 125);
+ check_set_gyr_range(emul, ms, 125, 1, 125);
+ check_set_gyr_range(emul, ms, 126, 1, 250);
+ check_set_gyr_range(emul, ms, 249, 1, 250);
+ check_set_gyr_range(emul, ms, 250, 1, 250);
+ check_set_gyr_range(emul, ms, 251, 1, 500);
+ check_set_gyr_range(emul, ms, 499, 1, 500);
+ check_set_gyr_range(emul, ms, 500, 1, 500);
+ check_set_gyr_range(emul, ms, 501, 1, 1000);
+ check_set_gyr_range(emul, ms, 999, 1, 1000);
+ check_set_gyr_range(emul, ms, 1000, 1, 1000);
+ check_set_gyr_range(emul, ms, 1001, 1, 2000);
+ check_set_gyr_range(emul, ms, 1999, 1, 2000);
+ check_set_gyr_range(emul, ms, 2000, 1, 2000);
+ check_set_gyr_range(emul, ms, 2001, 1, 2000);
+}
+
+/** Test get resolution of acclerometer and gyroscope sensor */
+ZTEST_USER(bmi260, test_bmi_get_resolution)
+{
+ struct motion_sensor_t *ms;
+
+ /* Test accelerometer */
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Resolution should be always 16 bits */
+ zassert_equal(16, ms->drv->get_resolution(ms), NULL);
+
+ /* Test gyroscope */
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Resolution should be always 16 bits */
+ zassert_equal(16, ms->drv->get_resolution(ms), NULL);
+}
+
+/**
+ * Try to set accelerometer data rate and check if expected rate was set
+ * in driver and in emulator.
+ */
+static void check_set_acc_rate_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int rate, int rnd,
+ int exp_rate, int line)
+{
+ uint8_t exp_rate_reg;
+ uint8_t rate_reg;
+ int drv_rate;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, rnd),
+ "set_data_rate failed; line: %d", line);
+ drv_rate = ms->drv->get_data_rate(ms);
+ zassert_equal(exp_rate, drv_rate, "Expected rate %d, got %d; line %d",
+ exp_rate, drv_rate, line);
+ rate_reg = bmi_emul_get_reg(emul, BMI260_ACC_CONF);
+ rate_reg &= BMI_ODR_MASK;
+
+ switch (exp_rate) {
+ case 12500:
+ exp_rate_reg = 0x5;
+ break;
+ case 25000:
+ exp_rate_reg = 0x6;
+ break;
+ case 50000:
+ exp_rate_reg = 0x7;
+ break;
+ case 100000:
+ exp_rate_reg = 0x8;
+ break;
+ case 200000:
+ exp_rate_reg = 0x9;
+ break;
+ case 400000:
+ exp_rate_reg = 0xa;
+ break;
+ case 800000:
+ exp_rate_reg = 0xb;
+ break;
+ case 1600000:
+ exp_rate_reg = 0xc;
+ break;
+ default:
+ /* Unknown expected rate */
+ zassert_unreachable(
+ "Expected rate %d not supported by device; line %d",
+ exp_rate, line);
+ return;
+ }
+
+ zassert_equal(exp_rate_reg, rate_reg,
+ "Expected rate reg 0x%x, got 0x%x; line %d", exp_rate_reg,
+ rate_reg, line);
+}
+#define check_set_acc_rate(emul, ms, rate, rnd, exp_rate) \
+ check_set_acc_rate_f(emul, ms, rate, rnd, exp_rate, __LINE__)
+
+/** Test set and get accelerometer rate with and without I2C errors */
+ZTEST_USER(bmi260, test_bmi_acc_rate)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ uint8_t reg_rate;
+ uint8_t pwr_ctrl;
+ int drv_rate;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Test setting rate with rounding down */
+ check_set_acc_rate(emul, ms, 12500, 0, 12500);
+ check_set_acc_rate(emul, ms, 12501, 0, 12500);
+ check_set_acc_rate(emul, ms, 24999, 0, 12500);
+ check_set_acc_rate(emul, ms, 25000, 0, 25000);
+ check_set_acc_rate(emul, ms, 25001, 0, 25000);
+ check_set_acc_rate(emul, ms, 49999, 0, 25000);
+ check_set_acc_rate(emul, ms, 50000, 0, 50000);
+ check_set_acc_rate(emul, ms, 50001, 0, 50000);
+ check_set_acc_rate(emul, ms, 99999, 0, 50000);
+ check_set_acc_rate(emul, ms, 100000, 0, 100000);
+ check_set_acc_rate(emul, ms, 100001, 0, 100000);
+ check_set_acc_rate(emul, ms, 199999, 0, 100000);
+ check_set_acc_rate(emul, ms, 200000, 0, 200000);
+ check_set_acc_rate(emul, ms, 200001, 0, 200000);
+ check_set_acc_rate(emul, ms, 399999, 0, 200000);
+ /*
+ * We cannot test frequencies from 400000 to 1600000 because
+ * CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ is set to 250000
+ */
+
+ /* Test setting rate with rounding up */
+ check_set_acc_rate(emul, ms, 6251, 1, 12500);
+ check_set_acc_rate(emul, ms, 12499, 1, 12500);
+ check_set_acc_rate(emul, ms, 12500, 1, 12500);
+ check_set_acc_rate(emul, ms, 12501, 1, 25000);
+ check_set_acc_rate(emul, ms, 24999, 1, 25000);
+ check_set_acc_rate(emul, ms, 25000, 1, 25000);
+ check_set_acc_rate(emul, ms, 25001, 1, 50000);
+ check_set_acc_rate(emul, ms, 49999, 1, 50000);
+ check_set_acc_rate(emul, ms, 50000, 1, 50000);
+ check_set_acc_rate(emul, ms, 50001, 1, 100000);
+ check_set_acc_rate(emul, ms, 99999, 1, 100000);
+ check_set_acc_rate(emul, ms, 100000, 1, 100000);
+ check_set_acc_rate(emul, ms, 100001, 1, 200000);
+ check_set_acc_rate(emul, ms, 199999, 1, 200000);
+ check_set_acc_rate(emul, ms, 200000, 1, 200000);
+
+ /* Test out of range rate with rounding down */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 0),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 12499, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 2000000, 0), NULL);
+
+ /* Test out of range rate with rounding up */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 6250, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 200001, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 2000000, 1), NULL);
+
+ /* Current rate shouldn't be changed on error */
+ drv_rate = ms->drv->get_data_rate(ms);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_ACC_CONF);
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_CONF);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_ACC_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_ACC_CONF), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_ACC_CONF);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_ACC_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_ACC_CONF), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test disabling sensor */
+ bmi_emul_set_reg(emul, BMI260_PWR_CTRL,
+ BMI260_AUX_EN | BMI260_GYR_EN | BMI260_ACC_EN);
+ bmi_emul_set_reg(emul, BMI260_ACC_CONF, BMI260_FILTER_PERF);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL);
+
+ pwr_ctrl = bmi_emul_get_reg(emul, BMI260_PWR_CTRL);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_ACC_CONF);
+ zassert_equal(BMI260_AUX_EN | BMI260_GYR_EN, pwr_ctrl, NULL);
+ zassert_true(!(reg_rate & BMI260_FILTER_PERF), NULL);
+
+ /* Test enabling sensor */
+ bmi_emul_set_reg(emul, BMI260_PWR_CTRL, 0);
+ bmi_emul_set_reg(emul, BMI260_ACC_CONF, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ pwr_ctrl = bmi_emul_get_reg(emul, BMI260_PWR_CTRL);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_ACC_CONF);
+ zassert_equal(BMI260_ACC_EN, pwr_ctrl, NULL);
+ zassert_true(reg_rate & BMI260_FILTER_PERF, NULL);
+
+ /* Test disabling sensor (by setting rate to 0) but failing. */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_PWR_CTRL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 0, 0),
+ "Did not properly handle failed power down.");
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test enabling sensor but failing. (after first disabling it) */
+ ms->drv->set_data_rate(ms, 0, 0);
+
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_PWR_CTRL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ "Did not properly handle failed power up.");
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+/**
+ * Try to set gyroscope data rate and check if expected rate was set
+ * in driver and in emulator.
+ */
+static void check_set_gyr_rate_f(const struct emul *emul,
+ struct motion_sensor_t *ms, int rate, int rnd,
+ int exp_rate, int line)
+{
+ uint8_t exp_rate_reg;
+ uint8_t rate_reg;
+ int drv_rate;
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, rnd),
+ "set_data_rate failed; line: %d", line);
+ drv_rate = ms->drv->get_data_rate(ms);
+ zassert_equal(exp_rate, drv_rate, "Expected rate %d, got %d; line %d",
+ exp_rate, drv_rate, line);
+ rate_reg = bmi_emul_get_reg(emul, BMI260_GYR_CONF);
+ rate_reg &= BMI_ODR_MASK;
+
+ switch (exp_rate) {
+ case 25000:
+ exp_rate_reg = 0x6;
+ break;
+ case 50000:
+ exp_rate_reg = 0x7;
+ break;
+ case 100000:
+ exp_rate_reg = 0x8;
+ break;
+ case 200000:
+ exp_rate_reg = 0x9;
+ break;
+ case 400000:
+ exp_rate_reg = 0xa;
+ break;
+ case 800000:
+ exp_rate_reg = 0xb;
+ break;
+ case 1600000:
+ exp_rate_reg = 0xc;
+ break;
+ case 3200000:
+ exp_rate_reg = 0xc;
+ break;
+ default:
+ /* Unknown expected rate */
+ zassert_unreachable(
+ "Expected rate %d not supported by device; line %d",
+ exp_rate, line);
+ return;
+ }
+
+ zassert_equal(exp_rate_reg, rate_reg,
+ "Expected rate reg 0x%x, got 0x%x; line %d", exp_rate_reg,
+ rate_reg, line);
+}
+#define check_set_gyr_rate(emul, ms, rate, rnd, exp_rate) \
+ check_set_gyr_rate_f(emul, ms, rate, rnd, exp_rate, __LINE__)
+
+/** Test set and get gyroscope rate with and without I2C errors */
+ZTEST_USER(bmi260, test_bmi_gyr_rate)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ uint8_t reg_rate;
+ uint8_t pwr_ctrl;
+ int drv_rate;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Test setting rate with rounding down */
+ check_set_gyr_rate(emul, ms, 25000, 0, 25000);
+ check_set_gyr_rate(emul, ms, 25001, 0, 25000);
+ check_set_gyr_rate(emul, ms, 49999, 0, 25000);
+ check_set_gyr_rate(emul, ms, 50000, 0, 50000);
+ check_set_gyr_rate(emul, ms, 50001, 0, 50000);
+ check_set_gyr_rate(emul, ms, 99999, 0, 50000);
+ check_set_gyr_rate(emul, ms, 100000, 0, 100000);
+ check_set_gyr_rate(emul, ms, 100001, 0, 100000);
+ check_set_gyr_rate(emul, ms, 199999, 0, 100000);
+ check_set_gyr_rate(emul, ms, 200000, 0, 200000);
+ check_set_gyr_rate(emul, ms, 200001, 0, 200000);
+ check_set_gyr_rate(emul, ms, 399999, 0, 200000);
+ /*
+ * We cannot test frequencies from 400000 to 3200000 because
+ * CONFIG_EC_MAX_SENSOR_FREQ_MILLIHZ is set to 250000
+ */
+
+ /* Test setting rate with rounding up */
+ check_set_gyr_rate(emul, ms, 12501, 1, 25000);
+ check_set_gyr_rate(emul, ms, 24999, 1, 25000);
+ check_set_gyr_rate(emul, ms, 25000, 1, 25000);
+ check_set_gyr_rate(emul, ms, 25001, 1, 50000);
+ check_set_gyr_rate(emul, ms, 49999, 1, 50000);
+ check_set_gyr_rate(emul, ms, 50000, 1, 50000);
+ check_set_gyr_rate(emul, ms, 50001, 1, 100000);
+ check_set_gyr_rate(emul, ms, 99999, 1, 100000);
+ check_set_gyr_rate(emul, ms, 100000, 1, 100000);
+ check_set_gyr_rate(emul, ms, 100001, 1, 200000);
+ check_set_gyr_rate(emul, ms, 199999, 1, 200000);
+ check_set_gyr_rate(emul, ms, 200000, 1, 200000);
+
+ /* Test out of range rate with rounding down */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 0),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 24999, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 0), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 4000000, 0), NULL);
+
+ /* Test out of range rate with rounding up */
+ zassert_equal(EC_RES_INVALID_PARAM, ms->drv->set_data_rate(ms, 1, 1),
+ NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 12499, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 200001, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 400000, 1), NULL);
+ zassert_equal(EC_RES_INVALID_PARAM,
+ ms->drv->set_data_rate(ms, 4000000, 1), NULL);
+
+ /* Current rate shouldn't be changed on error */
+ drv_rate = ms->drv->get_data_rate(ms);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_GYR_CONF);
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_CONF);
+
+ /* Test fail on read */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_GYR_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_GYR_CONF), NULL);
+
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup emulator fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_GYR_CONF);
+
+ /* Test fail on write */
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 0),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_GYR_CONF), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 50000, 1),
+ NULL);
+ zassert_equal(drv_rate, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(reg_rate, bmi_emul_get_reg(emul, BMI260_GYR_CONF), NULL);
+
+ /* Do not fail on write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test disabling sensor */
+ bmi_emul_set_reg(emul, BMI260_PWR_CTRL,
+ BMI260_AUX_EN | BMI260_GYR_EN | BMI260_ACC_EN);
+ bmi_emul_set_reg(emul, BMI260_GYR_CONF,
+ BMI260_FILTER_PERF | BMI260_GYR_NOISE_PERF);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL);
+
+ pwr_ctrl = bmi_emul_get_reg(emul, BMI260_PWR_CTRL);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_GYR_CONF);
+ zassert_equal(BMI260_AUX_EN | BMI260_ACC_EN, pwr_ctrl, NULL);
+ zassert_true(!(reg_rate & (BMI260_FILTER_PERF | BMI260_GYR_NOISE_PERF)),
+ NULL);
+
+ /* Test enabling sensor */
+ bmi_emul_set_reg(emul, BMI260_PWR_CTRL, 0);
+ bmi_emul_set_reg(emul, BMI260_GYR_CONF, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ pwr_ctrl = bmi_emul_get_reg(emul, BMI260_PWR_CTRL);
+ reg_rate = bmi_emul_get_reg(emul, BMI260_GYR_CONF);
+ zassert_equal(BMI260_GYR_EN, pwr_ctrl, NULL);
+ zassert_true(reg_rate & (BMI260_FILTER_PERF | BMI260_GYR_NOISE_PERF),
+ NULL);
+}
+
+/**
+ * Test setting and getting scale in accelerometer and gyroscope sensors.
+ * Correct appling scale to results is checked in "read" test.
+ */
+ZTEST_USER(bmi260, test_bmi_scale)
+{
+ struct motion_sensor_t *ms;
+ int16_t ret_scale[3];
+ int16_t exp_scale[3] = { 100, 231, 421 };
+ int16_t t;
+
+ /* Test accelerometer */
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, exp_scale, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->get_scale(ms, ret_scale, &t), NULL);
+
+ zassert_equal(t, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ zassert_equal(exp_scale[0], ret_scale[0], NULL);
+ zassert_equal(exp_scale[1], ret_scale[1], NULL);
+ zassert_equal(exp_scale[2], ret_scale[2], NULL);
+
+ /* Test gyroscope */
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, exp_scale, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->get_scale(ms, ret_scale, &t), NULL);
+
+ zassert_equal(t, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, NULL);
+ zassert_equal(exp_scale[0], ret_scale[0], NULL);
+ zassert_equal(exp_scale[1], ret_scale[1], NULL);
+ zassert_equal(exp_scale[2], ret_scale[2], NULL);
+}
+
+/** Test reading temperature using accelerometer and gyroscope sensors */
+ZTEST_USER(bmi260, test_bmi_read_temp)
+{
+ struct motion_sensor_t *ms_acc, *ms_gyr;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int ret_temp;
+ int exp_temp;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Setup emulator fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_TEMPERATURE_0);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_TEMPERATURE_1);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+ /* Do not fail on read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Fail on invalid temperature */
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_1, 0x80);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_acc->drv->read_temp(ms_acc, &ret_temp), NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ ms_gyr->drv->read_temp(ms_gyr, &ret_temp), NULL);
+
+ /*
+ * Test correct values. Both motion sensors should return the same
+ * temperature.
+ */
+ exp_temp = C_TO_K(23);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_1, 0x00);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(87);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_0, 0xff);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_1, 0x7f);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(-41);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_0, 0x01);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_1, 0x80);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+
+ exp_temp = C_TO_K(47);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_0, 0x00);
+ bmi_emul_set_reg(emul, BMI260_TEMPERATURE_1, 0x30);
+ zassert_equal(EC_SUCCESS, ms_acc->drv->read_temp(ms_acc, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->read_temp(ms_gyr, &ret_temp),
+ NULL);
+ zassert_equal(exp_temp, ret_temp, NULL);
+}
+
+/** Test reading accelerometer sensor data */
+ZTEST_USER(bmi260, test_bmi_acc_read)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t scale[3] = { MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE };
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Set offset 0 to simplify test */
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_X, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Y, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_ACC_Z, 0);
+
+ /* Fail on read status */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* When not ready, driver should return saved raw value */
+ exp_v[0] = 100;
+ exp_v[1] = 200;
+ exp_v[2] = 300;
+ ms->raw_xyz[0] = exp_v[0];
+ ms->raw_xyz[1] = exp_v[1];
+ ms->raw_xyz[2] = exp_v[2];
+
+ /* Status not ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status only GYR ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, BMI260_DRDY_GYR);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status ACC ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, BMI260_DRDY_ACC);
+
+ /* Set input accelerometer values */
+ exp_v[0] = BMI_EMUL_1G / 10;
+ exp_v[1] = BMI_EMUL_1G / 20;
+ exp_v[2] = -(int)BMI_EMUL_1G / 30;
+ set_emul_acc(emul, exp_v);
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+ /* Set scale */
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, scale, 0), NULL);
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 2, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 2, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 4, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 4, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected vector */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+ /* Set range to 2G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 2, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 2, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 4G */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 4, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_acc_to_emul(ret_v, 4, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Fail on read of data registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_X_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_Y_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_Y_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_Z_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_Z_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ ms->rot_standard_ref = NULL;
+}
+
+/** Test reading gyroscope sensor data */
+ZTEST_USER(bmi260, test_bmi_gyr_read)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ intv3_t ret_v;
+ intv3_t exp_v;
+ int16_t scale[3] = { MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE };
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Set offset 0 to simplify test */
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_X, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Y, 0);
+ bmi_emul_set_off(emul, BMI_EMUL_GYR_Z, 0);
+
+ /* Fail on read status */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* When not ready, driver should return saved raw value */
+ exp_v[0] = 100;
+ exp_v[1] = 200;
+ exp_v[2] = 300;
+ ms->raw_xyz[0] = exp_v[0];
+ ms->raw_xyz[1] = exp_v[1];
+ ms->raw_xyz[2] = exp_v[2];
+
+ /* Status not ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status only ACC ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, BMI260_DRDY_ACC);
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ compare_int3v(exp_v, ret_v);
+
+ /* Status GYR ready */
+ bmi_emul_set_reg(emul, BMI260_STATUS, BMI260_DRDY_GYR);
+
+ /* Set input accelerometer values */
+ exp_v[0] = BMI_EMUL_125_DEG_S / 10;
+ exp_v[1] = BMI_EMUL_125_DEG_S / 20;
+ exp_v[2] = -(int)BMI_EMUL_125_DEG_S / 30;
+ set_emul_gyr(emul, exp_v);
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+ /* Set scale */
+ zassert_equal(EC_SUCCESS, ms->drv->set_scale(ms, scale, 0), NULL);
+ /* Set range to 125°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 125, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 125, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 1000°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 1000, 0), NULL);
+
+ /* Test read without rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 1000, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Setup rotation and rotate expected vector */
+ ms->rot_standard_ref = &test_rotation;
+ rotate_int3v_by_test_rotation(exp_v);
+ /* Set range to 125°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 125, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 125, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Set range to 1000°/s */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 1000, 0), NULL);
+
+ /* Test read with rotation */
+ zassert_equal(EC_SUCCESS, ms->drv->read(ms, ret_v), NULL);
+ drv_gyr_to_emul(ret_v, 1000, ret_v);
+ compare_int3v(exp_v, ret_v);
+
+ /* Fail on read of data registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_X_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_Y_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_Y_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_Z_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_Z_H_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, ret_v), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ ms->rot_standard_ref = NULL;
+}
+
+/** Test accelerometer calibration */
+ZTEST_USER(bmi260, test_bmi_acc_perform_calib)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ intv3_t start_off;
+ intv3_t exp_off;
+ intv3_t ret_off;
+ int range;
+ int rate;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ bmi_init_emul();
+
+ /* Disable rotation */
+ ms->rot_standard_ref = NULL;
+
+ /* Range and rate cannot change after calibration */
+ range = 4;
+ rate = 50000;
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, 0), NULL);
+
+ /* Set offset 0 */
+ start_off[0] = 0;
+ start_off[1] = 0;
+ start_off[2] = 0;
+ set_emul_acc_offset(emul, start_off);
+
+ /* Set input accelerometer values */
+ exp_off[0] = BMI_EMUL_1G / 10;
+ exp_off[1] = BMI_EMUL_1G / 20;
+ exp_off[2] = BMI_EMUL_1G - (int)BMI_EMUL_1G / 30;
+ set_emul_acc(emul, exp_off);
+
+ /* Expected offset is [-X, -Y, 1G - Z] */
+ exp_off[0] = -exp_off[0];
+ exp_off[1] = -exp_off[1];
+ exp_off[2] = BMI_EMUL_1G - exp_off[2];
+
+ /* Test success on disabling calibration */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on rate read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on status read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on data not ready */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bmi_emul_set_reg(emul, BMI260_STATUS, 0);
+ zassert_equal(EC_ERROR_TIMEOUT, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Setup data status ready for rest of the test */
+ bmi_emul_set_reg(emul, BMI260_STATUS, BMI260_DRDY_ACC);
+
+ /* Test fail on data read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_ACC_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on setting offset */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_NV_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test successful offset compenastion */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_acc_offset(emul, ret_off);
+ /*
+ * Depending on used range, accelerometer values may be up to 6 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_off, ret_off, 64);
+}
+
+/** Test gyroscope calibration */
+ZTEST_USER(bmi260, test_bmi_gyr_perform_calib)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ intv3_t start_off;
+ intv3_t exp_off;
+ intv3_t ret_off;
+ int range;
+ int rate;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ bmi_init_emul();
+
+ /* Range and rate cannot change after calibration */
+ range = 125;
+ rate = 50000;
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, rate, 0), NULL);
+
+ /* Set offset 0 */
+ start_off[0] = 0;
+ start_off[1] = 0;
+ start_off[2] = 0;
+ set_emul_gyr_offset(emul, start_off);
+
+ /* Set input accelerometer values */
+ exp_off[0] = BMI_EMUL_125_DEG_S / 100;
+ exp_off[1] = BMI_EMUL_125_DEG_S / 200;
+ exp_off[2] = -(int)BMI_EMUL_125_DEG_S / 300;
+ set_emul_gyr(emul, exp_off);
+
+ /* Expected offset is [-X, -Y, -Z] */
+ exp_off[0] = -exp_off[0];
+ exp_off[1] = -exp_off[1];
+ exp_off[2] = -exp_off[2];
+
+ /* Test success on disabling calibration */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on rate read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_CONF);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on status read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on data not ready */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ bmi_emul_set_reg(emul, BMI260_STATUS, 0);
+ zassert_equal(EC_ERROR_TIMEOUT, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /*
+ * Setup data status ready for rest of the test. Gyroscope calibration
+ * should check DRDY_GYR bit, but current driver check only for ACC.
+ */
+ bmi_emul_set_reg(emul, BMI260_STATUS,
+ BMI260_DRDY_ACC | BMI260_DRDY_GYR);
+
+ /* Test fail on data read */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_GYR_X_L_G);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ /* Test fail on setting offset */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_OFFSET_EN_GYR98);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test successful offset compenastion */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(range, ms->current_range, NULL);
+ zassert_equal(rate, ms->drv->get_data_rate(ms), NULL);
+ get_emul_gyr_offset(emul, ret_off);
+ /*
+ * Depending on used range, gyroscope values may be up to 4 bits
+ * more accurate then offset value resolution.
+ */
+ compare_int3v_eps(exp_off, ret_off, 32);
+}
+
+/**
+ * A custom fake to use with the `init_rom_map` mock that returns the
+ * value of `addr`
+ */
+static const void *init_rom_map_addr_passthru(const void *addr, int size)
+{
+ return addr;
+}
+
+/** Test init function of BMI260 accelerometer and gyroscope sensors */
+ZTEST_USER(bmi260, test_bmi_init)
+{
+ struct motion_sensor_t *ms_acc, *ms_gyr;
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* The mock should return whatever is passed in to its addr param */
+ RESET_FAKE(init_rom_map);
+ init_rom_map_fake.custom_fake = init_rom_map_addr_passthru;
+
+ bmi_init_emul();
+}
+
+/** Data for custom emulator read function used in FIFO test */
+struct fifo_func_data {
+ uint16_t interrupts;
+};
+
+/**
+ * Custom emulator read function used in FIFO test. It sets interrupt registers
+ * to value passed as additional data. It sets interrupt registers to 0 after
+ * access.
+ */
+static int emul_fifo_func(const struct emul *emul, int reg, uint8_t *val,
+ int byte, void *data)
+{
+ struct fifo_func_data *d = data;
+
+ if (reg + byte == BMI260_INT_STATUS_0) {
+ bmi_emul_set_reg(emul, BMI260_INT_STATUS_0,
+ d->interrupts & 0xff);
+ d->interrupts &= 0xff00;
+ } else if (reg + byte == BMI260_INT_STATUS_1) {
+ bmi_emul_set_reg(emul, BMI260_INT_STATUS_1,
+ (d->interrupts >> 8) & 0xff);
+ d->interrupts &= 0xff;
+ }
+
+ return 1;
+}
+
+/**
+ * Run irq handler on accelerometer sensor and check if committed data in FIFO
+ * match what was set in FIFO frames in emulator.
+ */
+static void check_fifo_f(struct motion_sensor_t *ms_acc,
+ struct motion_sensor_t *ms_gyr,
+ struct bmi_emul_frame *frame, int acc_range,
+ int gyr_range, int line)
+{
+ struct ec_response_motion_sensor_data vector;
+ struct bmi_emul_frame *f_acc, *f_gyr;
+ uint32_t event = BMI_INT_EVENT;
+ uint16_t size;
+ intv3_t exp_v;
+ intv3_t ret_v;
+
+ /* Find first frame of acc and gyr type */
+ f_acc = frame;
+ while (f_acc != NULL && !(f_acc->type & BMI_EMUL_FRAME_ACC)) {
+ f_acc = f_acc->next;
+ }
+
+ f_gyr = frame;
+ while (f_gyr != NULL && !(f_gyr->type & BMI_EMUL_FRAME_GYR)) {
+ f_gyr = f_gyr->next;
+ }
+
+ /* Read FIFO in driver */
+ zassert_equal(EC_SUCCESS, ms_acc->drv->irq_handler(ms_acc, &event),
+ "Failed to read FIFO in irq handler, line %d", line);
+
+ /* Read all data committed to FIFO */
+ while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) {
+ /* Ignore timestamp frames */
+ if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) {
+ continue;
+ }
+
+ /* Check acclerometer frames */
+ if (ms_acc - motion_sensors == vector.sensor_num) {
+ if (f_acc == NULL) {
+ zassert_unreachable(
+ "Not expected acclerometer data in FIFO, line %d",
+ line);
+ }
+
+ convert_int3v_int16(vector.data, ret_v);
+ drv_acc_to_emul(ret_v, acc_range, ret_v);
+ exp_v[0] = f_acc->acc_x;
+ exp_v[1] = f_acc->acc_y;
+ exp_v[2] = f_acc->acc_z;
+ compare_int3v_f(exp_v, ret_v, V_EPS, line);
+ f_acc = f_acc->next;
+ }
+
+ /* Check gyroscope frames */
+ if (ms_gyr - motion_sensors == vector.sensor_num) {
+ if (f_gyr == NULL) {
+ zassert_unreachable(
+ "Not expected gyroscope data in FIFO, line %d",
+ line);
+ }
+
+ convert_int3v_int16(vector.data, ret_v);
+ drv_gyr_to_emul(ret_v, gyr_range, ret_v);
+ exp_v[0] = f_gyr->gyr_x;
+ exp_v[1] = f_gyr->gyr_y;
+ exp_v[2] = f_gyr->gyr_z;
+ compare_int3v_f(exp_v, ret_v, V_EPS, line);
+ f_gyr = f_gyr->next;
+ }
+ }
+
+ /* Skip frames of different type at the end */
+ while (f_acc != NULL && !(f_acc->type & BMI_EMUL_FRAME_ACC)) {
+ f_acc = f_acc->next;
+ }
+
+ while (f_gyr != NULL && !(f_gyr->type & BMI_EMUL_FRAME_GYR)) {
+ f_gyr = f_gyr->next;
+ }
+
+ /* All frames are readed */
+ zassert_is_null(f_acc, "Not all accelerometer frames are read, line %d",
+ line);
+ zassert_is_null(f_gyr, "Not all gyroscope frames are read, line %d",
+ line);
+}
+#define check_fifo(ms_acc, ms_gyr, frame, acc_range, gyr_range) \
+ check_fifo_f(ms_acc, ms_gyr, frame, acc_range, gyr_range, __LINE__)
+
+/** Test irq handler of accelerometer sensor */
+ZTEST_USER(bmi260, test_bmi_acc_fifo)
+{
+ struct motion_sensor_t *ms, *ms_gyr;
+ struct fifo_func_data func_data;
+ struct bmi_emul_frame f[3];
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ int gyr_range = 125;
+ int acc_range = 2;
+ int event;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+ ms = &motion_sensors[BMI_ACC_SENSOR_ID];
+ ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ bmi_init_emul();
+
+ /* Need to be set to collect all data in FIFO */
+ ms->oversampling_ratio = 1;
+ ms_gyr->oversampling_ratio = 1;
+ /* Only BMI event should be handled */
+ event = 0x1234 & ~BMI_INT_EVENT;
+ zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event),
+ NULL);
+
+ event = BMI_INT_EVENT;
+
+ /* Test fail to read interrupt status registers */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_INT_STATUS_0);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_INT_STATUS_1);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test no interrupt */
+ bmi_emul_set_reg(emul, BMI260_INT_STATUS_0, 0);
+ bmi_emul_set_reg(emul, BMI260_INT_STATUS_1, 0);
+
+ /* Enable sensor FIFO */
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 50000, 0), NULL);
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, NULL, acc_range, gyr_range);
+
+ /* Set custom function for FIFO test */
+ i2c_common_emul_set_read_func(common_data, emul_fifo_func, &func_data);
+ /* Set range */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, acc_range, 0), NULL);
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->set_range(ms_gyr, gyr_range, 0),
+ NULL);
+ /* Setup single accelerometer frame */
+ f[0].type = BMI_EMUL_FRAME_ACC;
+ f[0].acc_x = BMI_EMUL_1G / 10;
+ f[0].acc_y = BMI_EMUL_1G / 20;
+ f[0].acc_z = -(int)BMI_EMUL_1G / 30;
+ f[0].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second accelerometer frame */
+ f[1].type = BMI_EMUL_FRAME_ACC;
+ f[1].acc_x = -(int)BMI_EMUL_1G / 40;
+ f[1].acc_y = BMI_EMUL_1G / 50;
+ f[1].acc_z = BMI_EMUL_1G / 60;
+ f[0].next = &(f[1]);
+ f[1].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Enable sensor FIFO */
+ zassert_equal(EC_SUCCESS, ms_gyr->drv->set_data_rate(ms_gyr, 50000, 0),
+ NULL);
+
+ /* Setup first gyroscope frame (after two accelerometer frames) */
+ f[2].type = BMI_EMUL_FRAME_GYR;
+ f[2].gyr_x = -(int)BMI_EMUL_125_DEG_S / 100;
+ f[2].gyr_y = BMI_EMUL_125_DEG_S / 200;
+ f[2].gyr_z = BMI_EMUL_125_DEG_S / 300;
+ f[1].next = &(f[2]);
+ f[2].next = NULL;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second accelerometer frame to by gyroscope frame too */
+ f[1].type |= BMI_EMUL_FRAME_GYR;
+ f[1].gyr_x = -(int)BMI_EMUL_125_DEG_S / 300;
+ f[1].gyr_y = BMI_EMUL_125_DEG_S / 400;
+ f[1].gyr_z = BMI_EMUL_125_DEG_S / 500;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Skip frame should be ignored by driver */
+ bmi_emul_set_skipped_frames(emul, 8);
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Setup second frame as an config frame */
+ f[1].type = BMI_EMUL_FRAME_CONFIG;
+ /* Indicate that accelerometer range changed */
+ f[1].config = 0x1;
+ bmi_emul_append_frame(emul, f);
+ /* Setup interrupts register */
+ func_data.interrupts = BMI260_FWM_INT;
+
+ /* Trigger irq handler and check results */
+ check_fifo(ms, ms_gyr, f, acc_range, gyr_range);
+
+ /* Remove custom emulator read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+/** Test irq handler of gyroscope sensor */
+ZTEST_USER(bmi260, test_bmi_gyr_fifo)
+{
+ struct motion_sensor_t *ms;
+ uint32_t event;
+
+ ms = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ /* Interrupt shuldn't be triggered for gyroscope motion sense */
+ event = BMI_INT_EVENT;
+ zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event),
+ NULL);
+}
+
+ZTEST_USER(bmi260, test_unsupported_configs)
+{
+ /*
+ * This test checks that we properly handle passing in invalid sensor
+ * types or attempting unsupported operations on certain sensor types.
+ */
+
+ struct motion_sensor_t ms_fake;
+
+ /* Part 1:
+ * Setting offset on anything that is not an accel or gyro is an error.
+ * Make a copy of the accelerometer motion sensor struct and modify its
+ * type to magnetometer for this test.
+ */
+ memcpy(&ms_fake, &motion_sensors[BMI_ACC_SENSOR_ID], sizeof(ms_fake));
+ ms_fake.type = MOTIONSENSE_TYPE_MAG;
+
+ int16_t offset[3] = { 0 };
+ int ret =
+ ms_fake.drv->set_offset(&ms_fake, (const int16_t *)&offset, 0);
+ zassert_equal(
+ ret, EC_RES_INVALID_PARAM,
+ "Expected a return code of %d (EC_RES_INVALID_PARAM) but got %d",
+ EC_RES_INVALID_PARAM, ret);
+
+ /* Part 2:
+ * Running a calibration on a magnetometer is also not supported.
+ */
+ memcpy(&ms_fake, &motion_sensors[BMI_ACC_SENSOR_ID], sizeof(ms_fake));
+ ms_fake.type = MOTIONSENSE_TYPE_MAG;
+
+ ret = ms_fake.drv->perform_calib(&ms_fake, 1);
+ zassert_equal(
+ ret, EC_RES_INVALID_PARAM,
+ "Expected a return code of %d (EC_RES_INVALID_PARAM) but got %d",
+ EC_RES_INVALID_PARAM, ret);
+}
+
+ZTEST_USER(bmi260, test_interrupt_handler)
+{
+ /* The accelerometer interrupt handler simply sets an event flag for the
+ * motion sensing task. Make sure that flag starts cleared, fire the
+ * interrupt, and ensure the flag is set.
+ */
+
+ atomic_t *mask;
+
+ mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE);
+ zassert_true(mask != NULL,
+ "Got a null pointer when getting event bitmap.");
+ zassert_true((*mask & CONFIG_ACCELGYRO_BMI260_INT_EVENT) == 0,
+ "Event flag is set before firing interrupt");
+
+ bmi260_interrupt(0);
+
+ mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE);
+ zassert_true(mask != NULL,
+ "Got a null pointer when getting event bitmap.");
+ zassert_true(*mask & CONFIG_ACCELGYRO_BMI260_INT_EVENT,
+ "Event flag is not set after firing interrupt");
+}
+
+ZTEST_USER(bmi260, test_bmi_init_chip_id)
+{
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bmi_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+
+ /* Part 1:
+ * Error occurs while reading the chip ID
+ */
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_CHIP_ID);
+ int ret = ms_acc->drv->init(ms_acc);
+
+ zassert_equal(ret, EC_ERROR_UNKNOWN,
+ "Expected %d (EC_ERROR_UNKNOWN) but got %d",
+ EC_ERROR_UNKNOWN, ret);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Part 2:
+ * Test cases where the returned chip ID does not match what is
+ * expected. This involves overriding values in the motion_sensor
+ * struct, so make a copy first.
+ */
+ struct motion_sensor_t ms_fake;
+
+ memcpy(&ms_fake, ms_acc, sizeof(ms_fake));
+
+ /* Part 2a: expecting MOTIONSENSE_CHIP_BMI220 but get BMI260's chip ID!
+ */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI260_CHIP_ID_MAJOR);
+ ms_fake.chip = MOTIONSENSE_CHIP_BMI220;
+
+ ret = ms_fake.drv->init(&ms_fake);
+ zassert_equal(ret, EC_ERROR_ACCESS_DENIED,
+ "Expected %d (EC_ERROR_ACCESS_DENIED) but got %d",
+ EC_ERROR_ACCESS_DENIED, ret);
+
+ /* Part 2b: expecting MOTIONSENSE_CHIP_BMI260 but get BMI220's chip ID!
+ */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI220_CHIP_ID_MAJOR);
+ ms_fake.chip = MOTIONSENSE_CHIP_BMI260;
+
+ ret = ms_fake.drv->init(&ms_fake);
+ zassert_equal(ret, EC_ERROR_ACCESS_DENIED,
+ "Expected %d (EC_ERROR_ACCESS_DENIED) but got %d",
+ EC_ERROR_ACCESS_DENIED, ret);
+
+ /* Part 2c: use an invalid expected chip */
+ ms_fake.chip = MOTIONSENSE_CHIP_MAX;
+
+ ret = ms_fake.drv->init(&ms_fake);
+ zassert_equal(ret, EC_ERROR_ACCESS_DENIED,
+ "Expected %d (EC_ERROR_ACCESS_DENIED) but got %d",
+ EC_ERROR_ACCESS_DENIED, ret);
+}
+
+/* Make an I2C emulator mock wrapped in FFF */
+FAKE_VALUE_FUNC(int, bmi_config_load_no_mapped_flash_mock_read_fn,
+ const struct emul *, int, uint8_t *, int, void *);
+struct i2c_common_emul_data *common_data;
+static int bmi_config_load_no_mapped_flash_mock_read_fn_helper(
+ const struct emul *emul, int reg, uint8_t *val, int bytes, void *data)
+{
+ if (reg == BMI260_INTERNAL_STATUS && val) {
+ /* We want to force-return a status of 'initialized' when this
+ * is read.
+ */
+ *val = BMI260_INIT_OK;
+ return 0;
+ }
+ /* For other registers, go through the normal emulator route */
+ return 1;
+}
+
+ZTEST_USER(bmi260, test_bmi_config_load_no_mapped_flash)
+{
+ /* Tests the situation where we load BMI config data when flash memory
+ * is not mapped (basically what occurs when `init_rom_map()` in
+ * `bmi_config_load()` returns NULL)
+ */
+
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ struct motion_sensor_t *ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ int ret, num_status_reg_reads;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+
+ /* Force bmi_config_load() to have to manually copy from memory */
+ RESET_FAKE(init_rom_map);
+ init_rom_map_fake.return_val = NULL;
+
+ /* Force init_rom_copy() to succeed */
+ RESET_FAKE(init_rom_copy);
+ init_rom_copy_fake.return_val = 0;
+
+ /* Set proper chip ID and raise the INIT_OK flag to signal that config
+ * succeeded.
+ */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI260_CHIP_ID_MAJOR);
+ i2c_common_emul_set_read_func(
+ common_data, bmi_config_load_no_mapped_flash_mock_read_fn,
+ NULL);
+ RESET_FAKE(bmi_config_load_no_mapped_flash_mock_read_fn);
+ bmi_config_load_no_mapped_flash_mock_read_fn_fake.custom_fake =
+ bmi_config_load_no_mapped_flash_mock_read_fn_helper;
+
+ /* Part 1: successful path */
+ ret = ms_acc->drv->init(ms_acc);
+
+ zassert_equal(ret, EC_RES_SUCCESS, "Got %d but expected %d", ret,
+ EC_RES_SUCCESS);
+
+ /* Check the number of times we accessed BMI260_INTERNAL_STATUS */
+ num_status_reg_reads = MOCK_COUNT_CALLS_WITH_ARG_VALUE(
+ bmi_config_load_no_mapped_flash_mock_read_fn_fake, 1,
+ BMI260_INTERNAL_STATUS);
+ zassert_equal(1, num_status_reg_reads,
+ "Accessed status reg %d times but expected %d.",
+ num_status_reg_reads, 1);
+
+ /* Part 2: write to `BMI260_INIT_ADDR_0` fails */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_INIT_ADDR_0);
+
+ ret = ms_acc->drv->init(ms_acc);
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Got %d but expected %d",
+ ret, EC_ERROR_INVALID_CONFIG);
+
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Part 3: init_rom_copy() fails w/ a non-zero return code of 255. */
+ init_rom_copy_fake.return_val = 255;
+
+ ret = ms_acc->drv->init(ms_acc);
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Got %d but expected %d",
+ ret, EC_ERROR_INVALID_CONFIG);
+
+ init_rom_copy_fake.return_val = 0;
+
+ /* Part 4: write to `BMI260_INIT_DATA` fails */
+ i2c_common_emul_set_write_fail_reg(common_data, BMI260_INIT_DATA);
+
+ ret = ms_acc->drv->init(ms_acc);
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Got %d but expected %d",
+ ret, EC_ERROR_INVALID_CONFIG);
+
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Cleanup */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+ZTEST_USER(bmi260, test_bmi_config_unsupported_chip)
+{
+ /* Test what occurs when we try to configure a chip that is
+ * turned off in Kconfig (BMI220). This test assumes that
+ * CONFIG_ACCELGYRO_BMI220 is NOT defined.
+ */
+
+#if defined(CONFIG_ACCELGYRO_BMI220)
+#error "Test test_bmi_config_unsupported_chip will not work properly with " \
+ "CONFIG_ACCELGYRO_BMI220 defined."
+#endif
+
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ struct motion_sensor_t ms_fake;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+
+ /* Set up struct and emaulator to be a BMI220 chip, which
+ * `bmi_config_load()` does not support in the current configuration
+ */
+
+ memcpy(&ms_fake, &motion_sensors[BMI_ACC_SENSOR_ID], sizeof(ms_fake));
+ ms_fake.chip = MOTIONSENSE_CHIP_BMI220;
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI220_CHIP_ID_MAJOR);
+
+ int ret = ms_fake.drv->init(&ms_fake);
+
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Expected %d but got %d",
+ EC_ERROR_INVALID_CONFIG, ret);
+}
+
+ZTEST_USER(bmi260, test_init_config_read_failure)
+{
+ /* Test proper response to a failed read from the register
+ * BMI260_INTERNAL_STATUS.
+ */
+
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ struct motion_sensor_t *ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ int ret;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+
+ /* Set up i2c emulator and mocks */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI260_CHIP_ID_MAJOR);
+ i2c_common_emul_set_read_fail_reg(common_data, BMI260_INTERNAL_STATUS);
+ RESET_FAKE(init_rom_map);
+ init_rom_map_fake.custom_fake = init_rom_map_addr_passthru;
+
+ ret = ms_acc->drv->init(ms_acc);
+
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Expected %d but got %d",
+ EC_ERROR_INVALID_CONFIG, ret);
+}
+
+/* Mock read function and counter used to test the timeout when
+ * waiting for the chip to initialize
+ */
+static int timeout_test_status_reg_access_count;
+static int status_timeout_mock_read_fn(const struct emul *emul, int reg,
+ uint8_t *val, int bytes, void *data)
+{
+ if (reg == BMI260_INTERNAL_STATUS && val) {
+ /* We want to force-return a non-OK status each time */
+ timeout_test_status_reg_access_count++;
+ *val = BMI260_INIT_ERR;
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+ZTEST_USER(bmi260, test_init_config_status_timeout)
+{
+ /* We allow up to 15 tries to get a successful BMI260_INIT_OK
+ * value from the BMI260_INTERNAL_STATUS register. Make sure
+ * we properly handle the case where the chip is not initialized
+ * before the timeout.
+ */
+
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ struct motion_sensor_t *ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ int ret;
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+
+ /* Set up i2c emulator and mocks */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI260_CHIP_ID_MAJOR);
+ timeout_test_status_reg_access_count = 0;
+ i2c_common_emul_set_read_func(common_data, status_timeout_mock_read_fn,
+ NULL);
+ RESET_FAKE(init_rom_map);
+ init_rom_map_fake.custom_fake = init_rom_map_addr_passthru;
+
+ ret = ms_acc->drv->init(ms_acc);
+
+ zassert_equal(timeout_test_status_reg_access_count, 15,
+ "Expected %d attempts but counted %d", 15,
+ timeout_test_status_reg_access_count);
+ zassert_equal(ret, EC_ERROR_INVALID_CONFIG, "Expected %d but got %d",
+ EC_ERROR_INVALID_CONFIG, ret);
+}
+
+/**
+ * @brief Put the driver and emulator in to a consistent state before each test.
+ *
+ * @param arg Test fixture (unused)
+ */
+static void bmi260_test_before(void *arg)
+{
+ ARG_UNUSED(arg);
+
+ const struct emul *emul = EMUL_DT_GET(BMI_NODE);
+ struct i2c_common_emul_data *common_data;
+ struct motion_sensor_t *ms_acc = &motion_sensors[BMI_ACC_SENSOR_ID];
+ struct motion_sensor_t *ms_gyr = &motion_sensors[BMI_GYR_SENSOR_ID];
+
+ common_data = emul_bmi_get_i2c_common_data(emul);
+
+ /* Reset I2C */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+
+ /* Reset local fakes(s) */
+ RESET_FAKE(bmi_config_load_no_mapped_flash_mock_read_fn);
+
+ /* Clear rotation matrices */
+ ms_acc->rot_standard_ref = NULL;
+ ms_gyr->rot_standard_ref = NULL;
+
+ /* Set Chip ID register to BMI260 (required for init() to succeed) */
+ bmi_emul_set_reg(emul, BMI260_CHIP_ID, BMI260_CHIP_ID_MAJOR);
+}
+
+ZTEST_SUITE(bmi260, drivers_predicate_pre_main, NULL, bmi260_test_before, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/charge_manager.c b/zephyr/test/drivers/default/src/charge_manager.c
new file mode 100644
index 0000000000..85048178ae
--- /dev/null
+++ b/zephyr/test/drivers/default/src/charge_manager.c
@@ -0,0 +1,58 @@
+/* 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 "charge_manager.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(charge_manager, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+/**
+ * Test the default implementation of board_fill_source_power_info(). The fill
+ * function should reset all the power info values. If the test binary overrides
+ * board_fill_source_power_info(), then this test can be removed.
+ */
+ZTEST_USER(charge_manager, test_default_fill_power_info)
+{
+ struct ec_response_usb_pd_power_info info = {
+ .meas = {
+ .voltage_now = 10,
+ .voltage_max = 10,
+ .current_max = 10,
+ .current_lim = 10,
+ },
+ .max_power = 10,
+ };
+
+ board_fill_source_power_info(0, &info);
+ zassert_equal(info.meas.voltage_now, 0, NULL);
+ zassert_equal(info.meas.voltage_max, 0, NULL);
+ zassert_equal(info.meas.current_max, 0, NULL);
+ zassert_equal(info.meas.current_lim, 0, NULL);
+ zassert_equal(info.max_power, 0, NULL);
+}
+
+/**
+ * Test the default implementation of board_charge_port_is_connected(). This
+ * function should always return 1 regardless of input.
+ */
+ZTEST_USER(charge_manager, test_default_charge_port_is_connected)
+{
+ zassert_true(board_charge_port_is_connected(-1), NULL);
+ zassert_true(board_charge_port_is_connected(0), NULL);
+ zassert_true(board_charge_port_is_connected(1), NULL);
+ zassert_true(board_charge_port_is_connected(500), NULL);
+}
+
+ZTEST_USER(charge_manager, test_default_charge_port_is_sink)
+{
+ zassert_true(board_charge_port_is_sink(-1), NULL);
+ zassert_true(board_charge_port_is_sink(0), NULL);
+ zassert_true(board_charge_port_is_sink(1), NULL);
+ zassert_true(board_charge_port_is_sink(500), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console.c b/zephyr/test/drivers/default/src/console.c
new file mode 100644
index 0000000000..c74fd3ea1c
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console.c
@@ -0,0 +1,88 @@
+/* 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/shell/shell_dummy.h>
+
+#include "builtin/stdio.h"
+#include "test/drivers/test_state.h"
+#include "console.h"
+#include "uart.h"
+#include "ec_commands.h"
+
+ZTEST_USER(console, printf_overflow)
+{
+ char buffer[10];
+
+ zassert_equal(-EC_ERROR_OVERFLOW,
+ crec_snprintf(buffer, 4, "1234567890"), NULL);
+ zassert_equal(0, strcmp(buffer, "123"), "got '%s'", buffer);
+ zassert_equal(-EC_ERROR_OVERFLOW,
+ crec_snprintf(buffer, 4, "%%%%%%%%%%"), NULL);
+ zassert_equal(0, strcmp(buffer, "%%%"), "got '%s'", buffer);
+}
+
+/* This test is identical to test_buf_notify_null in
+ * test/console_edit.c. Please keep them in sync to verify that
+ * uart_console_read_buffer works identically in legacy EC and zephyr.
+ */
+ZTEST_USER(console, buf_notify_null)
+{
+ char buffer[100];
+ uint16_t write_count;
+ size_t consumed_count;
+
+ /* Flush the console buffer before we start. */
+ zassert_ok(uart_console_read_buffer_init(), NULL);
+
+ /* Write a nul char to the buffer. */
+ consumed_count = console_buf_notify_chars("ab\0c", 4);
+
+ /* Check if all bytes were consumed by console buffer */
+ zassert_equal(consumed_count, 4, "got %d", consumed_count);
+
+ /* Check if the nul is present in the buffer. */
+ zassert_ok(uart_console_read_buffer_init(), NULL);
+ zassert_ok(uart_console_read_buffer(CONSOLE_READ_RECENT, buffer,
+ sizeof(buffer), &write_count),
+ NULL);
+ zassert_equal(0, strncmp(buffer, "abc", 4), "got '%s'", buffer);
+ zassert_equal(write_count, 4, "got %d", write_count);
+}
+
+static const char *large_string =
+ "This is a very long string, it will cause a buffer flush at "
+ "some point while printing to the shell. Long long text. Blah "
+ "blah. Long long text. Blah blah. Long long text. Blah blah.";
+ZTEST_USER(console, shell_fprintf_full)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ zassert_true(strlen(large_string) >=
+ shell_zephyr->fprintf_ctx->buffer_size,
+ "large_string is too short, fix test.");
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+ shell_fprintf(shell_zephyr, SHELL_NORMAL, "%s", large_string);
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_true(strncmp(outbuffer, large_string, strlen(large_string)) ==
+ 0,
+ "Invalid console output %s", outbuffer);
+}
+
+ZTEST_USER(console, cprint_too_big)
+{
+ zassert_true(strlen(large_string) >= CONFIG_SHELL_PRINTF_BUFF_SIZE,
+ "buffer is too short, fix test.");
+
+ zassert_equal(cprintf(CC_COMMAND, "%s", large_string),
+ -EC_ERROR_OVERFLOW, NULL);
+}
+
+ZTEST_SUITE(console, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelinfo.c b/zephyr/test/drivers/default/src/console_cmd/accelinfo.c
new file mode 100644
index 0000000000..11638fcc70
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelinfo.c
@@ -0,0 +1,55 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "config.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "timer.h"
+
+static void console_cmd_accelinfo_after(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ shell_execute_cmd(get_ec_shell(), "accelinfo off");
+}
+
+ZTEST_SUITE(console_cmd_accelinfo, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_accelinfo_after, NULL);
+
+ZTEST_USER(console_cmd_accelinfo, test_too_many_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelinfo arg1 arg2");
+
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelinfo, test_print_once)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelinfo"), NULL);
+}
+
+ZTEST_USER(console_cmd_accelinfo, test_invalid_arg)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelinfo bar");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelinfo, test_enable_disable)
+{
+ /*
+ * There's no way to verify what is being printed to the console yet, so
+ * just assert that the command executed and returned 0.
+ */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelinfo on"), NULL);
+ k_msleep(CONFIG_MOTION_MIN_SENSE_WAIT_TIME * MSEC * 2);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelinfo off"), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelinit.c b/zephyr/test/drivers/default/src/console_cmd/accelinit.c
new file mode 100644
index 0000000000..c440faebba
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelinit.c
@@ -0,0 +1,93 @@
+/* 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/fff.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "accelgyro.h"
+#include "console.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+FAKE_VALUE_FUNC(int, mock_init, struct motion_sensor_t *);
+
+struct console_cmd_accelinit_fixture {
+ const struct accelgyro_drv *sensor_0_drv;
+ struct accelgyro_drv mock_drv;
+};
+
+static void *console_cmd_accelinit_setup(void)
+{
+ static struct console_cmd_accelinit_fixture fixture = {
+ .mock_drv = {
+ .init = mock_init,
+ },
+ };
+ fixture.sensor_0_drv = motion_sensors[0].drv;
+
+ return &fixture;
+}
+
+static void console_cmd_accelinit_before(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ RESET_FAKE(mock_init);
+ FFF_RESET_HISTORY();
+}
+static void console_cmd_accelinit_after(void *fixture)
+{
+ struct console_cmd_accelinit_fixture *this = fixture;
+
+ motion_sensors[0].drv = this->sensor_0_drv;
+ motion_sensors[0].drv->init(&motion_sensors[0]);
+}
+
+ZTEST_SUITE(console_cmd_accelinit, drivers_predicate_post_main,
+ console_cmd_accelinit_setup, console_cmd_accelinit_before,
+ console_cmd_accelinit_after, NULL);
+
+ZTEST_USER(console_cmd_accelinit, test_invalid_sensor_num)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelinit f");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelinit -1");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelinit 100");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelinit, test_state_was_set)
+{
+ motion_sensors[0].state = SENSOR_INIT_ERROR;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelinit 0"), NULL);
+ zassert_equal(SENSOR_INITIALIZED, motion_sensors[0].state,
+ "Expected %d, but got %d", SENSOR_INITIALIZED,
+ motion_sensors[0].state);
+}
+
+ZTEST_USER_F(console_cmd_accelinit, test_fail_3_times)
+{
+ mock_init_fake.return_val = 1;
+ motion_sensors[0].drv = &fixture->mock_drv;
+ motion_sensors[0].state = SENSOR_INITIALIZED;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelinit 0"), NULL);
+ zassert_equal(3, mock_init_fake.call_count,
+ "Expected 3 calls, but got %d",
+ mock_init_fake.call_count);
+ zassert_equal(SENSOR_INIT_ERROR, motion_sensors[0].state,
+ "Expected %d, but got %d", SENSOR_INIT_ERROR,
+ motion_sensors[0].state);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelrange.c b/zephyr/test/drivers/default/src/console_cmd/accelrange.c
new file mode 100644
index 0000000000..ff9d03bfe2
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelrange.c
@@ -0,0 +1,118 @@
+/* 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/shell/shell.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "driver/accel_bma2x2.h"
+#include "ec_commands.h"
+#include "emul/emul_bma255.h"
+#include "emul/emul_common_i2c.h"
+#include "i2c.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+
+#define EMUL_NODE DT_NODELABEL(bma_emul)
+
+#define BMA_ORD DT_DEP_ORD(EMUL_LABEL)
+
+static void console_cmd_accelrange_after(void *fixture)
+{
+ const struct emul *emul = EMUL_DT_GET(EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+
+ ARG_UNUSED(fixture);
+ shell_execute_cmd(get_ec_shell(), "accelrange 0 2");
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_SUITE(console_cmd_accelrange, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_accelrange_after, NULL);
+
+ZTEST_USER(console_cmd_accelrange, test_num_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange 0 1 2 3");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_bad_sensor_num)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange t");
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange -1");
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange 100");
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_print_range)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrange 0"), NULL);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_set_invalid_range)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelrange 0 t");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_set_range_round_up_implicit)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrange 0 3"), NULL);
+ zassert_equal(motion_sensors[0].current_range, 4,
+ "Expected 4, but got %d",
+ motion_sensors[0].current_range);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_set_range_round_up_explicit)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrange 0 3 1"), NULL);
+ zassert_equal(motion_sensors[0].current_range, 4,
+ "Expected 4, but got %d",
+ motion_sensors[0].current_range);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_set_range_round_down)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrange 0 5 0"), NULL);
+ zassert_equal(motion_sensors[0].current_range, 4,
+ "Expected 4, but got %d",
+ motion_sensors[0].current_range);
+}
+
+ZTEST_USER(console_cmd_accelrange, test_i2c_error)
+{
+ const struct emul *emul = EMUL_DT_GET(EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_bma_get_i2c_common_data(emul);
+ int rv;
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ BMA2x2_RANGE_SELECT_ADDR);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrange 0 3");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelrate.c b/zephyr/test/drivers/default/src/console_cmd/accelrate.c
new file mode 100644
index 0000000000..59482ed866
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelrate.c
@@ -0,0 +1,104 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+static int original_sensor_0_s0_config_odr;
+
+static void *console_cmd_accelrate_setup(void)
+{
+ original_sensor_0_s0_config_odr =
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr;
+ return NULL;
+}
+
+static void console_cmd_accelrate_after(void *state)
+{
+ ARG_UNUSED(state);
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr =
+ original_sensor_0_s0_config_odr;
+}
+
+ZTEST_SUITE(console_cmd_accelrate, drivers_predicate_post_main,
+ console_cmd_accelrate_setup, NULL, console_cmd_accelrate_after,
+ NULL);
+
+ZTEST_USER(console_cmd_accelrate, test_bad_arg_count)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrate");
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrate 1 2 3 4");
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelrate, test_invalid_sensor_num)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrate f");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrate -1");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelrate 100");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelrate, test_print_rate)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrate 0"), NULL);
+}
+
+ZTEST_USER(console_cmd_accelrate, test_bad_rate_value)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelrate 0 f");
+
+ zassert_equal(EC_ERROR_PARAM2, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_accelrate, test_set_ap_rate)
+{
+ test_set_chipset_to_s0();
+
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr = 0;
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrate 0 100"), NULL);
+ zassert_equal(100 | ROUND_UP_FLAG,
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr,
+ "Expected %d, but got %d", 100 | ROUND_UP_FLAG,
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr);
+
+ /* Try explicit round up value: 1 */
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr = 0;
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrate 0 100 1"),
+ NULL);
+ zassert_equal(100 | ROUND_UP_FLAG,
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr,
+ "Expected %d, but got %d", 100 | ROUND_UP_FLAG,
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr);
+
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr = 0;
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelrate 0 100 0"),
+ NULL);
+ zassert_equal(100, motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr,
+ "Expected %d, but got %d", 100 | ROUND_UP_FLAG,
+ motion_sensors[0].config[SENSOR_CONFIG_EC_S0].odr);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelread.c b/zephyr/test/drivers/default/src/console_cmd/accelread.c
new file mode 100644
index 0000000000..81ebf87e55
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelread.c
@@ -0,0 +1,124 @@
+/* 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/fff.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "accelgyro.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+FAKE_VALUE_FUNC(int, mock_read, const struct motion_sensor_t *, int *);
+FAKE_VALUE_FUNC(int, mock_set_data_rate, const struct motion_sensor_t *, int,
+ int);
+FAKE_VALUE_FUNC(int, mock_get_data_rate, const struct motion_sensor_t *);
+
+struct console_cmd_accelread_fixture {
+ const struct accelgyro_drv *sensor_0_drv;
+ struct accelgyro_drv mock_drv;
+};
+
+static void *console_cmd_accelread_setup(void)
+{
+ static struct console_cmd_accelread_fixture fixture = {
+ .mock_drv = {
+ .read = mock_read,
+ /*
+ * Data rate functions are required so that motion_sense
+ * task doesn't segfault.
+ */
+ .set_data_rate = mock_set_data_rate,
+ .get_data_rate = mock_get_data_rate,
+ },
+ };
+ fixture.sensor_0_drv = motion_sensors[0].drv;
+
+ return &fixture;
+}
+
+static void console_cmd_accelread_before(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ RESET_FAKE(mock_read);
+ RESET_FAKE(mock_set_data_rate);
+ RESET_FAKE(mock_get_data_rate);
+ FFF_RESET_HISTORY();
+}
+
+static void console_cmd_accelread_after(void *fixture)
+{
+ struct console_cmd_accelread_fixture *this = fixture;
+
+ motion_sensors[0].drv = this->sensor_0_drv;
+}
+
+ZTEST_SUITE(console_cmd_accelread, drivers_predicate_pre_main,
+ console_cmd_accelread_setup, console_cmd_accelread_before,
+ console_cmd_accelread_after, NULL);
+
+ZTEST_USER(console_cmd_accelread, test_too_few_arguments)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelread");
+
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelread, test_invalid_sensor_num)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelread f");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelread -1");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelread 100");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+static struct console_cmd_accelread_fixture *current_fixture;
+
+int mock_read_call_super(const struct motion_sensor_t *s, int *v)
+{
+ return current_fixture->sensor_0_drv->read(s, v);
+}
+
+ZTEST_USER_F(console_cmd_accelread, test_read)
+{
+ current_fixture = fixture;
+ mock_read_fake.custom_fake = mock_read_call_super;
+ mock_get_data_rate_fake.return_val = 100;
+ motion_sensors[0].drv = &fixture->mock_drv;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelread 0"), NULL);
+ zassert_equal(1, mock_read_fake.call_count,
+ "Expected only 1 call to read, but got %d",
+ mock_read_fake.call_count);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelread 0 2"), NULL);
+ zassert_equal(3, mock_read_fake.call_count,
+ "Expected only 3 call to read, but got %d",
+ mock_read_fake.call_count);
+}
+
+ZTEST_USER_F(console_cmd_accelread, test_read_fail)
+{
+ mock_read_fake.return_val = 1;
+ motion_sensors[0].drv = &fixture->mock_drv;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelread 0"), NULL);
+ zassert_equal(1, mock_read_fake.call_count,
+ "Expected only 1 call to read, but got %d",
+ mock_read_fake.call_count);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelres.c b/zephyr/test/drivers/default/src/console_cmd/accelres.c
new file mode 100644
index 0000000000..5e29a0572d
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelres.c
@@ -0,0 +1,127 @@
+/* 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/fff.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "accelgyro.h"
+#include "console.h"
+#include "driver/accel_bma2x2.h"
+#include "ec_commands.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+
+FAKE_VALUE_FUNC(int, set_resolution, const struct motion_sensor_t *, int, int);
+
+struct console_cmd_accelres_fixture {
+ const struct accelgyro_drv *sensor_0_drv;
+ struct accelgyro_drv mock_drv;
+};
+
+void *console_cmd_accelres_setup(void)
+{
+ static struct console_cmd_accelres_fixture fixture = {
+ .mock_drv = {
+ .set_resolution = set_resolution,
+ },
+ };
+
+ fixture.sensor_0_drv = motion_sensors[0].drv;
+
+ return &fixture;
+}
+
+void console_cmd_accelres_before(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ RESET_FAKE(set_resolution);
+ FFF_RESET_HISTORY();
+}
+
+void console_cmd_accelres_after(void *fixture)
+{
+ struct console_cmd_accelres_fixture *this = fixture;
+
+ motion_sensors[0].drv = this->sensor_0_drv;
+}
+
+ZTEST_SUITE(console_cmd_accelres, drivers_predicate_post_main,
+ console_cmd_accelres_setup, NULL, console_cmd_accelres_after, NULL);
+
+ZTEST_USER(console_cmd_accelres, test_too_few_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelres");
+
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelres, test_too_many_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelres 1 2 3 4");
+
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelres, test_invalid_sensor_num)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelres f");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelres -1");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelres 100");
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelres, test_print_res)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelres 0"), NULL);
+}
+
+ZTEST_USER(console_cmd_accelres, test_set_res__invalid_data)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelres 0 f");
+
+ zassert_equal(EC_ERROR_PARAM2, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_accelres, test_set_res__no_setter)
+{
+ int resolution;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelres 0 4"), NULL);
+ resolution = motion_sensors[0].drv->get_resolution(&motion_sensors[0]);
+ zassert_equal(BMA2x2_RESOLUTION, resolution, "Expected %d, but got %d",
+ BMA2x2_RESOLUTION, resolution);
+}
+
+ZTEST_USER_F(console_cmd_accelres, test_set_res__bad_res_value)
+{
+ int rv;
+
+ set_resolution_fake.return_val = EC_ERROR_INVAL;
+ motion_sensors[0].drv = &fixture->mock_drv;
+ rv = shell_execute_cmd(get_ec_shell(), "accelres 0 0");
+ zassert_equal(EC_ERROR_PARAM2, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_accelres, test_invalid_rounding_arg)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelres 0 12 f");
+
+ zassert_equal(EC_ERROR_PARAM3, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM3, rv);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/accelspoof.c b/zephyr/test/drivers/default/src/console_cmd/accelspoof.c
new file mode 100644
index 0000000000..3e183ca296
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/accelspoof.c
@@ -0,0 +1,97 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "motion_sense.h"
+#include "test/drivers/test_state.h"
+
+static void console_cmd_accelspoof_after(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ shell_execute_cmd(get_ec_shell(), "accelspoof 0 off");
+ motion_sensors[0].spoof_xyz[0] = 0;
+ motion_sensors[0].spoof_xyz[1] = 0;
+ motion_sensors[0].spoof_xyz[2] = 0;
+}
+
+ZTEST_SUITE(console_cmd_accelspoof, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_accelspoof_after, NULL);
+
+ZTEST_USER(console_cmd_accelspoof, test_too_few_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelspoof");
+
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_invalid_sensor_id)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelspoof -1");
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "accelspoof 100");
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_print_mode)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelspoof 0"), NULL);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_invalid_boolean)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelspoof 0 bar");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_enable_disable)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelspoof 0 on"), NULL);
+ zassert_true(motion_sensors[0].flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE,
+ NULL);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelspoof 0 off"), NULL);
+ zassert_false(motion_sensors[0].flags & MOTIONSENSE_FLAG_IN_SPOOF_MODE,
+ NULL);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_wrong_num_axis_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "accelspoof 0 on 1");
+
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_enable_explicit_values)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelspoof 0 on 1 2 3"),
+ NULL);
+ zassert_equal(1, motion_sensors[0].spoof_xyz[0], NULL);
+ zassert_equal(2, motion_sensors[0].spoof_xyz[1], NULL);
+ zassert_equal(3, motion_sensors[0].spoof_xyz[2], NULL);
+}
+
+ZTEST_USER(console_cmd_accelspoof, test_enable_implicit_values)
+{
+ motion_sensors[0].raw_xyz[0] = 4;
+ motion_sensors[0].raw_xyz[1] = 5;
+ motion_sensors[0].raw_xyz[2] = 6;
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "accelspoof 0 on"), NULL);
+ zassert_equal(4, motion_sensors[0].spoof_xyz[0], NULL);
+ zassert_equal(5, motion_sensors[0].spoof_xyz[1], NULL);
+ zassert_equal(6, motion_sensors[0].spoof_xyz[2], NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/adc.c b/zephyr/test/drivers/default/src/console_cmd/adc.c
new file mode 100644
index 0000000000..85dfda939a
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/adc.c
@@ -0,0 +1,43 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/* Default adc command, lists out channels */
+ZTEST_USER(console_cmd_adc, test_adc_noname)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "adc"),
+ "Failed default print");
+}
+
+/* adc with named channels */
+ZTEST_USER(console_cmd_adc, test_adc_named_channels)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "adc charger"),
+ "Failed to get charger adc channel.");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "adc ddr-soc"),
+ "Failed to get ddr-soc adc channel.");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "adc fan"),
+ "Failed to get fan adc channel.");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "adc psys"),
+ "Failed to get psys adc channel.");
+}
+
+/* adc with unknown channel */
+ZTEST_USER(console_cmd_adc, test_adc_wrong_name)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "adc fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_SUITE(console_cmd_adc, NULL, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/battery.c b/zephyr/test/drivers/default/src/console_cmd/battery.c
new file mode 100644
index 0000000000..9c3e21fcf1
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/battery.c
@@ -0,0 +1,90 @@
+/* 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/emul.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "battery_smart.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_smart_battery.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+struct console_cmd_battery_fixture {
+ const struct emul *emul;
+ struct i2c_common_emul_data *i2c_emul;
+};
+
+static void *console_cmd_battery_setup(void)
+{
+ static struct console_cmd_battery_fixture fixture = {
+ .emul = EMUL_DT_GET(DT_NODELABEL(battery)),
+ };
+
+ fixture.i2c_emul = emul_smart_battery_get_i2c_common_data(fixture.emul);
+
+ return &fixture;
+}
+
+static void console_cmd_battery_after(void *f)
+{
+ struct console_cmd_battery_fixture *fixture = f;
+
+ i2c_common_emul_set_read_fail_reg(fixture->i2c_emul,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+/* Default battery command */
+ZTEST_USER(console_cmd_battery, test_battery_default)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery"),
+ "Failed default print");
+}
+
+ZTEST_USER_F(console_cmd_battery, test_battery_status_i2c_error)
+{
+ /* Force a failure on the battery i2c write to SB_BATTERY_STATUS */
+ i2c_common_emul_set_read_fail_reg(fixture->i2c_emul, SB_BATTERY_STATUS);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery"),
+ "Failed default print");
+}
+
+/* Battery command with repeat */
+ZTEST_USER(console_cmd_battery, test_battery_repeat)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery 2"),
+ "Failed default print");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery 8"),
+ "Failed default print");
+}
+
+/* Battery command with repeat and sleep */
+ZTEST_USER(console_cmd_battery, test_battery_repeat_sleep)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery 2 400"),
+ "Failed default print");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "battery 8 200"),
+ "Failed default print");
+}
+
+/* Battery command with invalid repeat and sleep */
+ZTEST_USER(console_cmd_battery, test_battery_bad_repeat_sleep)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "battery fish 400");
+
+ zassert_equal(rv, EC_ERROR_INVAL, "Expected %d, but got %d",
+ EC_ERROR_INVAL, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "battery 2 fish");
+
+ zassert_equal(rv, EC_ERROR_INVAL, "Expected %d, but got %d",
+ EC_ERROR_INVAL, rv);
+}
+
+ZTEST_SUITE(console_cmd_battery, drivers_predicate_post_main,
+ console_cmd_battery_setup, NULL, console_cmd_battery_after, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/button.c b/zephyr/test/drivers/default/src/console_cmd/button.c
new file mode 100644
index 0000000000..9272b2ce2d
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/button.c
@@ -0,0 +1,67 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_button, test_button_no_arg)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "button");
+
+ zassert_equal(EC_ERROR_PARAM_COUNT, rv, "Expected %d, returned %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_button, test_button_vup)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "button vup a");
+
+ zassert_equal(EC_ERROR_PARAM2, rv, "Expected %d, returned %d",
+ EC_ERROR_PARAM2, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "button vup 50");
+
+ zassert_ok(rv, "Expected %d, returned %d", EC_SUCCESS, rv);
+}
+
+ZTEST_USER(console_cmd_button, test_button_vdown)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "button vdown a");
+
+ zassert_equal(EC_ERROR_PARAM2, rv, "Expected %d, returned %d",
+ EC_ERROR_PARAM2, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "button vdown 50");
+
+ zassert_ok(rv, "Expected %d, returned %d", EC_SUCCESS, rv);
+}
+
+ZTEST_USER(console_cmd_button, test_button_rec)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "button rec 50");
+
+ if (IS_ENABLED(CONFIG_DEDICATED_RECOVERY_BUTTON)) {
+ zassert_ok(rv, "Expected %d, returned %d", EC_SUCCESS, rv);
+ } else {
+ /* Recovery button does not exist */
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, returned %d",
+ EC_ERROR_PARAM1, rv);
+ }
+}
+
+ZTEST_SUITE(console_cmd_button, NULL, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/cbi.c b/zephyr/test/drivers/default/src/console_cmd/cbi.c
new file mode 100644
index 0000000000..495ffd7e4c
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/cbi.c
@@ -0,0 +1,81 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_state.h"
+
+static void set_wp(bool value)
+{
+ const struct gpio_dt_spec *wp = GPIO_DT_FROM_NODELABEL(gpio_wp_l);
+
+ gpio_pin_set_dt(wp, value);
+}
+
+static void before(void *unused)
+{
+ /* Ensure eeprom is ready */
+ set_wp(false);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "cbi remove 42 init"),
+ NULL);
+}
+
+static void after(void *unused)
+{
+ /* re-enable WP */
+ set_wp(true);
+}
+
+ZTEST_SUITE(console_cmd_cbi, drivers_predicate_post_main, NULL, before, after,
+ NULL);
+
+ZTEST_USER(console_cmd_cbi, test_base)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "cbi"), NULL);
+}
+
+ZTEST_USER(console_cmd_cbi, test_wp)
+{
+ set_wp(true);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi remove 42"), NULL);
+}
+
+ZTEST_USER(console_cmd_cbi, test_remove)
+{
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi remove"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "cbi remove 42"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi remove abc"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi remove 42 1"), NULL);
+}
+
+ZTEST_USER(console_cmd_cbi, test_set)
+{
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi set"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi set 10"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi set 11 1"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "cbi set 12 1 4"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi set 13 1 4 4"),
+ NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi set 14 1 10"), NULL);
+}
+
+ZTEST_USER(console_cmd_cbi, test_extra)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(),
+ "cbi remove 42 skip_write"),
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "cbi remove 42 init"),
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(),
+ "cbi remove 42 init skip_write"),
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(),
+ "cbi remove 42 skip_write init"),
+ NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "cbi remove 42 extra"),
+ NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/charge_manager.c b/zephyr/test/drivers/default/src/console_cmd/charge_manager.c
new file mode 100644
index 0000000000..f6ee049ea1
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/charge_manager.c
@@ -0,0 +1,118 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "charge_manager.h"
+#include "console.h"
+#include "emul/emul_isl923x.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_tcpci_partner_snk.h"
+#include "tcpm/tcpci.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+struct console_cmd_charge_manager_fixture {
+ struct tcpci_partner_data sink_5v_3a;
+ struct tcpci_snk_emul_data sink_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static void *console_cmd_charge_manager_setup(void)
+{
+ static struct console_cmd_charge_manager_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 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.sink_ext, &test_fixture.sink_5v_3a, NULL);
+ test_fixture.sink_ext.pdo[1] =
+ PDO_FIXED(5000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &test_fixture;
+}
+
+static void console_cmd_charge_manager_after(void *state)
+{
+ struct console_cmd_charge_manager_fixture *fixture = state;
+
+ shell_execute_cmd(get_ec_shell(), "chgoverride -1");
+ disconnect_sink_from_port(fixture->tcpci_emul);
+}
+
+ZTEST_SUITE(console_cmd_charge_manager, drivers_predicate_post_main,
+ console_cmd_charge_manager_setup, NULL,
+ console_cmd_charge_manager_after, NULL);
+
+/**
+ * Test the chgsup (charge supplier info) command. This command only prints to
+ * console some information which is not yet possible to verify. So just check
+ * that the console command ran successfully.
+ */
+ZTEST_USER(console_cmd_charge_manager, test_chgsup)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgsup"), NULL);
+}
+
+/**
+ * Test chgoverride command with no arguments. This should just print the
+ * current override port.
+ */
+ZTEST_USER(console_cmd_charge_manager, test_chgoverride_missing_port)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgoverride"), NULL);
+}
+
+ZTEST_USER(console_cmd_charge_manager, test_chgoverride_off_from_off)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgoverride -1"), NULL);
+ zassert_equal(charge_manager_get_override(), OVERRIDE_OFF, NULL);
+}
+
+ZTEST_USER(console_cmd_charge_manager, test_chgoverride_disable_from_off)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgoverride -2"), NULL);
+ zassert_equal(charge_manager_get_override(), OVERRIDE_DONT_CHARGE,
+ NULL);
+}
+
+ZTEST_USER(console_cmd_charge_manager, test_chgoverride_0_from_off)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgoverride 0"), NULL);
+ zassert_equal(charge_manager_get_override(), 0, NULL);
+}
+
+ZTEST_USER_F(console_cmd_charge_manager, test_chgoverride_0_from_sink)
+{
+ 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));
+
+ connect_sink_to_port(&fixture->sink_5v_3a, fixture->tcpci_emul,
+ fixture->charger_emul);
+ zassert_equal(shell_execute_cmd(get_ec_shell(), "chgoverride 0"),
+ EC_ERROR_INVAL, NULL);
+}
+
+ZTEST_USER(console_cmd_charge_manager, test_chgoverride_invalid_port)
+{
+ char cmd[256];
+
+ zassume_true(sprintf(cmd, "chgoverride %d", CHARGE_PORT_COUNT) > 0,
+ NULL);
+ zassert_equal(shell_execute_cmd(get_ec_shell(), cmd), EC_ERROR_PARAM1,
+ NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/charge_state.c b/zephyr/test/drivers/default/src/console_cmd/charge_state.c
new file mode 100644
index 0000000000..d5dc9fe415
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/charge_state.c
@@ -0,0 +1,282 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "charge_state.h"
+#include "charge_state_v2.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_charge_state, test_idle_too_few_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate idle");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_idle_arg_not_a_bool)
+{
+ int rv;
+
+ /*
+ * There are many strings that will fail parse_bool(), just test one to
+ * test the code path in the command, other tests for parse_bool are
+ * done in the respective unit test.
+ */
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate idle g");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_idle_on__no_ac)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate idle on");
+ zassert_equal(rv, EC_ERROR_NOT_POWERED, "Expected %d, but got %d",
+ EC_ERROR_NOT_POWERED, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_discharge_on__no_ac)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate discharge on");
+ zassert_equal(rv, EC_ERROR_NOT_POWERED, "Expected %d, but got %d",
+ EC_ERROR_NOT_POWERED, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_discharge_too_few_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate discharge");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_discharge_arg_not_a_bool)
+{
+ int rv;
+
+ /*
+ * There are many strings that will fail parse_bool(), just test one to
+ * test the code path in the command, other tests for parse_bool are
+ * done in the respective unit test.
+ */
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate discharge g");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_debug_too_few_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate debug");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_debug_arg_not_bool)
+{
+ int rv;
+
+ /*
+ * There are many strings that will fail parse_bool(), just test one to
+ * test the code path in the command, other tests for parse_bool are
+ * done in the respective unit test.
+ */
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate debug g");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_debug_on)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate debug on"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_debug_on_show_charging_progress)
+{
+ /*
+ * Force reset the previous display charge so the charge state task
+ * prints on the next iteration.
+ */
+ reset_prev_disp_charge();
+ charging_progress_displayed();
+
+ /* Enable debug printing */
+ zassume_ok(shell_execute_cmd(get_ec_shell(), "chgstate debug on"),
+ NULL);
+
+ /* Sleep at least 1 full iteration of the charge state loop */
+ k_sleep(K_USEC(CHARGE_MAX_SLEEP_USEC + 1));
+
+ zassert_true(charging_progress_displayed(), NULL);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_sustain_too_few_args__2_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate sustain");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_sustain_too_few_args__3_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "chgstate sustain 5");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_sustain_invalid_params)
+{
+ /* Verify that lower bound is less than upper bound */
+ zassert_equal(shell_execute_cmd(get_ec_shell(),
+ "chgstate sustain 50 30"),
+ EC_ERROR_INVAL, NULL);
+
+ /* Verify that lower bound is at least 0 (when upper bound is given) */
+ zassert_equal(shell_execute_cmd(get_ec_shell(),
+ "chgstate sustain -5 30"),
+ EC_ERROR_INVAL, NULL);
+
+ /* Verify that upper bound is at most 100 */
+ zassert_equal(shell_execute_cmd(get_ec_shell(),
+ "chgstate sustain 50 101"),
+ EC_ERROR_INVAL, NULL);
+}
+
+struct console_cmd_charge_state_fixture {
+ struct tcpci_partner_data source_5v_3a;
+ struct tcpci_src_emul_data source_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static void *console_cmd_charge_state_setup(void)
+{
+ static struct console_cmd_charge_state_fixture fixture;
+
+ /* Get references for the emulators */
+ fixture.tcpci_emul = EMUL_GET_USBC_BINDING(0, tcpc);
+ fixture.charger_emul = EMUL_GET_USBC_BINDING(0, chg);
+
+ /* Initialized the source to supply 5V and 3A */
+ tcpci_partner_init(&fixture.source_5v_3a, PD_REV20);
+ fixture.source_5v_3a.extensions = tcpci_src_emul_init(
+ &fixture.source_ext, &fixture.source_5v_3a, NULL);
+ fixture.source_ext.pdo[1] =
+ PDO_FIXED(5000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &fixture;
+}
+
+static void console_cmd_charge_state_after(void *data)
+{
+ struct console_cmd_charge_state_fixture *fixture = data;
+
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ shell_execute_cmd(get_ec_shell(), "chgstate debug off");
+ shell_execute_cmd(get_ec_shell(), "chgstate sustain -1 -1");
+}
+
+ZTEST_SUITE(console_cmd_charge_state, drivers_predicate_post_main,
+ console_cmd_charge_state_setup, NULL,
+ console_cmd_charge_state_after, NULL);
+
+ZTEST_USER_F(console_cmd_charge_state, test_idle_on_from_normal)
+{
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+
+ /* Verify that we're in "normal" mode */
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+
+ /* Move to idle */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate idle on"), NULL);
+ zassert_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_IDLE, NULL);
+}
+
+ZTEST_USER_F(console_cmd_charge_state, test_normal_from_idle)
+{
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+
+ /* Verify that we're in "normal" mode */
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+
+ /* Move to idle */
+ zassume_ok(shell_execute_cmd(get_ec_shell(), "chgstate idle on"), NULL);
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_IDLE, NULL);
+
+ /* Move back to normal */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate idle off"),
+ NULL);
+ zassert_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+}
+
+ZTEST_USER_F(console_cmd_charge_state, test_discharge_on)
+{
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+
+ /* Verify that we're in "normal" mode */
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+
+ /* Enable discharge */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate discharge on"),
+ NULL);
+ zassert_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_DISCHARGE, NULL);
+}
+
+ZTEST_USER_F(console_cmd_charge_state, test_discharge_off)
+{
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+
+ /* Verify that we're in "normal" mode */
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+
+ /* Enable discharge */
+ zassume_ok(shell_execute_cmd(get_ec_shell(), "chgstate discharge on"),
+ NULL);
+ zassume_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_DISCHARGE, NULL);
+
+ /* Disable discharge */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate discharge off"),
+ NULL);
+ zassert_equal(get_chg_ctrl_mode(), CHARGE_CONTROL_NORMAL, NULL);
+}
+
+ZTEST_USER(console_cmd_charge_state, test_sustain)
+{
+ struct ec_response_charge_control charge_control_values;
+
+ /* Verify that lower bound is less than upper bound */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "chgstate sustain 30 50"),
+ NULL);
+
+ charge_control_values = host_cmd_charge_control(
+ CHARGE_CONTROL_NORMAL, EC_CHARGE_CONTROL_CMD_GET);
+ zassert_equal(charge_control_values.sustain_soc.lower, 30, NULL);
+ zassert_equal(charge_control_values.sustain_soc.upper, 50, NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/charger.c b/zephyr/test/drivers/default/src/console_cmd/charger.c
new file mode 100644
index 0000000000..9adda29a8d
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/charger.c
@@ -0,0 +1,184 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "dptf.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/* Tests which need no fixture */
+ZTEST_USER(console_cmd_charger, test_default_dump)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger"),
+ "Failed default print");
+}
+
+ZTEST_USER(console_cmd_charger, test_good_index)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger 0"),
+ "Failed index 0 print");
+}
+
+/* Bad parameter tests */
+ZTEST_USER(console_cmd_charger, test_bad_index)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger 55");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_charger, test_bad_command)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_charger, test_bad_input_current)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger input fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_charger, test_bad_current)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger current fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_charger, test_bad_voltage)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger voltage fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_charger, test_bad_dptf_current)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "charger dptf fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+/* Good parameter sub-command tests */
+ZTEST_USER(console_cmd_charger, test_good_input_current)
+{
+ int input_current;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger input 1000"),
+ "Failed to set input current");
+ zassume_ok(charger_get_input_current_limit(0, &input_current),
+ "Failed to get input current");
+ zassert_equal(input_current, 1000,
+ "Input current not set in charger: %d", input_current);
+}
+
+ZTEST_USER(console_cmd_charger, test_good_dptf)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger dptf 1000"),
+ "Failed to set dptf current");
+ zassert_equal(dptf_get_charging_current_limit(), 1000,
+ "Unexpected dptf current");
+}
+
+ZTEST_USER(console_cmd_charger, test_unsupported_dump)
+{
+ /* Must define CONFIG_CMD_CHARGER_DUMP for this sub-command */
+ int rv = shell_execute_cmd(get_ec_shell(), "charger dump");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+/* Fixture needed to supply AC for manual current/voltage set */
+struct console_cmd_charger_fixture {
+ struct tcpci_partner_data source_5v_3a;
+ struct tcpci_src_emul_data source_ext;
+ const struct emul *tcpci_emul;
+ const struct emul *charger_emul;
+};
+
+static void *console_cmd_charger_setup(void)
+{
+ static struct console_cmd_charger_fixture fixture;
+
+ /* Assume we have one charger at index 0 */
+ zassume_true(board_get_charger_chip_count() > 0,
+ "Insufficient chargers found");
+
+ /* Get references for the emulators */
+ fixture.tcpci_emul = EMUL_DT_GET(DT_NODELABEL(tcpci_emul));
+ fixture.charger_emul = EMUL_DT_GET(DT_NODELABEL(isl923x_emul));
+
+ /* Initialized the source to supply 5V and 3A */
+ tcpci_partner_init(&fixture.source_5v_3a, PD_REV20);
+ fixture.source_5v_3a.extensions = tcpci_src_emul_init(
+ &fixture.source_ext, &fixture.source_5v_3a, NULL);
+ fixture.source_ext.pdo[1] =
+ PDO_FIXED(5000, 3000, PDO_FIXED_UNCONSTRAINED);
+
+ return &fixture;
+}
+
+static void console_cmd_charger_after(void *data)
+{
+ struct console_cmd_charger_fixture *fixture = data;
+
+ /* Disconnect the source, and ensure we reset charge params */
+ disconnect_source_from_port(fixture->tcpci_emul, fixture->charger_emul);
+ host_cmd_charge_control(CHARGE_CONTROL_NORMAL,
+ EC_CHARGE_CONTROL_CMD_SET);
+}
+
+/* Tests that need the fixture */
+ZTEST_USER_F(console_cmd_charger, test_good_current)
+{
+ int current;
+
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger current 1000"),
+ "Failed to set current");
+
+ /* Give the charger task time to pick up the manual current */
+ k_sleep(K_SECONDS(1));
+
+ zassume_ok(charger_get_current(0, &current), "Failed to get current");
+ zassert_equal(current, 1000, "Current not set in charger: %d", current);
+}
+
+ZTEST_USER_F(console_cmd_charger, test_good_voltage)
+{
+ int voltage;
+
+ /* Connect a source so we start charging */
+ connect_source_to_port(&fixture->source_5v_3a, &fixture->source_ext, 1,
+ fixture->tcpci_emul, fixture->charger_emul);
+ /* Note: select a fake voltage larger than the charger's minimum */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "charger voltage 3000"),
+ "Failed to set voltage");
+
+ /* Give the charger task time to pick up the manual voltage */
+ k_sleep(K_SECONDS(1));
+
+ zassume_ok(charger_get_voltage(0, &voltage), "Failed to get voltage");
+ zassert_equal(voltage, 3000, "Voltage not set in charger: %d", voltage);
+}
+
+ZTEST_SUITE(console_cmd_charger, drivers_predicate_post_main,
+ console_cmd_charger_setup, NULL, console_cmd_charger_after, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/crash.c b/zephyr/test/drivers/default/src/console_cmd/crash.c
new file mode 100644
index 0000000000..bc0b5d0254
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/crash.c
@@ -0,0 +1,34 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "builtin/assert.h"
+#include "console.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(console_cmd_crash, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_USER(console_cmd_crash, test_wrong_num_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "crash");
+
+ zassert_equal(EC_ERROR_PARAM1, rv, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_crash, test_assert)
+{
+ int rv;
+
+ RESET_FAKE(assert_post_action);
+ rv = shell_execute_cmd(get_ec_shell(), "crash assert");
+
+ zassert_equal(EC_ERROR_UNKNOWN, rv, NULL);
+ zassert_equal(1, assert_post_action_fake.call_count, NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/cutoff.c b/zephyr/test/drivers/default/src/console_cmd/cutoff.c
new file mode 100644
index 0000000000..00ce40660f
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/cutoff.c
@@ -0,0 +1,86 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "battery.h"
+#include "console.h"
+#include "ec_commands.h"
+#include "hooks.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+static void console_cmd_cutoff_after(void *unused)
+{
+ ARG_UNUSED(unused);
+ set_ac_enabled(true);
+ hook_notify(HOOK_AC_CHANGE);
+ k_msleep(500);
+}
+
+ZTEST_SUITE(console_cmd_cutoff, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_cutoff_after, NULL);
+
+ZTEST_USER(console_cmd_cutoff, test_sb_cutoff)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "cutoff");
+
+ zassert_equal(EC_RES_SUCCESS, rv, "Expected %d, but got %d",
+ EC_RES_SUCCESS, rv);
+ zassert_true(battery_is_cut_off(), NULL);
+}
+
+ZTEST_USER(console_cmd_cutoff, test_invalid_arg1)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "cutoff bad_arg");
+
+ zassert_equal(EC_ERROR_INVAL, rv, "Expected %d, but got %d",
+ EC_ERROR_INVAL, rv);
+ zassert_false(battery_is_cut_off(), NULL);
+}
+
+ZTEST_USER(console_cmd_cutoff, test_at_shutdown)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "cutoff at-shutdown");
+
+ zassert_equal(EC_RES_SUCCESS, rv, "Expected %d, but got %d",
+ EC_RES_SUCCESS, rv);
+ zassert_false(battery_is_cut_off(), NULL);
+ hook_notify(HOOK_CHIPSET_SHUTDOWN);
+ zassert_true(WAIT_FOR(battery_is_cut_off(), 1500000, k_msleep(250)),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_cutoff, test_clear_pending_shutdown)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "cutoff at-shutdown");
+
+ zassume_true(extpower_is_present(), NULL);
+ zassert_equal(EC_RES_SUCCESS, rv, "Expected %d, but got %d",
+ EC_RES_SUCCESS, rv);
+
+ /* Triggering the AC_CHANGE hook will cancel the pending cutoff */
+ hook_notify(HOOK_AC_CHANGE);
+
+ /* The shutdown will no longer cutoff the battery */
+ hook_notify(HOOK_CHIPSET_SHUTDOWN);
+ zassert_false(WAIT_FOR(battery_is_cut_off(), 1500000, k_msleep(250)),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_cutoff, test_ac_change_exits_cutoff)
+{
+ int rv;
+
+ set_ac_enabled(false);
+
+ rv = shell_execute_cmd(get_ec_shell(), "cutoff");
+ zassert_equal(EC_RES_SUCCESS, rv, "Expected %d, but got %d",
+ EC_RES_SUCCESS, rv);
+
+ set_ac_enabled(true);
+ zassert_false(battery_is_cut_off(), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/gpio.c b/zephyr/test/drivers/default/src/console_cmd/gpio.c
new file mode 100644
index 0000000000..164f272e27
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/gpio.c
@@ -0,0 +1,37 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_gpio, test_read_invoke_success)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "gpioget test"), NULL);
+}
+
+ZTEST_USER(console_cmd_gpio, test_read_invoke_fail)
+{
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "gpioget DOES_NOT_EXIST"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_gpio, test_set_gpio)
+{
+ const struct gpio_dt_spec *gp = GPIO_DT_FROM_NODELABEL(gpio_test);
+
+ zassert_ok(gpio_pin_set_dt(gp, 0), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "gpioset test 1"), NULL);
+ zassert_equal(gpio_pin_get_dt(gp), 1, NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "gpioset test 0"), NULL);
+ zassert_equal(gpio_pin_get_dt(gp), 0, NULL);
+}
+
+ZTEST_SUITE(console_cmd_gpio, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/hcdebug.c b/zephyr/test/drivers/default/src/console_cmd/hcdebug.c
new file mode 100644
index 0000000000..71adb02690
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/hcdebug.c
@@ -0,0 +1,49 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+
+static void console_cmd_hcdebug_after(void *fixture)
+{
+ ARG_UNUSED(fixture);
+ shell_execute_cmd(get_ec_shell(), "hcdebug off");
+}
+
+ZTEST_SUITE(console_cmd_hcdebug, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_hcdebug_after, NULL);
+
+ZTEST_USER(console_cmd_hcdebug, test_too_many_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "hcdebug arg1 arg2");
+
+ zassert_not_equal(rv, EC_SUCCESS, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_hcdebug, test_no_args)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hcdebug"), NULL);
+}
+
+ZTEST_USER(console_cmd_hcdebug, test_invalid_arg)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "hcdebug bar");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_hcdebug, test_valid_args)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hcdebug off"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hcdebug normal"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hcdebug every"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hcdebug params"), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/hibdelay.c b/zephyr/test/drivers/default/src/console_cmd/hibdelay.c
new file mode 100644
index 0000000000..c72a2bf66a
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/hibdelay.c
@@ -0,0 +1,37 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(console_cmd_hibdelay, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_USER(console_cmd_hibdelay, test_too_many_args)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hibdelay 1 2"), NULL);
+}
+
+ZTEST_USER(console_cmd_hibdelay, test_no_args)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hibdelay"), NULL);
+}
+
+ZTEST_USER(console_cmd_hibdelay, test_invalid_arg)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "hibdelay 3.4");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_USER(console_cmd_hibdelay, test_valid_args)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hibdelay 5"), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/hostevent.c b/zephyr/test/drivers/default/src/console_cmd/hostevent.c
new file mode 100644
index 0000000000..af9b37edd1
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/hostevent.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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "include/lpc.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+#ifdef CONFIG_HOST_EVENT64
+#define HOSTEVENT_PRINT_FORMAT "016" PRIx64
+#else
+#define HOSTEVENT_PRINT_FORMAT "08" PRIx32
+#endif
+
+struct console_cmd_hostevent_fixture {
+ struct host_events_ctx ctx;
+};
+
+static void *console_cmd_hostevent_setup(void)
+{
+ static struct console_cmd_hostevent_fixture fixture = { 0 };
+
+ return &fixture;
+}
+
+static void console_cmd_hostevent_before(void *fixture)
+{
+ struct console_cmd_hostevent_fixture *f = fixture;
+
+ host_events_save(&f->ctx);
+}
+
+static void console_cmd_hostevent_after(void *fixture)
+{
+ struct console_cmd_hostevent_fixture *f = fixture;
+
+ host_events_restore(&f->ctx);
+}
+
+static int console_cmd_hostevent(const char *subcommand, host_event_t mask)
+{
+ int rv;
+ char cmd_buf[CONFIG_SHELL_CMD_BUFF_SIZE];
+
+ rv = snprintf(cmd_buf, CONFIG_SHELL_CMD_BUFF_SIZE,
+ "hostevent %s 0x%" HOSTEVENT_PRINT_FORMAT, subcommand,
+ mask);
+
+ zassume_between_inclusive(rv, 0, CONFIG_SHELL_CMD_BUFF_SIZE,
+ "hostevent console command too long");
+
+ return shell_execute_cmd(get_ec_shell(), cmd_buf);
+}
+
+/* hostevent with no arguments */
+ZTEST_USER(console_cmd_hostevent, test_hostevent)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "hostevent"),
+ "Failed default print");
+}
+
+/* hostevent with invalid arguments */
+ZTEST_USER(console_cmd_hostevent, test_hostevent_invalid)
+{
+ int rv;
+ host_event_t mask = 0;
+
+ /* Test invalid sub-command */
+ rv = console_cmd_hostevent("invalid", mask);
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ /* Test invalid mask */
+ rv = shell_execute_cmd(get_ec_shell(), "hostevent set invalid-mask");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+/* hostevent with sub-commands and verification */
+ZTEST_USER(console_cmd_hostevent, test_hostevent_sub_commands)
+{
+ int rv;
+ enum ec_status ret_val;
+ host_event_t event_mask;
+ host_event_t all_events = 0;
+ host_event_t set_events;
+ struct ec_response_host_event result = { 0 };
+ struct {
+ enum lpc_host_event_type type;
+ const char *name;
+ host_event_t mask;
+ } subcommand[] = {
+ {
+ .type = LPC_HOST_EVENT_SMI,
+ .name = "SMI",
+ .mask = EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_CLOSED),
+ },
+ {
+ .type = LPC_HOST_EVENT_SCI,
+ .name = "SCI",
+ .mask = EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN),
+ },
+ {
+ .type = LPC_HOST_EVENT_WAKE,
+ .name = "WAKE",
+ .mask = EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON),
+ },
+ {
+ .type = LPC_HOST_EVENT_ALWAYS_REPORT,
+ .name = "ALWAYS_REPORT",
+ .mask = EC_HOST_EVENT_MASK(
+ EC_HOST_EVENT_AC_DISCONNECTED),
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(subcommand); i++) {
+ event_mask = lpc_get_host_event_mask(subcommand[i].type);
+ zassert_false(event_mask & subcommand[i].mask,
+ "%s mask is set before test started",
+ subcommand[i].name);
+ /*
+ * Setting mask value overwrites existing setting, so OR in
+ * the test bit.
+ */
+ event_mask |= subcommand[i].mask;
+ rv = console_cmd_hostevent(subcommand[i].name, event_mask);
+ zassert_ok(rv, "Subcommand %s failed", subcommand[i].name);
+ zassert_true(lpc_get_host_event_mask(subcommand[i].type) &
+ subcommand[i].mask,
+ "Failed to set %s event mask", subcommand[i].name);
+
+ /*
+ * It is only valid to set host events, once at least one mask
+ * value includes the event. Setting host events preserves
+ * existing events.
+ */
+ zassert_false(host_get_events() & subcommand[i].mask,
+ "Host event is set before test started");
+ rv = console_cmd_hostevent("set", subcommand[i].mask);
+ zassert_ok(rv, "Subcommand SET failed");
+
+ all_events |= subcommand[i].mask;
+ }
+
+ /* Verify all host events were set, and none were lost */
+ zassert_true((host_get_events() & all_events) == all_events,
+ "Failed to set host events");
+
+ /* Test clearing of host events */
+ set_events = all_events;
+ for (int i = 0; i < ARRAY_SIZE(subcommand); i++) {
+ set_events &= ~subcommand[i].mask;
+ rv = console_cmd_hostevent("clear", subcommand[i].mask);
+ zassert_ok(rv, "Subcommand CLEAR failed");
+
+ zassert_true((host_get_events() & set_events) == set_events,
+ "Failed to clear host event");
+ }
+
+ /* Verify the backup host events were set, and none were cleared */
+ ret_val = host_cmd_host_event(EC_HOST_EVENT_GET, EC_HOST_EVENT_B,
+ &result);
+ zassert_equal(ret_val, EC_RES_SUCCESS, "Expected=%d, returned=%d",
+ EC_RES_SUCCESS, ret_val);
+ zassert_true((result.value & all_events) == all_events,
+ "Failed to set host events backup");
+
+ /* Test clearing of backup host events */
+ set_events = all_events;
+ for (int i = 0; i < ARRAY_SIZE(subcommand); i++) {
+ set_events &= ~subcommand[i].mask;
+ rv = console_cmd_hostevent("clearb", subcommand[i].mask);
+ zassert_ok(rv, "Subcommand CLEAR failed");
+
+ ret_val = host_cmd_host_event(EC_HOST_EVENT_GET,
+ EC_HOST_EVENT_B, &result);
+ zassert_equal(ret_val, EC_RES_SUCCESS,
+ "Expected=%d, returned=%d", EC_RES_SUCCESS,
+ ret_val);
+ zassert_true((result.value & set_events) == set_events,
+ "Failed to clear host events backup");
+ }
+}
+
+ZTEST_SUITE(console_cmd_hostevent, drivers_predicate_post_main,
+ console_cmd_hostevent_setup, console_cmd_hostevent_before,
+ console_cmd_hostevent_after, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/i2c_portmap.c b/zephyr/test/drivers/default/src/console_cmd/i2c_portmap.c
new file mode 100644
index 0000000000..4b2ec548a2
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/i2c_portmap.c
@@ -0,0 +1,27 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(console_cmd_i2c_portmap, drivers_predicate_post_main, NULL, NULL,
+ NULL, NULL);
+
+ZTEST_USER(console_cmd_i2c_portmap, test_too_many_args)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "i2c_portmap arg1");
+
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_i2c_portmap, test_get_i2c_portmap)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "i2c_portmap"), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/md.c b/zephyr/test/drivers/default/src/console_cmd/md.c
new file mode 100644
index 0000000000..c8c3e2c130
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/md.c
@@ -0,0 +1,83 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(console_cmd_md, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_USER(console_cmd_md, test_too_few_args)
+{
+ zassert_equal(EC_ERROR_PARAM_COUNT,
+ shell_execute_cmd(get_ec_shell(), "md"), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_error_param1)
+{
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "md .j"), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_error_bad_address)
+{
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "md not_an_address"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_default_count)
+{
+ uint8_t memory[] = { 0x01, 0x02, 0x03, 0x04 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "md %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_count_arg)
+{
+ uint8_t memory[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "md %" PRIuPTR " 2", (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_byte_format)
+{
+ uint8_t memory[] = { 0x01, 0x02, 0x03, 0x04 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "md .b %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_half_format)
+{
+ uint8_t memory[] = { 0x01, 0x02, 0x03, 0x04 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "md .h %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
+
+ZTEST_USER(console_cmd_md, test_string_format)
+{
+ char memory[] = "hello world";
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "md .s %" PRIuPTR " 12", (uintptr_t)memory) !=
+ 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/panic_output.c b/zephyr/test/drivers/default/src/console_cmd/panic_output.c
new file mode 100644
index 0000000000..7cc809e835
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/panic_output.c
@@ -0,0 +1,71 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "panic.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/* Test panicinfo when a panic hasn't occurred */
+ZTEST_USER(console_cmd_panic_output, test_panicinfo)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "panicinfo"),
+ "Failed default print");
+}
+
+/* Test panicinfo when a panic hasn't occurred with an extra arg. */
+/* Should return successfully. */
+ZTEST_USER(console_cmd_panic_output, test_panicinfo_bad_arg)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "panicinfo fish"),
+ "Failed default print with a bad argument");
+}
+
+/* Fixture needed to save panic data state */
+struct console_cmd_panic_output_fixture {
+ struct panic_data *p_data;
+ struct panic_data cpy_data;
+};
+
+static void *console_cmd_panic_setup(void)
+{
+ static struct console_cmd_panic_output_fixture fixture;
+
+ return &fixture;
+}
+
+static void console_cmd_panic_before(void *data)
+{
+ struct console_cmd_panic_output_fixture *fixture = data;
+
+ fixture->p_data = get_panic_data_write();
+ fixture->cpy_data = *fixture->p_data;
+}
+
+static void console_cmd_panic_after(void *data)
+{
+ struct console_cmd_panic_output_fixture *fixture = data;
+
+ struct panic_data *p_data = fixture->p_data;
+
+ *p_data = fixture->cpy_data;
+}
+
+/* Tests that need the fixture */
+ZTEST_USER_F(console_cmd_panic_output, test_panicinfo_with_panic)
+{
+ fixture->p_data->flags = 0x1;
+ fixture->p_data->struct_size = CONFIG_PANIC_DATA_SIZE;
+ fixture->p_data->magic = PANIC_DATA_MAGIC;
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "panicinfo"),
+ "Failed to print details about panic.");
+}
+
+ZTEST_SUITE(console_cmd_panic_output, NULL, console_cmd_panic_setup,
+ console_cmd_panic_before, console_cmd_panic_after, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/port80.c b/zephyr/test/drivers/default/src/console_cmd/port80.c
new file mode 100644
index 0000000000..792895eb27
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/port80.c
@@ -0,0 +1,46 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief Unit Tests for ESPI port 80 console command
+ */
+
+#include <zephyr/logging/log.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "port80.h"
+
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/**
+ * @brief TestPurpose: Verify port 80 console commands
+ *
+ * @details
+ * Validate that the port 80 console commands work.
+ *
+ * Expected Results
+ * - The port 80 console commands return the appropriate result
+ */
+ZTEST(port80, test_port80_console)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "port80"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "port80 flush"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "port80 scroll"), NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "port80 intprint"), NULL);
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "port80 unknown_param"),
+ NULL);
+}
+
+/**
+ * @brief Test Suite: Verifies port 80 console commands.
+ */
+ZTEST_SUITE(console_cmd_port80, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/power_button.c b/zephyr/test/drivers/default/src/console_cmd/power_button.c
new file mode 100644
index 0000000000..92d0aeaf78
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/power_button.c
@@ -0,0 +1,34 @@
+/* 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 <console.h>
+
+ZTEST_SUITE(console_cmd_power_button, NULL, NULL, NULL, NULL, NULL);
+
+ZTEST_USER(console_cmd_power_button, test_return_ok)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "powerbtn"), NULL);
+}
+
+ZTEST_USER(console_cmd_power_button, test_negative_delay)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "powerbtn -1");
+
+ zassert_not_equal(rv, EC_SUCCESS,
+ "Command should error on negative delay");
+}
+
+ZTEST_USER(console_cmd_power_button, test_invalid_arg)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "powerbtn foo");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/powerindebug.c b/zephyr/test/drivers/default/src/console_cmd/powerindebug.c
new file mode 100644
index 0000000000..9f52a9b569
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/powerindebug.c
@@ -0,0 +1,36 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_powerindebug, test_no_params)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "powerindebug"),
+ "Failed to get debug mask");
+}
+
+ZTEST_USER(console_cmd_powerindebug, test_good_params)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "powerindebug 0x10"),
+ "Failed to set debug mask");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "powerindebug 0"),
+ "Failed to set debug mask");
+}
+
+ZTEST_USER(console_cmd_powerindebug, test_bad_params)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "powerindebug fish");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_SUITE(console_cmd_powerindebug, NULL, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/rtc.c b/zephyr/test/drivers/default/src/console_cmd/rtc.c
new file mode 100644
index 0000000000..80530129af
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/rtc.c
@@ -0,0 +1,73 @@
+/* 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 "console.h"
+#include "ec_commands.h"
+#include "system.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_rtc, test_rtc_no_arg)
+{
+ char expected_buffer[32];
+ uint32_t sec = 7;
+
+ snprintf(expected_buffer, sizeof(expected_buffer),
+ "RTC: 0x%08x (%d.00 s)", sec, sec);
+
+ system_set_rtc(sec);
+
+ CHECK_CONSOLE_CMD("rtc", expected_buffer, EC_SUCCESS);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_invalid)
+{
+ CHECK_CONSOLE_CMD("rtc set", NULL, EC_ERROR_INVAL);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_set)
+{
+ char command[32];
+ char expected_buffer[32];
+ uint32_t sec = 48879;
+
+ snprintf(expected_buffer, sizeof(expected_buffer),
+ "RTC: 0x%08x (%d.00 s)", sec, sec);
+ snprintf(command, sizeof(command), "rtc set %d", sec);
+
+ CHECK_CONSOLE_CMD(command, expected_buffer, EC_SUCCESS);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_set_bad)
+{
+ CHECK_CONSOLE_CMD("rtc set t", NULL, EC_ERROR_PARAM2);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_alarm_no_args)
+{
+ CHECK_CONSOLE_CMD("rtc_alarm", "Setting RTC alarm", EC_SUCCESS);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_alarm_good_args)
+{
+ CHECK_CONSOLE_CMD("rtc_alarm 1", "Setting RTC alarm", EC_SUCCESS);
+ CHECK_CONSOLE_CMD("rtc_alarm 1 5", "Setting RTC alarm", EC_SUCCESS);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_alarm_bad_args)
+{
+ CHECK_CONSOLE_CMD("rtc_alarm t", NULL, EC_ERROR_PARAM1);
+ CHECK_CONSOLE_CMD("rtc_alarm 1 t", NULL, EC_ERROR_PARAM2);
+}
+
+ZTEST_USER(console_cmd_rtc, test_rtc_alarm_reset)
+{
+ CHECK_CONSOLE_CMD("rtc_alarm 0", "Setting RTC alarm", EC_SUCCESS);
+ CHECK_CONSOLE_CMD("rtc_alarm 0 0", "Setting RTC alarm", EC_SUCCESS);
+}
+
+ZTEST_SUITE(console_cmd_rtc, NULL, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/rw.c b/zephyr/test/drivers/default/src/console_cmd/rw.c
new file mode 100644
index 0000000000..2bf59b30d5
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/rw.c
@@ -0,0 +1,98 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(console_cmd_rw, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_USER(console_cmd_rw, test_too_few_args)
+{
+ zassert_equal(EC_ERROR_PARAM_COUNT,
+ shell_execute_cmd(get_ec_shell(), "rw"), NULL);
+}
+
+ZTEST_USER(console_cmd_rw, test_error_param1)
+{
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "rw .j"), NULL);
+}
+
+ZTEST_USER(console_cmd_rw, test_error_bad_address)
+{
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "rw not_an_address"),
+ NULL);
+ zassert_equal(EC_ERROR_PARAM2,
+ shell_execute_cmd(get_ec_shell(), "rw .b not_an_address"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_rw, test_read)
+{
+ uint8_t memory[] = { 0x01, 0x02, 0x03, 0x04 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "rw .b %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+
+ zassume_true(sprintf(cmd, "rw .h %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+
+ zassume_true(sprintf(cmd, "rw %" PRIuPTR, (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+}
+
+ZTEST_USER(console_cmd_rw, test_write_invalid_value)
+{
+ zassert_equal(EC_ERROR_PARAM2,
+ shell_execute_cmd(get_ec_shell(), "rw 0 not-a-value"),
+ NULL);
+ zassert_equal(EC_ERROR_PARAM3,
+ shell_execute_cmd(get_ec_shell(), "rw .b 0 not-a-value"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_rw, test_write)
+{
+ uint8_t memory[4] = { 0 };
+ char cmd[128] = { 0 };
+
+ zassume_true(sprintf(cmd, "rw .b %" PRIuPTR " 1", (uintptr_t)memory) !=
+ 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+ zassert_equal(1, memory[0], "memory[0] was %u", memory[0]);
+ zassert_equal(0, memory[1], "memory[1] was %u", memory[1]);
+ zassert_equal(0, memory[2], "memory[2] was %u", memory[2]);
+ zassert_equal(0, memory[3], "memory[3] was %u", memory[3]);
+
+ memset(memory, 0, 4);
+ zassume_true(sprintf(cmd, "rw .h %" PRIuPTR " 258",
+ (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+ zassert_equal(2, memory[0], "memory[0] was %u", memory[0]);
+ zassert_equal(1, memory[1], "memory[1] was %u", memory[1]);
+ zassert_equal(0, memory[2], "memory[2] was %u", memory[2]);
+ zassert_equal(0, memory[3], "memory[3] was %u", memory[3]);
+
+ memset(memory, 0, 4);
+ zassume_true(sprintf(cmd, "rw %" PRIuPTR " 16909060",
+ (uintptr_t)memory) != 0,
+ NULL);
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd), NULL);
+ zassert_equal(4, memory[0], "memory[0] was %u", memory[0]);
+ zassert_equal(3, memory[1], "memory[1] was %u", memory[1]);
+ zassert_equal(2, memory[2], "memory[2] was %u", memory[2]);
+ zassert_equal(1, memory[3], "memory[3] was %u", memory[3]);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/sleepmask.c b/zephyr/test/drivers/default/src/console_cmd/sleepmask.c
new file mode 100644
index 0000000000..6ae017dc66
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/sleepmask.c
@@ -0,0 +1,100 @@
+/* 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/emul.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "system.h"
+
+ZTEST_USER(console_cmd_sleepmask, test_no_args)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(buffer_size > 0, NULL);
+ zassert_not_null(strstr(outbuffer, "sleep mask"), NULL);
+}
+
+ZTEST_USER(console_cmd_sleepmask, test_bad_args)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(shell_zephyr, "sleepmask whoopsie"),
+ NULL);
+}
+
+ZTEST_USER(console_cmd_sleepmask, test_set_sleep_mask_directly)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ /* Set mask as 0 */
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask 0"), NULL);
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ /* Get mask and weakly verify mask is 0 */
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_not_null(strstr(outbuffer, "0"), NULL);
+ zassert_is_null(strstr(outbuffer, "1"), NULL);
+
+ /* Set mask as 1 */
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask 1"), NULL);
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ /* Get mask and weakly verify mask is 1 */
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask"), NULL);
+ zassert_not_null(strstr(outbuffer, "1"), NULL);
+}
+
+ZTEST_USER(console_cmd_sleepmask, test_enable_disable_force_sleepmask)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+
+ /* Verifying enabled to disabled */
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask on"), NULL);
+
+ int enabled_bits = sleep_mask & SLEEP_MASK_FORCE_NO_DSLEEP;
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask off"), NULL);
+
+ int disabled_bits = sleep_mask & SLEEP_MASK_FORCE_NO_DSLEEP;
+
+ zassert_false(enabled_bits & disabled_bits, NULL);
+
+ /* Verifying disabled to enabled */
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sleepmask on"), NULL);
+
+ enabled_bits = sleep_mask & SLEEP_MASK_FORCE_NO_DSLEEP;
+ zassert_false(enabled_bits & disabled_bits, NULL);
+}
+
+static void console_cmd_sleepmask_before_after(void *test_data)
+{
+ ARG_UNUSED(test_data);
+
+ enable_sleep(-1);
+}
+
+ZTEST_SUITE(console_cmd_sleepmask, drivers_predicate_post_main, NULL,
+ console_cmd_sleepmask_before_after,
+ console_cmd_sleepmask_before_after, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/sleeptimeout.c b/zephyr/test/drivers/default/src/console_cmd/sleeptimeout.c
new file mode 100644
index 0000000000..d802eb5948
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/sleeptimeout.c
@@ -0,0 +1,44 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_sleeptimeout, test_no_params)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "sleeptimeout"),
+ "Failed default print");
+}
+
+ZTEST_USER(console_cmd_sleeptimeout, test_good_params)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "sleeptimeout default"),
+ "Failed to set default sleep timeout");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "sleeptimeout infinite"),
+ "Failed to disable sleep timeout");
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "sleeptimeout 1500"),
+ "Failed to set sleep timeout to a custom value");
+}
+
+ZTEST_USER(console_cmd_sleeptimeout, test_bad_params)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "sleeptimeout 0");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(),
+ "sleeptimeout EC_HOST_SLEEP_TIMEOUT_INFINITE");
+
+ zassert_equal(rv, EC_ERROR_PARAM1, "Expected %d, but got %d",
+ EC_ERROR_PARAM1, rv);
+}
+
+ZTEST_SUITE(console_cmd_sleeptimeout, NULL, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/sysinfo.c b/zephyr/test/drivers/default/src/console_cmd/sysinfo.c
new file mode 100644
index 0000000000..3aeef6510c
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/sysinfo.c
@@ -0,0 +1,84 @@
+/* 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/emul.h>
+#include <zephyr/fff.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "system.h"
+
+ZTEST_USER(console_cmd_sysinfo, test_no_args)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sysinfo"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(buffer_size > 0, NULL);
+
+ /* Weakly verify some contents */
+ zassert_not_null(strstr(outbuffer, "Reset flags:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Copy:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Jumped:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Recovery:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Flags:"), NULL);
+}
+
+ZTEST_USER(console_cmd_sysinfo, test_no_args__sys_locked)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ /* System unlocked */
+ shell_backend_dummy_clear_output(shell_zephyr);
+ system_is_locked_fake.return_val = false;
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sysinfo"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(buffer_size > 0, NULL);
+ zassert_not_null(strstr(outbuffer, "unlocked"), NULL);
+
+ /* System locked */
+ shell_backend_dummy_clear_output(shell_zephyr);
+ system_is_locked_fake.return_val = true;
+
+ zassert_true(buffer_size > 0, NULL);
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sysinfo"), NULL);
+
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+ zassert_not_null(strstr(outbuffer, "locked"), NULL);
+
+ /* Verify system_is_locked in sysinfo cmd response remains */
+ shell_backend_dummy_clear_output(shell_zephyr);
+ system_is_locked_fake.return_val = false;
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "sysinfo"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(buffer_size > 0, NULL);
+ zassert_not_null(strstr(outbuffer, "locked"), NULL);
+}
+
+static void console_cmd_sysinfo_before_after(void *test_data)
+{
+ ARG_UNUSED(test_data);
+
+ system_common_reset_state();
+}
+
+ZTEST_SUITE(console_cmd_sysinfo, drivers_predicate_post_main, NULL,
+ console_cmd_sysinfo_before_after, console_cmd_sysinfo_before_after,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/tcpci_dump.c b/zephyr/test/drivers/default/src/console_cmd/tcpci_dump.c
new file mode 100644
index 0000000000..9652519cab
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/tcpci_dump.c
@@ -0,0 +1,46 @@
+/* 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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_USER(console_cmd_tcpci_dump, test_no_params)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "tcpci_dump");
+
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_tcpci_dump, test_good_index)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "tcpci_dump 0"),
+ "Failed index 0 print");
+}
+
+ZTEST_USER(console_cmd_tcpci_dump, test_bad_index)
+{
+ int rv = shell_execute_cmd(get_ec_shell(), "tcpci_dump 84");
+
+ zassert_equal(rv, EC_ERROR_INVAL, "Expected %d, but got %d",
+ EC_ERROR_INVAL, rv);
+}
+
+static void console_cmd_tcpci_dump_begin(void *data)
+{
+ ARG_UNUSED(data);
+
+ /* Assume we have at least one TCPC */
+ zassume_true(board_get_charger_chip_count() > 0,
+ "Insufficient TCPCs found");
+}
+
+ZTEST_SUITE(console_cmd_tcpci_dump, drivers_predicate_post_main, NULL,
+ console_cmd_tcpci_dump_begin, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/usb_pd_console.c b/zephyr/test/drivers/default/src/console_cmd/usb_pd_console.c
new file mode 100644
index 0000000000..21056056d4
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/usb_pd_console.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/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usb_prl_sm.h"
+
+static void console_cmd_usb_pd_after(void *fixture)
+{
+ ARG_UNUSED(fixture);
+
+ /* TODO (b/230059737) */
+ test_set_chipset_to_g3();
+ k_sleep(K_SECONDS(1));
+ test_set_chipset_to_s0();
+ k_sleep(K_SECONDS(10));
+
+ /* Keep port used by testsuite enabled (default state) */
+ pd_comm_enable(0, 1);
+ pd_set_suspend(0, 0);
+}
+
+ZTEST_SUITE(console_cmd_usb_pd, drivers_predicate_post_main, NULL, NULL,
+ console_cmd_usb_pd_after, NULL);
+
+ZTEST_USER(console_cmd_usb_pd, test_too_few_args)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_dump)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd dump 0");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd dump 4");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd dump -4");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd dump x");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_trysrc)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd trysrc 0");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd trysrc 2");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd trysrc 5");
+ zassert_equal(rv, EC_ERROR_PARAM3, "Expected %d, but got %d",
+ EC_ERROR_PARAM3, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_version)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd version");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_bad_port)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 5");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 5 tx");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_tx)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 tx");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_charger)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 charger");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_dev)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dev");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dev 20");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dev x");
+ zassert_equal(rv, EC_ERROR_PARAM3, "Expected %d, but got %d",
+ EC_ERROR_PARAM3, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_disable)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 disable");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_enable)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 enable");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_suspend)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 suspend");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_resume)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 resume");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_hard)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 hard");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_soft)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 soft");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_swap)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 swap");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 swap power");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 swap data");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 swap vconn");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 swap x");
+ zassert_equal(rv, EC_ERROR_PARAM3, "Expected %d, but got %d",
+ EC_ERROR_PARAM3, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_dualrole)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole on");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole off");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole freeze");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole sink");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole source");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 dualrole x");
+ zassert_equal(rv, EC_ERROR_PARAM4, "Expected %d, but got %d",
+ EC_ERROR_PARAM4, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_state)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 state");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_srccaps)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 srccaps");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_timer)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pd 0 timer");
+ zassert_equal(rv, EC_SUCCESS, "Expected %d, but got %d", EC_SUCCESS,
+ rv);
+}
+
+static void set_device_vdo(int port, enum tcpci_msg_type type)
+{
+ union tbt_mode_resp_device device_resp;
+ struct pd_discovery *dev_disc;
+
+ dev_disc = pd_get_am_discovery_and_notify_access(port, type);
+ dev_disc->svid_cnt = 1;
+ dev_disc->svids[0].svid = USB_VID_INTEL;
+ dev_disc->svids[0].discovery = PD_DISC_COMPLETE;
+ dev_disc->svids[0].mode_cnt = 1;
+ device_resp.tbt_alt_mode = TBT_ALTERNATE_MODE;
+ device_resp.tbt_adapter = TBT_ADAPTER_TBT3;
+ device_resp.intel_spec_b0 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ device_resp.vendor_spec_b0 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ device_resp.vendor_spec_b1 = VENDOR_SPECIFIC_NOT_SUPPORTED;
+ dev_disc->svids[0].mode_vdo[0] = device_resp.raw_value;
+}
+
+static void set_active_cable_type(int port, enum tcpci_msg_type type,
+ enum idh_ptype ptype)
+{
+ struct pd_discovery *dev_disc;
+
+ dev_disc = pd_get_am_discovery_and_notify_access(port, type);
+ dev_disc->identity.idh.product_type = ptype;
+ prl_set_rev(port, type, PD_REV30);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_pe)
+{
+ int rv;
+
+ pd_set_identity_discovery(0, TCPCI_MSG_SOP, PD_DISC_COMPLETE);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pe 0 dump");
+ zassert_ok(rv, "Expected %d, but got %d", EC_SUCCESS, rv);
+
+ set_device_vdo(0, TCPCI_MSG_SOP);
+ rv = shell_execute_cmd(get_ec_shell(), "pe 0 dump");
+ zassert_ok(rv, "Expected %d, but got %d", EC_SUCCESS, rv);
+
+ /* Handle error scenarios */
+ rv = shell_execute_cmd(get_ec_shell(), "pe 0");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pe x dump");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
+
+ZTEST_USER(console_cmd_usb_pd, test_pdcable)
+{
+ int rv;
+
+ rv = shell_execute_cmd(get_ec_shell(), "pdcable 0");
+ zassert_ok(rv, "Expected %d, but got %d", EC_SUCCESS, rv);
+
+ set_device_vdo(0, TCPCI_MSG_SOP_PRIME);
+
+ /* Set active cable type IDH_PTYPE_ACABLE */
+ set_active_cable_type(0, TCPCI_MSG_SOP_PRIME, IDH_PTYPE_ACABLE);
+ rv = shell_execute_cmd(get_ec_shell(), "pdcable 0");
+ zassert_ok(rv, "Expected %d, but got %d", EC_SUCCESS, rv);
+
+ /* Set active cable type IDH_PTYPE_PCABLE */
+ set_active_cable_type(0, TCPCI_MSG_SOP_PRIME, IDH_PTYPE_PCABLE);
+ rv = shell_execute_cmd(get_ec_shell(), "pdcable 0");
+ zassert_ok(rv, "Expected %d, but got %d", EC_SUCCESS, rv);
+
+ /* Handle error scenarios */
+ rv = shell_execute_cmd(get_ec_shell(), "pdcable");
+ zassert_equal(rv, EC_ERROR_PARAM_COUNT, "Expected %d, but got %d",
+ EC_ERROR_PARAM_COUNT, rv);
+
+ rv = shell_execute_cmd(get_ec_shell(), "pdcable t");
+ zassert_equal(rv, EC_ERROR_PARAM2, "Expected %d, but got %d",
+ EC_ERROR_PARAM2, rv);
+}
diff --git a/zephyr/test/drivers/default/src/console_cmd/version.c b/zephyr/test/drivers/default/src/console_cmd/version.c
new file mode 100644
index 0000000000..932cc51449
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/version.c
@@ -0,0 +1,37 @@
+/* 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/emul.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "system.h"
+
+ZTEST_USER(console_cmd_version, test_no_args)
+{
+ const struct shell *shell_zephyr = get_ec_shell();
+ const char *outbuffer;
+ size_t buffer_size;
+
+ shell_backend_dummy_clear_output(shell_zephyr);
+
+ zassert_ok(shell_execute_cmd(shell_zephyr, "version"), NULL);
+ outbuffer = shell_backend_dummy_get_output(shell_zephyr, &buffer_size);
+
+ zassert_true(buffer_size > 0, NULL);
+
+ /* Weakly verify some contents */
+ zassert_not_null(strstr(outbuffer, "Chip:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Board:"), NULL);
+ zassert_not_null(strstr(outbuffer, "RO:"), NULL);
+ zassert_not_null(strstr(outbuffer, "RW:"), NULL);
+ zassert_not_null(strstr(outbuffer, "Build:"), NULL);
+}
+
+ZTEST_SUITE(console_cmd_version, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/console_cmd/waitms.c b/zephyr/test/drivers/default/src/console_cmd/waitms.c
new file mode 100644
index 0000000000..0d03ee7414
--- /dev/null
+++ b/zephyr/test/drivers/default/src/console_cmd/waitms.c
@@ -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 <stdio.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "timer.h"
+
+static void test_int(int ms)
+{
+ char cmd[32];
+ unsigned long measured;
+ timestamp_t start;
+ timestamp_t end;
+
+ sprintf(cmd, "waitms %d", ms);
+ start = get_time();
+ zassert_ok(shell_execute_cmd(get_ec_shell(), cmd),
+ "Failed to execute 'waitms' command");
+ end = get_time();
+ measured = (end.val - start.val) / 1000;
+ zassert_equal(measured, ms, "'waitms %d' failed, took %ld ms", ms,
+ measured);
+}
+
+ZTEST_SUITE(console_cmd_waitms, NULL, NULL, NULL, NULL, NULL);
+
+ZTEST_USER(console_cmd_waitms, test_waitms)
+{
+ /*
+ * Test across three orders of magnitude. Beyond ~3s the watchdog will
+ * trigger so don't need to bother testing 10s of seconds or greater.
+ */
+ test_int(0);
+ test_int(5);
+ test_int(75);
+ test_int(250);
+ test_int(1000);
+
+ /* A plain string should fail. */
+ zassert_true(shell_execute_cmd(get_ec_shell(), "waitms string"), NULL);
+
+ /* Floats and negative ints should fail. */
+ zassert_true(shell_execute_cmd(get_ec_shell(), "waitms 123.456"), NULL);
+ zassert_true(shell_execute_cmd(get_ec_shell(), "waitms -67.3"), NULL);
+ zassert_true(shell_execute_cmd(get_ec_shell(), "waitms -7"), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/cros_cbi.c b/zephyr/test/drivers/default/src/cros_cbi.c
new file mode 100644
index 0000000000..e92765cb52
--- /dev/null
+++ b/zephyr/test/drivers/default/src/cros_cbi.c
@@ -0,0 +1,55 @@
+/* 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/device.h>
+#include <zephyr/ztest.h>
+
+#include "cros_cbi.h"
+#include "test/drivers/test_state.h"
+
+ZTEST(cros_cbi, test_check_match)
+{
+ int value;
+
+ value = cros_cbi_ssfc_check_match(
+ CBI_SSFC_VALUE_ID(DT_NODELABEL(base_sensor_0)));
+ zassert_true(value, "Expected cbi ssfc to match base_sensor_0");
+
+ value = cros_cbi_ssfc_check_match(
+ CBI_SSFC_VALUE_ID(DT_NODELABEL(base_sensor_1)));
+ zassert_false(value, "Expected cbi ssfc not to match base_sensor_1");
+
+ value = cros_cbi_ssfc_check_match(CBI_SSFC_VALUE_COUNT);
+ zassert_false(value, "Expected cbi ssfc to fail on invalid enum");
+}
+
+ZTEST(cros_cbi, test_fail_check_match)
+{
+ int value;
+
+ value = cros_cbi_ssfc_check_match(CBI_SSFC_VALUE_COUNT);
+ zassert_false(value,
+ "Expected cbi ssfc to never match CBI_SSFC_VALUE_COUNT");
+}
+
+ZTEST(cros_cbi, test_fw_config)
+{
+ uint32_t value;
+ int ret;
+
+ ret = cros_cbi_get_fw_config(FW_CONFIG_FIELD_1, &value);
+ zassert_true(ret == 0,
+ "Expected no error return from cros_cbi_get_fw_config");
+ zassert_true(value == FW_FIELD_1_B,
+ "Expected field value to match FW_FIELD_1_B as default");
+
+ ret = cros_cbi_get_fw_config(FW_CONFIG_FIELD_2, &value);
+ zassert_true(ret == 0,
+ "Expected no error return from cros_cbi_get_fw_config");
+ zassert_false(value == FW_FIELD_2_X,
+ "Expected field value to not match FW_FIELD_2_X");
+}
+
+ZTEST_SUITE(cros_cbi, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/espi.c b/zephyr/test/drivers/default/src/espi.c
new file mode 100644
index 0000000000..9843471ae7
--- /dev/null
+++ b/zephyr/test/drivers/default/src/espi.c
@@ -0,0 +1,326 @@
+/* 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 <string.h>
+#include <zephyr/fff.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "ec_commands.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "system.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+#define PORT 0
+
+#define AC_OK_OD_GPIO_NAME "acok_od"
+
+static void espi_before(void *state)
+{
+ ARG_UNUSED(state);
+ RESET_FAKE(system_is_locked);
+}
+
+static void espi_after(void *state)
+{
+ ARG_UNUSED(state);
+ RESET_FAKE(system_is_locked);
+}
+
+ZTEST_USER(espi, test_host_command_get_protocol_info)
+{
+ struct ec_response_get_protocol_info response;
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE(
+ EC_CMD_GET_PROTOCOL_INFO, 0, response);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.protocol_versions, BIT(3), NULL);
+ zassert_equal(response.max_request_packet_size, EC_LPC_HOST_PACKET_SIZE,
+ NULL);
+ zassert_equal(response.max_response_packet_size,
+ EC_LPC_HOST_PACKET_SIZE, NULL);
+ zassert_equal(response.flags, 0, NULL);
+}
+
+ZTEST_USER(espi, test_host_command_usb_pd_power_info)
+{
+ /* Only test we've enabled the command */
+ struct ec_response_usb_pd_power_info response;
+ struct ec_params_usb_pd_power_info params = { .port = PORT };
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND(
+ EC_CMD_USB_PD_POWER_INFO, 0, response, params);
+
+ args.params = &params;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+}
+
+ZTEST_USER(espi, test_host_command_typec_status)
+{
+ /* Only test we've enabled the command */
+ struct ec_params_typec_status params = { .port = PORT };
+ struct ec_response_typec_status response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_TYPEC_STATUS, 0, response, params);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+}
+
+ZTEST_USER(espi, test_host_command_usb_pd_get_amode)
+{
+ /* Only test we've enabled the command */
+ struct ec_params_usb_pd_get_mode_request params = {
+ .port = PORT,
+ .svid_idx = 0,
+ };
+ struct ec_params_usb_pd_get_mode_response response;
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND(
+ EC_CMD_USB_PD_GET_AMODE, 0, response, params);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ /* Note: with no SVIDs the response size is the size of the svid field.
+ * See the usb alt mode test for verifying larger struct sizes
+ */
+ zassert_equal(args.response_size, sizeof(response.svid), NULL);
+}
+
+ZTEST_USER(espi, test_host_command_gpio_get_v0)
+{
+ struct ec_params_gpio_get p = {
+ /* Checking for AC enabled */
+ .name = AC_OK_OD_GPIO_NAME,
+ };
+ struct ec_response_gpio_get response;
+
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 0, response, p);
+
+ set_ac_enabled(true);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_true(response.val, NULL);
+
+ set_ac_enabled(false);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_false(response.val, NULL);
+}
+
+ZTEST_USER(espi, test_host_command_gpio_get_v1_get_by_name)
+{
+ struct ec_params_gpio_get_v1 p = {
+ .subcmd = EC_GPIO_GET_BY_NAME,
+ /* Checking for AC enabled */
+ .get_value_by_name = {
+ AC_OK_OD_GPIO_NAME,
+ },
+ };
+ struct ec_response_gpio_get_v1 response;
+
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, p);
+
+ set_ac_enabled(true);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response.get_value_by_name),
+ NULL);
+ zassert_true(response.get_info.val, NULL);
+
+ set_ac_enabled(false);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response.get_value_by_name),
+ NULL);
+ zassert_false(response.get_info.val, NULL);
+}
+
+ZTEST_USER(espi, test_host_command_gpio_get_v1_get_count)
+{
+ struct ec_params_gpio_get_v1 p = {
+ .subcmd = EC_GPIO_GET_COUNT,
+ };
+ struct ec_response_gpio_get_v1 response;
+
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, p);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response.get_count), NULL);
+ zassert_equal(response.get_count.val, GPIO_COUNT, NULL);
+}
+
+ZTEST_USER(espi, test_host_command_gpio_get_v1_get_info)
+{
+ const enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_acok_od));
+ struct ec_params_gpio_get_v1 p = {
+ .subcmd = EC_GPIO_GET_INFO,
+ .get_info = {
+ .index = signal,
+ },
+ };
+ struct ec_response_gpio_get_v1 response;
+
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, p);
+
+ set_ac_enabled(true);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_ok(strcmp(response.get_info.name, AC_OK_OD_GPIO_NAME), NULL);
+ zassert_true(response.get_info.val, NULL);
+
+ set_ac_enabled(false);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_ok(strcmp(response.get_info.name, AC_OK_OD_GPIO_NAME), NULL);
+ zassert_false(response.get_info.val, NULL);
+}
+
+ZTEST_USER(espi, test_host_command_gpio_set)
+{
+ struct nothing {
+ int place_holder;
+ };
+ const struct gpio_dt_spec *gp = GPIO_DT_FROM_NODELABEL(gpio_test);
+ struct ec_params_gpio_set p = {
+ .name = "test",
+ .val = 0,
+ };
+
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_GPIO_SET, 0, p);
+
+ /* Force value to 1 to see change */
+ zassume_ok(gpio_pin_set_dt(gp, 1), NULL);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(gpio_pin_get_dt(gp), p.val, NULL);
+
+ p.val = 1;
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(gpio_pin_get_dt(gp), p.val, NULL);
+}
+
+ZTEST(espi, test_hc_gpio_get_v0_invalid_name)
+{
+ struct ec_response_gpio_get response;
+ struct ec_params_gpio_get params = { .name = "INVALID_GPIO_NAME" };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 0, response, params);
+
+ zassert_equal(EC_RES_ERROR, host_command_process(&args), NULL);
+}
+
+ZTEST(espi, test_hc_gpio_get_v1_get_by_name_invalid_name)
+{
+ struct ec_response_gpio_get_v1 response;
+ struct ec_params_gpio_get_v1 params = {
+ .subcmd = EC_GPIO_GET_BY_NAME,
+ .get_value_by_name.name = "INVALID_GPIO_NAME",
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, params);
+
+ zassert_equal(EC_RES_ERROR, host_command_process(&args), NULL);
+}
+
+ZTEST(espi, test_hc_gpio_get_v1_get_info_invalid_index)
+{
+ struct ec_response_gpio_get_v1 response;
+ struct ec_params_gpio_get_v1 params = {
+ .subcmd = EC_GPIO_GET_INFO,
+ .get_info.index = GPIO_COUNT,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, params);
+
+ zassert_equal(EC_RES_ERROR, host_command_process(&args), NULL);
+}
+
+ZTEST(espi, test_hc_gpio_get_v1_invalid_subcmd)
+{
+ struct ec_response_gpio_get_v1 response;
+ struct ec_params_gpio_get_v1 params = {
+ .subcmd = EC_CMD_GPIO_GET,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_GPIO_GET, 1, response, params);
+
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL);
+}
+
+/* EC_CMD_GET_FEATURES */
+ZTEST_USER(espi, test_host_command_ec_cmd_get_features)
+{
+ struct ec_response_get_features response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_GET_FEATURES, 0, response);
+
+ int rv = host_command_process(&args);
+
+ zassert_equal(rv, EC_RES_SUCCESS, "Expected %d, but got %d",
+ EC_RES_SUCCESS, rv);
+
+ /* Check features returned */
+ uint32_t feature_mask;
+
+ feature_mask = EC_FEATURE_MASK_0(EC_FEATURE_FLASH);
+ feature_mask |= EC_FEATURE_MASK_0(EC_FEATURE_MOTION_SENSE);
+ feature_mask |= EC_FEATURE_MASK_0(EC_FEATURE_KEYB);
+ zassert_true((response.flags[0] & feature_mask),
+ "Known features were not returned.");
+ feature_mask = EC_FEATURE_MASK_1(EC_FEATURE_UNIFIED_WAKE_MASKS);
+ feature_mask |= EC_FEATURE_MASK_1(EC_FEATURE_HOST_EVENT64);
+ feature_mask |= EC_FEATURE_MASK_1(EC_FEATURE_EXEC_IN_RAM);
+ zassert_true((response.flags[1] & feature_mask),
+ "Known features were not returned.");
+}
+
+ZTEST(espi, test_hc_gpio_set_system_is_locked)
+{
+ struct ec_params_gpio_set params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_GPIO_SET, 0, params);
+
+ system_is_locked_fake.return_val = 1;
+ zassert_equal(EC_RES_ACCESS_DENIED, host_command_process(&args), NULL);
+}
+
+ZTEST(espi, test_hc_gpio_set_invalid_gpio_name)
+{
+ struct ec_params_gpio_set params = {
+ .name = "",
+ .val = 0,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_GPIO_SET, 0, params);
+
+ zassert_equal(EC_RES_ERROR, host_command_process(&args), NULL);
+}
+
+ZTEST_SUITE(espi, drivers_predicate_post_main, NULL, espi_before, espi_after,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/flash.c b/zephyr/test/drivers/default/src/flash.c
new file mode 100644
index 0000000000..b49d21b997
--- /dev/null
+++ b/zephyr/test/drivers/default/src/flash.c
@@ -0,0 +1,444 @@
+/* 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/emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "ec_commands.h"
+#include "emul/emul_flash.h"
+#include "flash.h"
+#include "host_command.h"
+#include "system.h"
+#include "test/drivers/test_state.h"
+
+#define WP_L_GPIO_PATH DT_PATH(named_gpios, wp_l)
+
+static int gpio_wp_l_set(int value)
+{
+ const struct device *wp_l_gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(WP_L_GPIO_PATH, gpios));
+
+ return gpio_emul_input_set(wp_l_gpio_dev,
+ DT_GPIO_PIN(WP_L_GPIO_PATH, gpios), value);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_protect_wp_asserted)
+{
+ struct ec_response_flash_protect response;
+ struct ec_params_flash_protect params = {
+ .mask = 0,
+ .flags = 0,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_FLASH_PROTECT, 0, response, params);
+ /* The original flags not 0 as GPIO WP_L asserted */
+ uint32_t expected_flags = EC_FLASH_PROTECT_GPIO_ASSERTED;
+
+ /* Get the flash protect */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Enable RO_AT_BOOT */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = EC_FLASH_PROTECT_RO_AT_BOOT;
+ expected_flags |= EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Disable RO_AT_BOOT; should change nothing as GPIO WP_L is asserted */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = 0;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Enable ALL_NOW */
+ params.mask = EC_FLASH_PROTECT_ALL_NOW;
+ params.flags = EC_FLASH_PROTECT_ALL_NOW;
+ expected_flags |= EC_FLASH_PROTECT_ALL_NOW;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Disable ALL_NOW; should change nothing as GPIO WP_L is asserted */
+ params.mask = EC_FLASH_PROTECT_ALL_NOW;
+ params.flags = 0;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Disable RO_AT_BOOT; should change nothing as GPIO WP_L is asserted */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = 0;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_protect_wp_deasserted)
+{
+ struct ec_response_flash_protect response;
+ struct ec_params_flash_protect params = {
+ .mask = 0,
+ .flags = 0,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_FLASH_PROTECT, 0, response, params);
+ /* The original flags 0 as GPIO WP_L deasserted */
+ uint32_t expected_flags = 0;
+
+ zassert_ok(gpio_wp_l_set(1), NULL);
+
+ /* Get the flash protect */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Enable RO_AT_BOOT */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = EC_FLASH_PROTECT_RO_AT_BOOT;
+ expected_flags |= EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Disable RO_AT_BOOT */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = 0;
+ expected_flags &=
+ ~(EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW);
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Enable RO_AT_BOOT */
+ params.mask = EC_FLASH_PROTECT_RO_AT_BOOT;
+ params.flags = EC_FLASH_PROTECT_RO_AT_BOOT;
+ expected_flags |= EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+
+ /* Enable ALL_NOW; should change nothing as GPIO WP_L is deasserted */
+ params.mask = EC_FLASH_PROTECT_ALL_NOW;
+ params.flags = EC_FLASH_PROTECT_ALL_NOW;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flags, expected_flags, "response.flags = %d",
+ response.flags);
+}
+
+#define TEST_BUF_SIZE 0x100
+
+ZTEST_USER(flash, test_hostcmd_flash_write_and_erase)
+{
+ uint8_t in_buf[TEST_BUF_SIZE];
+ uint8_t out_buf[sizeof(struct ec_params_flash_write) + TEST_BUF_SIZE];
+
+ struct ec_params_flash_read read_params = {
+ .offset = 0x10000,
+ .size = TEST_BUF_SIZE,
+ };
+ struct host_cmd_handler_args read_args =
+ BUILD_HOST_COMMAND(EC_CMD_FLASH_READ, 0, in_buf, read_params);
+
+ struct ec_params_flash_erase erase_params = {
+ .offset = 0x10000,
+ .size = 0x10000,
+ };
+ struct host_cmd_handler_args erase_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_FLASH_ERASE, 0, erase_params);
+
+ /* The write host command structs need to be filled run-time */
+ struct ec_params_flash_write *write_params =
+ (struct ec_params_flash_write *)out_buf;
+ struct host_cmd_handler_args write_args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_FLASH_WRITE, 0);
+
+ write_params->offset = 0x10000;
+ write_params->size = TEST_BUF_SIZE;
+ write_args.params = write_params;
+ write_args.params_size = sizeof(*write_params) + TEST_BUF_SIZE;
+
+ /* Flash write to all 0xec */
+ memset(write_params + 1, 0xec, TEST_BUF_SIZE);
+ zassert_ok(host_command_process(&write_args), NULL);
+
+ /* Flash read and compare the readback data */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_equal(read_args.response_size, TEST_BUF_SIZE, NULL);
+ zassert_equal(in_buf[0], 0xec, "readback data not expected: 0x%x",
+ in_buf[0]);
+ zassert_equal(in_buf[TEST_BUF_SIZE - 1], 0xec,
+ "readback data not expected: 0x%x", in_buf[0]);
+
+ /* Flash erase */
+ zassert_ok(host_command_process(&erase_args), NULL);
+
+ /* Flash read and compare the readback data */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_equal(in_buf[0], 0xff, "readback data not expected: 0x%x",
+ in_buf[0]);
+ zassert_equal(in_buf[TEST_BUF_SIZE - 1], 0xff,
+ "readback data not expected: 0x%x", in_buf[0]);
+}
+
+#define EC_FLASH_REGION_START \
+ MIN(CONFIG_EC_PROTECTED_STORAGE_OFF, CONFIG_EC_WRITABLE_STORAGE_OFF)
+
+static void test_region_info(uint32_t region, uint32_t expected_offset,
+ uint32_t expected_size)
+{
+ struct ec_response_flash_region_info response;
+ struct ec_params_flash_region_info params = {
+ .region = region,
+ };
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND(
+ EC_CMD_FLASH_REGION_INFO, 1, response, params);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.offset, expected_offset, NULL);
+ zassert_equal(response.size, expected_size, NULL);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_region_info_ro)
+{
+ test_region_info(EC_FLASH_REGION_RO,
+ CONFIG_EC_PROTECTED_STORAGE_OFF +
+ CONFIG_RO_STORAGE_OFF - EC_FLASH_REGION_START,
+ EC_FLASH_REGION_RO_SIZE);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_region_info_active)
+{
+ test_region_info(EC_FLASH_REGION_ACTIVE,
+ flash_get_rw_offset(system_get_active_copy()) -
+ EC_FLASH_REGION_START,
+ CONFIG_EC_WRITABLE_STORAGE_SIZE);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_region_info_active_wp_ro)
+{
+ test_region_info(EC_FLASH_REGION_WP_RO,
+ CONFIG_WP_STORAGE_OFF - EC_FLASH_REGION_START,
+ CONFIG_WP_STORAGE_SIZE);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_region_info_active_update)
+{
+ test_region_info(EC_FLASH_REGION_UPDATE,
+ flash_get_rw_offset(system_get_update_copy()) -
+ EC_FLASH_REGION_START,
+ CONFIG_EC_WRITABLE_STORAGE_SIZE);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_region_info_active_invalid)
+{
+ struct ec_response_flash_region_info response;
+ struct ec_params_flash_region_info params = {
+ /* Get an invalid region */
+ .region = 10,
+ };
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND(
+ EC_CMD_FLASH_REGION_INFO, 1, response, params);
+
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, NULL);
+}
+
+ZTEST_USER(flash, test_hostcmd_flash_info)
+{
+ struct ec_response_flash_info_1 response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_FLASH_INFO, 1, response);
+
+ /* Get the flash info. */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_equal(response.flash_size,
+ CONFIG_FLASH_SIZE_BYTES - EC_FLASH_REGION_START,
+ "response.flash_size = %d", response.flash_size);
+ zassert_equal(response.flags, 0, "response.flags = %d", response.flags);
+ zassert_equal(response.write_block_size, CONFIG_FLASH_WRITE_SIZE,
+ "response.write_block_size = %d",
+ response.write_block_size);
+ zassert_equal(response.erase_block_size, CONFIG_FLASH_ERASE_SIZE,
+ "response.erase_block_size = %d",
+ response.erase_block_size);
+ zassert_equal(response.protect_block_size, CONFIG_FLASH_BANK_SIZE,
+ "response.protect_block_size = %d",
+ response.protect_block_size);
+ zassert_equal(
+ response.write_ideal_size,
+ (args.response_max - sizeof(struct ec_params_flash_write)) &
+ ~(CONFIG_FLASH_WRITE_SIZE - 1),
+ "response.write_ideal_size = %d", response.write_ideal_size);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__invalid)
+{
+ /* Command requires a 2nd CLI arg */
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "flashwp"), NULL);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__now)
+{
+ uint32_t current;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp true"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_true(EC_FLASH_PROTECT_GPIO_ASSERTED & current, "current = %08x",
+ current);
+ zassert_true(EC_FLASH_PROTECT_RO_AT_BOOT & current, "current = %08x",
+ current);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp now"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_true(current & EC_FLASH_PROTECT_ALL_NOW, "current = %08x",
+ current);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__all)
+{
+ uint32_t current;
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp true"), NULL);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp all"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_true(EC_FLASH_PROTECT_ALL_NOW & current, "current = %08x",
+ current);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__bool_false)
+{
+ uint32_t current;
+
+ /* Set RO_AT_BOOT and verify */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp true"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_true(current & EC_FLASH_PROTECT_RO_AT_BOOT, "current = %08x",
+ current);
+
+ gpio_wp_l_set(1);
+
+ /* Now clear it */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp false"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_false(current & EC_FLASH_PROTECT_RO_AT_BOOT, "current = %08x",
+ current);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__bool_true)
+{
+ uint32_t current;
+
+ gpio_wp_l_set(1);
+
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "flashwp true"), NULL);
+
+ current = crec_flash_get_protect();
+ zassert_equal(EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW,
+ current, "current = %08x", current);
+}
+
+ZTEST_USER(flash, test_console_cmd_flashwp__bad_param)
+{
+ zassert_ok(!shell_execute_cmd(get_ec_shell(), "flashwp xyz"), NULL);
+}
+
+/**
+ * @brief Prepare a region of flash for the test_crec_flash_is_erased* tests
+ *
+ * @param offset Offset to write bytes at.
+ * @param size Number of bytes to erase.
+ * @param make_write If true, write an arbitrary byte after erase so the region
+ * is no longer fully erased.
+ */
+static void setup_flash_region_helper(uint32_t offset, uint32_t size,
+ bool make_write)
+{
+ struct ec_params_flash_erase erase_params = {
+ .offset = offset,
+ .size = size,
+ };
+ struct host_cmd_handler_args erase_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_FLASH_ERASE, 0, erase_params);
+
+ zassume_ok(host_command_process(&erase_args), NULL);
+
+ if (make_write) {
+ /* Sized for flash_write header plus one byte of data */
+ uint8_t out_buf[sizeof(struct ec_params_flash_write) +
+ sizeof(uint8_t)];
+
+ struct ec_params_flash_write *write_params =
+ (struct ec_params_flash_write *)out_buf;
+ struct host_cmd_handler_args write_args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_FLASH_WRITE, 0);
+
+ write_params->offset = offset;
+ write_params->size = 1;
+ write_args.params = write_params;
+ write_args.params_size = sizeof(out_buf);
+
+ /* Write one byte at start of region */
+ out_buf[sizeof(*write_params)] = 0xec;
+
+ zassume_ok(host_command_process(&write_args), NULL);
+ }
+}
+
+ZTEST_USER(flash, test_crec_flash_is_erased__happy)
+{
+ uint32_t offset = 0x10000;
+
+ setup_flash_region_helper(offset, TEST_BUF_SIZE, false);
+
+ zassert_true(crec_flash_is_erased(offset, TEST_BUF_SIZE), NULL);
+}
+
+ZTEST_USER(flash, test_crec_flash_is_erased__not_erased)
+{
+ uint32_t offset = 0x10000;
+
+ setup_flash_region_helper(offset, TEST_BUF_SIZE, true);
+
+ zassert_true(!crec_flash_is_erased(offset, TEST_BUF_SIZE), NULL);
+}
+
+static void flash_reset(void)
+{
+ /* Set the GPIO WP_L to default */
+ gpio_wp_l_set(0);
+
+ /* Reset the protection flags */
+ cros_flash_emul_protect_reset();
+}
+
+static void flash_before(void *data)
+{
+ ARG_UNUSED(data);
+ flash_reset();
+}
+
+static void flash_after(void *data)
+{
+ ARG_UNUSED(data);
+ flash_reset();
+
+ /* The test modifies this bank. Erase it in case of failure. */
+ crec_flash_erase(0x10000, 0x10000);
+}
+
+ZTEST_SUITE(flash, drivers_predicate_post_main, NULL, flash_before, flash_after,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/gpio.c b/zephyr/test/drivers/default/src/gpio.c
new file mode 100644
index 0000000000..acfa0de26e
--- /dev/null
+++ b/zephyr/test/drivers/default/src/gpio.c
@@ -0,0 +1,421 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief Unit Tests for GPIO.
+ */
+
+#include <zephyr/device.h>
+
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/logging/log.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include "gpio.h"
+#include "gpio/gpio.h"
+#include "gpio/gpio_int.h"
+#include "test/drivers/stubs.h"
+#include "util.h"
+#include "test/drivers/test_state.h"
+
+extern bool gpio_test_interrupt_triggered;
+/**
+ * @brief TestPurpose: Verify Zephyr to EC GPIO bitmask conversion.
+ *
+ * @details
+ * Validate Zephyr to EC GPIO bitmask conversion.
+ *
+ * Expected Results
+ * - GPIO bitmask conversions are successful
+ */
+ZTEST(gpio, test_convert_from_zephyr_flags)
+{
+ int retval;
+ struct {
+ int zephyr_bmask;
+ gpio_flags_t expected_ec_bmask;
+ } validate[] = {
+ { GPIO_DISCONNECTED, GPIO_FLAG_NONE },
+ { GPIO_OUTPUT_INIT_LOW, GPIO_LOW },
+ { GPIO_OUTPUT_INIT_HIGH, GPIO_HIGH },
+ { GPIO_VOLTAGE_1P8, GPIO_SEL_1P8V },
+ { GPIO_INT_ENABLE, GPIO_FLAG_NONE },
+ { GPIO_INT_ENABLE | GPIO_INT_EDGE, GPIO_FLAG_NONE },
+ { GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_HIGH_1,
+ GPIO_INT_F_RISING },
+ { GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_LOW_0,
+ GPIO_INT_F_FALLING },
+ { GPIO_INT_ENABLE | GPIO_INT_HIGH_1, GPIO_INT_F_HIGH },
+ { GPIO_INT_ENABLE | GPIO_INT_LOW_0, GPIO_INT_F_LOW },
+ { GPIO_OUTPUT_INIT_LOGICAL, 0 },
+ { GPIO_OPEN_DRAIN | GPIO_PULL_UP,
+ GPIO_OPEN_DRAIN | GPIO_PULL_UP },
+ };
+ int num_tests = ARRAY_SIZE(validate);
+
+ for (int i = 0; i < num_tests; i++) {
+ retval = convert_from_zephyr_flags(validate[i].zephyr_bmask);
+ zassert_equal(validate[i].expected_ec_bmask, retval,
+ "[%d] Expected 0x%08X, returned 0x%08X.", i,
+ validate[i].expected_ec_bmask, retval);
+ }
+}
+
+/**
+ * @brief TestPurpose: Verify EC to Zephyr GPIO bitmask conversion.
+ *
+ * @details
+ * Validate EC to Zephyr GPIO bitmask conversion.
+ *
+ * Expected Results
+ * - GPIO bitmask conversions are successful
+ */
+ZTEST(gpio, test_convert_to_zephyr_flags)
+{
+ gpio_flags_t retval;
+
+ struct {
+ gpio_flags_t ec_bmask;
+ int expected_zephyr_bmask;
+ } validate[] = {
+ { GPIO_FLAG_NONE, GPIO_DISCONNECTED },
+ { GPIO_LOW, GPIO_OUTPUT_INIT_LOW },
+ { GPIO_HIGH, GPIO_OUTPUT_INIT_HIGH },
+ { GPIO_INT_F_RISING,
+ GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_HIGH_1 },
+ { GPIO_INT_F_FALLING,
+ GPIO_INT_ENABLE | GPIO_INT_EDGE | GPIO_INT_LOW_0 },
+ { GPIO_INT_F_LOW, GPIO_INT_ENABLE | GPIO_INT_LOW_0 },
+ { GPIO_INT_F_HIGH, GPIO_INT_ENABLE | GPIO_INT_HIGH_1 },
+ { GPIO_SEL_1P8V, GPIO_VOLTAGE_1P8 },
+ };
+ int num_tests = ARRAY_SIZE(validate);
+
+ for (int i = 0; i < num_tests; i++) {
+ retval = convert_to_zephyr_flags(validate[i].ec_bmask);
+ zassert_equal(validate[i].expected_zephyr_bmask, retval,
+ "[%d] Expected 0x%08X, returned 0x%08X.", i,
+ validate[i].expected_zephyr_bmask, retval);
+ }
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO signal_is_gpio.
+ *
+ * @details
+ * Validate signal_is_gpio
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_signal_is_gpio)
+{
+ zassert_true(signal_is_gpio(GPIO_SIGNAL(DT_NODELABEL(gpio_test))),
+ "Expected true");
+}
+
+/**
+ * @brief TestPurpose: Verify legacy API GPIO set/get level.
+ *
+ * @details
+ * Validate set/get level for legacy API
+ * This tests the legacy API, though no Zepyhr
+ * based code should use it.
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_legacy_gpio_get_set_level)
+{
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_test));
+ int level;
+ /* Test invalid signal */
+ gpio_set_level(GPIO_COUNT, 0);
+ zassert_equal(0, gpio_get_level(GPIO_COUNT), "Expected level==0");
+ /* Test valid signal */
+ gpio_set_level(signal, 0);
+ zassert_equal(0, gpio_get_level(signal), "Expected level==0");
+ gpio_set_level(signal, 1);
+ zassert_equal(1, gpio_get_level(signal), "Expected level==1");
+ level = gpio_get_ternary(signal);
+ gpio_set_level_verbose(CC_CHIPSET, signal, 0);
+ zassert_equal(0, gpio_get_level(signal), "Expected level==0");
+}
+
+/**
+ * @brief TestPurpose: Verify legacy GPIO enable/disable interrupt.
+ *
+ * @details
+ * Validate gpio_enable_interrupt/gpio_disable_interrupt
+ * Uses the legacy API. No Zephyr code should use this API.
+ *
+ * Expected Results
+ * - Success
+ */
+
+ZTEST(gpio, test_legacy_gpio_enable_interrupt)
+{
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_test));
+
+ gpio_test_interrupt_triggered = false;
+
+ /* Test invalid signal */
+ zassert_not_equal(EC_SUCCESS, gpio_disable_interrupt(GPIO_COUNT), NULL);
+ zassert_not_equal(EC_SUCCESS, gpio_enable_interrupt(GPIO_COUNT), NULL);
+ zassert_false(gpio_test_interrupt_triggered, NULL);
+
+ /* Test valid signal */
+ zassert_ok(gpio_disable_interrupt(signal), NULL);
+ gpio_set_level(signal, 0);
+ zassert_false(gpio_test_interrupt_triggered, NULL);
+ gpio_set_level(signal, 1);
+ zassert_false(gpio_test_interrupt_triggered, NULL);
+
+ zassert_ok(gpio_enable_interrupt(signal), NULL);
+ gpio_set_level(signal, 0);
+ zassert_true(gpio_test_interrupt_triggered, NULL);
+ gpio_test_interrupt_triggered = false;
+ gpio_set_level(signal, 1);
+ zassert_true(gpio_test_interrupt_triggered, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO set/get level.
+ *
+ * @details
+ * Validate set/get level
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_pin_get_set_level)
+{
+ const struct gpio_dt_spec *gp = GPIO_DT_FROM_NODELABEL(gpio_test);
+
+ /* Test invalid signal */
+ zassert_equal(NULL, gpio_get_dt_spec(-1), "Expected NULL ptr");
+
+ zassert_false(gp == NULL, "Unexpected NULL ptr");
+ /* Test valid signal */
+ gpio_pin_set_dt(gp, 0);
+ zassert_equal(0, gpio_pin_get_dt(gp), "Expected level==0");
+
+ gpio_pin_set_dt(gp, 1);
+ zassert_equal(1, gpio_pin_get_dt(gp), "Expected level==1");
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO get name.
+ *
+ * @details
+ * Validate gpio_get_name
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_get_name)
+{
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_test));
+ const char *signal_name;
+
+ /* Test invalid signal */
+ signal_name = gpio_get_name(GPIO_COUNT);
+ zassert_mem_equal("UNIMPLEMENTED", signal_name, strlen(signal_name),
+ "gpio_get_name returned a valid signal \'%s\'",
+ signal_name);
+
+ /* Test valid signal */
+ signal_name = gpio_get_name(signal);
+ zassert_mem_equal("test", signal_name, strlen(signal_name),
+ "gpio_get_name returned signal \'%s\'", signal_name);
+}
+
+/**
+ * @brief Helper function to get GPIO flags
+ *
+ * @param signal
+ * @return gpio_flags_t
+ */
+gpio_flags_t gpio_helper_get_flags(enum gpio_signal signal)
+{
+ const struct gpio_dt_spec *spec;
+ gpio_flags_t flags;
+
+ spec = gpio_get_dt_spec(signal);
+ gpio_emul_flags_get(spec->port, spec->pin, &flags);
+
+ return flags;
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO get default flags.
+ *
+ * @details
+ * Validate gpio_get_default_flags
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_get_default_flags)
+{
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_test));
+ gpio_flags_t flags;
+ gpio_flags_t flags_at_start[GPIO_COUNT];
+ int def_flags;
+
+ /* Snapshot of GPIO flags before testing */
+ for (int i = 0; i < GPIO_COUNT; i++)
+ flags_at_start[i] = gpio_helper_get_flags(i);
+
+ /* Test invalid signal */
+ def_flags = gpio_get_default_flags(GPIO_COUNT);
+ zassert_equal(0, def_flags, "Expected 0x0, returned 0x%08X", def_flags);
+ gpio_set_flags(GPIO_COUNT, GPIO_INPUT);
+
+ /* Verify flags didn't change */
+ for (int i = 0; i < GPIO_COUNT; i++) {
+ flags = gpio_helper_get_flags(i);
+ zassert_equal(flags_at_start[i], flags,
+ "%s[%d] flags_at_start=0x%x, flags=0x%x",
+ gpio_get_name(i), i, flags_at_start[i], flags);
+ }
+
+ /* Test valid signal */
+ def_flags = gpio_get_default_flags(signal);
+ zassert_equal(GPIO_INPUT | GPIO_OUTPUT, def_flags,
+ "Expected 0x%08x, returned 0x%08X",
+ GPIO_INPUT | GPIO_OUTPUT, def_flags);
+
+ gpio_set_flags(signal, GPIO_INPUT);
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(flags, GPIO_INPUT, "Flags set 0x%x", flags);
+
+ gpio_set_flags(signal, GPIO_OUTPUT);
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(flags, GPIO_OUTPUT, "Flags set 0x%x", flags);
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO no-auto-init.
+ *
+ * @details
+ * Validate no-auto-init device tree property,
+ * which will not initialise the GPIO at startup.
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_no_auto_init)
+{
+ const struct gpio_dt_spec *gp = GPIO_DT_FROM_NODELABEL(gpio_no_init);
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_no_init));
+ gpio_flags_t flags;
+
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(0, flags, "Expected 0x%08x, returned 0x%08X", 0, flags);
+
+ /* Configure pin. */
+ gpio_pin_configure_dt(gp, GPIO_INPUT | GPIO_OUTPUT);
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(flags, (GPIO_ACTIVE_LOW | GPIO_OUTPUT | GPIO_INPUT),
+ "Flags set 0x%x", flags);
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO reset.
+ *
+ * @details
+ * Validate gpio_reset
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_reset)
+{
+ enum gpio_signal signal = GPIO_SIGNAL(DT_NODELABEL(gpio_test));
+ gpio_flags_t flags;
+ gpio_flags_t flags_at_start[GPIO_COUNT];
+
+ /* Snapshot of GPIO flags before testing */
+ for (int i = 0; i < GPIO_COUNT; i++)
+ flags_at_start[i] = gpio_helper_get_flags(i);
+
+ /* Test reset on invalid signal */
+ gpio_reset(GPIO_COUNT);
+
+ /* Verify flags didn't change */
+ for (int i = 0; i < GPIO_COUNT; i++) {
+ flags = gpio_helper_get_flags(i);
+ zassert_equal(flags_at_start[i], flags,
+ "%s[%d] flags_at_start=0x%x, flags=0x%x",
+ gpio_get_name(i), i, flags_at_start[i], flags);
+ }
+
+ /* Test reset on valid signal */
+ gpio_set_flags(signal, GPIO_OUTPUT);
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(flags, GPIO_OUTPUT, "Flags set 0x%x", flags);
+
+ gpio_reset(signal);
+
+ flags = gpio_helper_get_flags(signal);
+ zassert_equal(flags, gpio_get_default_flags(signal), "Flags set 0x%x",
+ flags);
+}
+
+/**
+ * @brief TestPurpose: Verify GPIO enable/disable interrupt.
+ *
+ * @details
+ * Validate gpio_enable_dt_interrupt
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(gpio, test_gpio_enable_dt_interrupt)
+{
+ const struct gpio_dt_spec *gp = GPIO_DT_FROM_NODELABEL(gpio_test);
+ const struct gpio_int_config *intr =
+ GPIO_INT_FROM_NODELABEL(int_gpio_test);
+
+ gpio_test_interrupt_triggered = false;
+
+ /* Test valid signal */
+ zassert_ok(gpio_disable_dt_interrupt(intr), NULL);
+ gpio_pin_set_dt(gp, 0);
+ zassert_false(gpio_test_interrupt_triggered, NULL);
+ gpio_pin_set_dt(gp, 1);
+ zassert_false(gpio_test_interrupt_triggered, NULL);
+
+ zassert_ok(gpio_enable_dt_interrupt(intr), NULL);
+ gpio_pin_set_dt(gp, 0);
+ zassert_true(gpio_test_interrupt_triggered, NULL);
+ gpio_test_interrupt_triggered = false;
+ gpio_pin_set_dt(gp, 1);
+ zassert_true(gpio_test_interrupt_triggered, NULL);
+}
+
+/**
+ * @brief GPIO test setup handler.
+ */
+static void gpio_before(void *state)
+{
+ ARG_UNUSED(state);
+ /** TODO: Reset all signals here. Currently other tests fail when reset
+ * for(int i = 0; i < GPIO_COUNT; i++) {
+ * gpio_reset(i);
+ * }
+ */
+ gpio_reset(GPIO_SIGNAL(DT_NODELABEL(gpio_test)));
+}
+
+/**
+ * @brief Test Suite: Verifies GPIO functionality.
+ */
+ZTEST_SUITE(gpio, drivers_predicate_post_main, NULL, gpio_before, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/i2c.c b/zephyr/test/drivers/default/src/i2c.c
new file mode 100644
index 0000000000..caced4aedf
--- /dev/null
+++ b/zephyr/test/drivers/default/src/i2c.c
@@ -0,0 +1,145 @@
+/* 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 "ec_commands.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_USER(i2c, test_i2c_set_speed_success)
+{
+ struct ec_response_i2c_control response;
+ struct ec_params_i2c_control get_params = {
+ .port = I2C_PORT_USB_C0,
+ .cmd = EC_I2C_CONTROL_GET_SPEED,
+ };
+ struct host_cmd_handler_args get_args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, get_params);
+ struct ec_params_i2c_control set_params = {
+ .port = I2C_PORT_USB_C0,
+ .cmd = EC_I2C_CONTROL_SET_SPEED,
+ };
+ struct host_cmd_handler_args set_args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, set_params);
+
+ /* Get the speed: 100. */
+ zassert_ok(host_command_process(&get_args), NULL);
+ zassert_ok(get_args.result, NULL);
+ zassert_equal(get_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.cmd_response.speed_khz, 100,
+ "response.cmd_response.speed_khz = %d",
+ response.cmd_response.speed_khz);
+
+ /* Set the speed to 400. */
+ set_params.cmd_params.speed_khz = 400;
+ zassert_ok(host_command_process(&set_args), NULL);
+ zassert_ok(set_args.result, NULL);
+ zassert_equal(set_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.cmd_response.speed_khz, 100,
+ "response.cmd_response.speed_khz = %d",
+ response.cmd_response.speed_khz);
+
+ /* Get the speed to verify. */
+ zassert_ok(host_command_process(&get_args), NULL);
+ zassert_ok(get_args.result, NULL);
+ zassert_equal(get_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.cmd_response.speed_khz, 400,
+ "response.cmd_response.speed_khz = %d",
+ response.cmd_response.speed_khz);
+
+ /* Set the speed back to 100. */
+ set_params.cmd_params.speed_khz = 100;
+ zassert_ok(host_command_process(&set_args), NULL);
+ zassert_ok(set_args.result, NULL);
+ zassert_equal(set_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.cmd_response.speed_khz, 400,
+ "response.cmd_response.speed_khz = %d",
+ response.cmd_response.speed_khz);
+}
+
+ZTEST_USER(i2c, test_i2c_set_speed_not_dynamic)
+{
+ struct ec_response_i2c_control response;
+ struct ec_params_i2c_control set_params = {
+ .port = I2C_PORT_POWER,
+ .cmd = EC_I2C_CONTROL_SET_SPEED,
+ .cmd_params.speed_khz = 400,
+ };
+ struct host_cmd_handler_args set_args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, set_params);
+
+ /* Set the speed to 400 on a bus which doesn't support dynamic-speed. */
+ zassert_equal(EC_RES_ERROR, host_command_process(&set_args), NULL);
+}
+
+ZTEST_USER(i2c, test_i2c_control_wrong_port)
+{
+ struct ec_response_i2c_control response;
+ struct ec_params_i2c_control get_params = {
+ .port = 10,
+ .cmd = EC_I2C_CONTROL_GET_SPEED,
+ };
+ struct host_cmd_handler_args get_args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, get_params);
+
+ /* Set the .port=10, which is not defined. */
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&get_args),
+ NULL);
+}
+
+ZTEST_USER(i2c, test_i2c_control_wrong_cmd)
+{
+ struct ec_response_i2c_control response;
+ struct ec_params_i2c_control params = {
+ .port = I2C_PORT_USB_C0,
+ .cmd = 10,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, params);
+
+ /* Call the .cmd=10, which is not defined. */
+ zassert_equal(EC_RES_INVALID_COMMAND, host_command_process(&args),
+ NULL);
+}
+
+ZTEST_USER(i2c, test_i2c_set_speed_wrong_freq)
+{
+ struct ec_response_i2c_control response;
+ struct ec_params_i2c_control set_params = {
+ .port = I2C_PORT_USB_C0,
+ .cmd = EC_I2C_CONTROL_SET_SPEED,
+ .cmd_params.speed_khz = 123,
+ };
+ struct host_cmd_handler_args set_args =
+ BUILD_HOST_COMMAND(EC_CMD_I2C_CONTROL, 0, response, set_params);
+
+ /* Set the speed to 123 KHz (an invalid speed). */
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&set_args),
+ NULL);
+}
+
+static void i2c_freq_reset(void)
+{
+ /* The test modifies this port. Reset it to the DTS defined. */
+ zassert_ok(i2c_set_freq(I2C_PORT_USB_C0, I2C_FREQ_100KHZ), NULL);
+}
+
+static void *i2c_setup(void)
+{
+ i2c_freq_reset();
+ return NULL;
+}
+
+static void i2c_teardown(void *state)
+{
+ ARG_UNUSED(state);
+ i2c_freq_reset();
+}
+
+ZTEST_SUITE(i2c, drivers_predicate_post_main, i2c_setup, NULL, NULL,
+ i2c_teardown);
diff --git a/zephyr/test/drivers/default/src/i2c_passthru.c b/zephyr/test/drivers/default/src/i2c_passthru.c
new file mode 100644
index 0000000000..aea81fc198
--- /dev/null
+++ b/zephyr/test/drivers/default/src/i2c_passthru.c
@@ -0,0 +1,123 @@
+/* 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 "driver/ln9310.h"
+#include "ec_commands.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_USER(i2c_passthru, test_read_without_write)
+{
+ uint8_t param_buf[sizeof(struct ec_params_i2c_passthru) +
+ sizeof(struct ec_params_i2c_passthru_msg)];
+ uint8_t response_buf[sizeof(struct ec_response_i2c_passthru) + 2];
+ struct ec_params_i2c_passthru *params =
+ (struct ec_params_i2c_passthru *)&param_buf;
+ struct ec_response_i2c_passthru *response =
+ (struct ec_response_i2c_passthru *)&response_buf;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_I2C_PASSTHRU, 0);
+
+ params->port = I2C_PORT_POWER;
+ params->num_msgs = 1;
+ params->msg[0].addr_flags = LN9310_I2C_ADDR_0_FLAGS | EC_I2C_FLAG_READ;
+ params->msg[0].len = 1;
+ args.params = &param_buf;
+ args.params_size = sizeof(param_buf);
+ args.response = &response_buf;
+ args.response_max = sizeof(response_buf);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(response->i2c_status, EC_I2C_STATUS_NAK, NULL);
+ zassert_equal(args.response_size,
+ sizeof(struct ec_response_i2c_passthru), NULL);
+}
+
+ZTEST_USER(i2c_passthru, test_passthru_protect)
+{
+ struct ec_response_i2c_passthru_protect response;
+ struct ec_params_i2c_passthru_protect status_params = {
+ .port = I2C_PORT_SENSOR,
+ .subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_STATUS,
+ };
+ struct host_cmd_handler_args status_args = BUILD_HOST_COMMAND(
+ EC_CMD_I2C_PASSTHRU_PROTECT, 0, response, status_params);
+ struct ec_params_i2c_passthru_protect enable_params = {
+ .port = I2C_PORT_SENSOR,
+ .subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE,
+ };
+ struct host_cmd_handler_args enable_args = BUILD_HOST_COMMAND_PARAMS(
+ EC_CMD_I2C_PASSTHRU_PROTECT, 0, enable_params);
+
+ /* Check the protect status: 0 (unprotected) */
+ zassert_ok(host_command_process(&status_args), NULL);
+ zassert_ok(status_args.result, NULL);
+ zassert_equal(status_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, 0, "response.status = %d",
+ response.status);
+
+ /* Protect the bus */
+ zassert_ok(host_command_process(&enable_args), NULL);
+ zassert_ok(enable_args.result, NULL);
+
+ /* Check the protect status: 1 (protected) */
+ zassert_ok(host_command_process(&status_args), NULL);
+ zassert_ok(status_args.result, NULL);
+ zassert_equal(status_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, 1, "response.status = %d",
+ response.status);
+
+ /* Error case: wrong subcmd */
+ status_params.subcmd = 10;
+ zassert_equal(host_command_process(&status_args),
+ EC_RES_INVALID_COMMAND, NULL);
+ status_params.subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_STATUS;
+
+ /* Error case: wrong port */
+ status_params.port = 10;
+ zassert_equal(host_command_process(&status_args), EC_RES_INVALID_PARAM,
+ NULL);
+ status_params.port = I2C_PORT_SENSOR;
+
+ /* Error case: response size not enough */
+ status_args.response_max = 0;
+ zassert_equal(host_command_process(&status_args), EC_RES_INVALID_PARAM,
+ NULL);
+ status_args.response_max = sizeof(response);
+
+ /* Error case: params size not enough */
+ status_args.params_size = 0;
+ zassert_equal(host_command_process(&status_args), EC_RES_INVALID_PARAM,
+ NULL);
+ status_args.params_size = sizeof(status_params);
+}
+
+ZTEST_USER(i2c_passthru, test_passthru_protect_tcpcs)
+{
+ struct ec_params_i2c_passthru_protect enable_params = {
+ .port = I2C_PORT_SENSOR,
+ .subcmd = EC_CMD_I2C_PASSTHRU_PROTECT_ENABLE_TCPCS,
+ };
+ struct host_cmd_handler_args enable_args = BUILD_HOST_COMMAND_PARAMS(
+ EC_CMD_I2C_PASSTHRU_PROTECT, 0, enable_params);
+
+ /* Protect the all TCPC buses */
+ zassert_ok(host_command_process(&enable_args), NULL);
+ zassert_ok(enable_args.result, NULL);
+}
+
+static void i2c_passthru_after(void *state)
+{
+ ARG_UNUSED(state);
+ i2c_passthru_protect_reset();
+}
+
+ZTEST_SUITE(i2c_passthru, drivers_predicate_post_main, NULL, NULL,
+ i2c_passthru_after, NULL);
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));
+}
diff --git a/zephyr/test/drivers/default/src/isl923x.c b/zephyr/test/drivers/default/src/isl923x.c
new file mode 100644
index 0000000000..9144730887
--- /dev/null
+++ b/zephyr/test/drivers/default/src/isl923x.c
@@ -0,0 +1,1076 @@
+/* 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/ztest.h>
+#include <zephyr/drivers/emul.h>
+#include <zephyr/fff.h>
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "test/drivers/charger_utils.h"
+#include "driver/charger/isl923x.h"
+#include "driver/charger/isl923x_public.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_isl923x.h"
+#include "system.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+BUILD_ASSERT(CONFIG_CHARGER_SENSE_RESISTOR == 10 ||
+ CONFIG_CHARGER_SENSE_RESISTOR == 5);
+
+BUILD_ASSERT(CONFIG_CHARGER_SENSE_RESISTOR_AC == 20 ||
+ CONFIG_CHARGER_SENSE_RESISTOR_AC == 10);
+
+BUILD_ASSERT(IS_ENABLED(CONFIG_CHARGER_ISL9238),
+ "Must test on ISL9238; ISL9237, ISL9238c, and RAA489000 are not"
+ " yet supported");
+
+#if CONFIG_CHARGER_SENSE_RESISTOR == 10
+#define EXPECTED_CURRENT_MA(n) (n)
+#define EXPECTED_CURRENT_REG(n) (n)
+#else
+#define EXPECTED_CURRENT_MA(n) (n * 2)
+#define EXPECTED_CURRENT_REG(n) (n / 2)
+#endif
+
+#if CONFIG_CHARGER_SENSE_RESISTOR_AC == 20
+#define EXPECTED_INPUT_CURRENT_MA(n) (n)
+#define EXPECTED_INPUT_CURRENT_REG(n) (n)
+#else
+#define EXPECTED_INPUT_CURRENT_MA(n) (n * 2)
+#define EXPECTED_INPUT_CURRENT_REG(n) (n / 2)
+#endif
+
+#define CHARGER_NUM get_charger_num(&isl923x_drv)
+#define ISL923X_EMUL EMUL_DT_GET(DT_NODELABEL(isl923x_emul))
+#define COMMON_DATA emul_isl923x_get_i2c_common_data(ISL923X_EMUL)
+
+static int mock_write_fn_always_fail(const struct emul *emul, int reg,
+ uint8_t val, int bytes, void *data)
+{
+ ztest_test_fail();
+ return 0;
+}
+
+ZTEST(isl923x, test_isl923x_set_current)
+{
+ int expected_current_milli_amps[] = {
+ EXPECTED_CURRENT_MA(0), EXPECTED_CURRENT_MA(4),
+ EXPECTED_CURRENT_MA(8), EXPECTED_CURRENT_MA(16),
+ EXPECTED_CURRENT_MA(32), EXPECTED_CURRENT_MA(64),
+ EXPECTED_CURRENT_MA(128), EXPECTED_CURRENT_MA(256),
+ EXPECTED_CURRENT_MA(512), EXPECTED_CURRENT_MA(1024),
+ EXPECTED_CURRENT_MA(2048), EXPECTED_CURRENT_MA(4096)
+ };
+ int current_milli_amps;
+
+ /* Test I2C failure when reading charge current */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CHG_CURRENT);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.get_current(CHARGER_NUM, &current_milli_amps),
+ NULL);
+
+ /* Reset fail register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ for (int i = 0; i < ARRAY_SIZE(expected_current_milli_amps); ++i) {
+ zassert_ok(isl923x_drv.set_current(
+ CHARGER_NUM, expected_current_milli_amps[i]),
+ "Failed to set the current to %dmA",
+ expected_current_milli_amps[i]);
+ zassert_ok(isl923x_drv.get_current(CHARGER_NUM,
+ &current_milli_amps),
+ "Failed to get current");
+ zassert_equal(expected_current_milli_amps[i],
+ current_milli_amps,
+ "Expected current %dmA but got %dmA",
+ expected_current_milli_amps[i],
+ current_milli_amps);
+ }
+}
+
+ZTEST(isl923x, test_isl923x_set_voltage)
+{
+ int expected_voltage_milli_volts[] = { 8, 16, 32, 64,
+ 128, 256, 512, 1024,
+ 2048, 4096, 8192, 16384 };
+ int voltage_milli_volts;
+
+ /* Test 0mV first, it's a special case because of voltage_min */
+ zassert_ok(isl923x_drv.set_voltage(CHARGER_NUM, 0),
+ "Failed to set the voltage to 0mV");
+ zassert_ok(isl923x_drv.get_voltage(CHARGER_NUM, &voltage_milli_volts),
+ "Failed to get voltage");
+ zassert_equal(battery_get_info()->voltage_min, voltage_milli_volts,
+ "Expected voltage %dmV but got %dmV",
+ battery_get_info()->voltage_min, voltage_milli_volts);
+
+ for (int i = 0; i < ARRAY_SIZE(expected_voltage_milli_volts); ++i) {
+ zassert_ok(isl923x_drv.set_voltage(
+ CHARGER_NUM,
+ expected_voltage_milli_volts[i]),
+ "Failed to set the voltage to %dmV",
+ expected_voltage_milli_volts[i]);
+ zassert_ok(isl923x_drv.get_voltage(CHARGER_NUM,
+ &voltage_milli_volts),
+ "Failed to get voltage");
+ zassert_equal(expected_voltage_milli_volts[i],
+ voltage_milli_volts,
+ "Expected voltage %dmV but got %dmV",
+ expected_voltage_milli_volts[i],
+ voltage_milli_volts);
+ }
+}
+
+ZTEST(isl923x, test_isl923x_set_input_current_limit)
+{
+ int expected_current_milli_amps[] = { EXPECTED_INPUT_CURRENT_MA(0),
+ EXPECTED_INPUT_CURRENT_MA(4),
+ EXPECTED_INPUT_CURRENT_MA(8),
+ EXPECTED_INPUT_CURRENT_MA(16),
+ EXPECTED_INPUT_CURRENT_MA(32),
+ EXPECTED_INPUT_CURRENT_MA(64),
+ EXPECTED_INPUT_CURRENT_MA(128),
+ EXPECTED_INPUT_CURRENT_MA(256),
+ EXPECTED_INPUT_CURRENT_MA(512),
+ EXPECTED_INPUT_CURRENT_MA(1024),
+ EXPECTED_INPUT_CURRENT_MA(2048),
+ EXPECTED_INPUT_CURRENT_MA(4096) };
+ int current_milli_amps;
+
+ /* Test failing to write to current limit 1 reg */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ ISL923X_REG_ADAPTER_CURRENT_LIMIT1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.set_input_current_limit(CHARGER_NUM, 0),
+ NULL);
+
+ /* Test failing to write to current limit 2 reg */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ ISL923X_REG_ADAPTER_CURRENT_LIMIT2);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.set_input_current_limit(CHARGER_NUM, 0),
+ NULL);
+
+ /* Reset fail register */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test failing to read current limit 1 reg */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ ISL923X_REG_ADAPTER_CURRENT_LIMIT1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &current_milli_amps),
+ NULL);
+
+ /* Reset fail register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test normal code path */
+ for (int i = 0; i < ARRAY_SIZE(expected_current_milli_amps); ++i) {
+ zassert_ok(isl923x_drv.set_input_current_limit(
+ CHARGER_NUM, expected_current_milli_amps[i]),
+ "Failed to set input current limit to %dmV",
+ expected_current_milli_amps[i]);
+ zassert_ok(isl923x_drv.get_input_current_limit(
+ CHARGER_NUM, &current_milli_amps),
+ "Failed to get input current limit");
+ zassert_equal(expected_current_milli_amps[i],
+ current_milli_amps,
+ "Expected input current %dmA but got %dmA",
+ expected_current_milli_amps[i],
+ current_milli_amps);
+ }
+}
+
+ZTEST(isl923x, test_isl923x_psys)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "psys"), NULL);
+}
+
+ZTEST(isl923x, test_manufacturer_id)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ int id;
+
+ isl923x_emul_set_manufacturer_id(isl923x_emul, 0x1234);
+ zassert_ok(isl923x_drv.manufacturer_id(CHARGER_NUM, &id), NULL);
+ zassert_equal(0x1234, id, NULL);
+
+ /* Test read error */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ ISL923X_REG_MANUFACTURER_ID);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.manufacturer_id(CHARGER_NUM, &id), NULL);
+
+ /* Reset fail register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST(isl923x, test_device_id)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ int id;
+
+ isl923x_emul_set_device_id(isl923x_emul, 0x5678);
+ zassert_ok(isl923x_drv.device_id(CHARGER_NUM, &id), NULL);
+ zassert_equal(0x5678, id, NULL);
+
+ /* Test read error */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_DEVICE_ID);
+ zassert_equal(EC_ERROR_INVAL, isl923x_drv.device_id(CHARGER_NUM, &id),
+ NULL);
+
+ /* Reset fail register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST(isl923x, test_options)
+{
+ uint32_t option;
+
+ /* Test failed control 0 read */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL0);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.get_option(CHARGER_NUM, &option), NULL);
+
+ /* Test failed control 1 read */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.get_option(CHARGER_NUM, &option), NULL);
+
+ /* Reset failed read */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test failed control 0 write */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL0);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.set_option(CHARGER_NUM, option), NULL);
+
+ /* Test failed control 1 write */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.set_option(CHARGER_NUM, option), NULL);
+
+ /* Reset failed write */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test normal write/read, note that bits 23 and 0 are always 0 */
+ zassert_ok(isl923x_drv.set_option(CHARGER_NUM, 0xffffffff), NULL);
+ zassert_ok(isl923x_drv.get_option(CHARGER_NUM, &option), NULL);
+ zassert_equal(0xff7ffffe, option,
+ "Expected options 0xff7ffffe but got 0x%x", option);
+}
+
+ZTEST(isl923x, test_get_info)
+{
+ const struct charger_info *info = isl923x_drv.get_info(CHARGER_NUM);
+
+ zassert_ok(strcmp("isl9238", info->name), NULL);
+ zassert_equal(ISL9238_SYS_VOLTAGE_REG_MAX, info->voltage_max, NULL);
+ zassert_equal(ISL923X_SYS_VOLTAGE_REG_MIN, info->voltage_min, NULL);
+ zassert_equal(8, info->voltage_step, NULL);
+ zassert_equal(EXPECTED_CURRENT_MA(6080), info->current_max, NULL);
+ zassert_equal(EXPECTED_CURRENT_MA(4), info->current_min, NULL);
+ zassert_equal(EXPECTED_CURRENT_MA(4), info->current_step, NULL);
+ zassert_equal(EXPECTED_INPUT_CURRENT_MA(6080), info->input_current_max,
+ NULL);
+ zassert_equal(EXPECTED_INPUT_CURRENT_MA(4), info->input_current_min,
+ NULL);
+ zassert_equal(EXPECTED_INPUT_CURRENT_MA(4), info->input_current_step,
+ NULL);
+}
+
+ZTEST(isl923x, test_status)
+{
+ int status;
+
+ zassert_ok(isl923x_drv.get_status(CHARGER_NUM, &status), NULL);
+ zassert_equal(CHARGER_LEVEL_2, status, NULL);
+}
+
+ZTEST(isl923x, test_set_mode)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+
+ /* Enable learn mode and set mode (actual value doesn't matter) */
+ zassert_ok(isl923x_drv.discharge_on_ac(CHARGER_NUM, true), NULL);
+ zassert_ok(isl923x_drv.set_mode(CHARGER_NUM, 0), NULL);
+ /* Learn mode should still be set */
+ zassert_true(isl923x_emul_is_learn_mode_enabled(isl923x_emul), NULL);
+
+ /* Disable learn mode, but keep the bits */
+ zassert_ok(isl923x_drv.discharge_on_ac(CHARGER_NUM, false), NULL);
+ isl923x_emul_set_learn_mode_enabled(isl923x_emul, true);
+ zassert_ok(isl923x_drv.set_mode(CHARGER_NUM, 0), NULL);
+ /* Learn mode should still be off */
+ zassert_true(!isl923x_emul_is_learn_mode_enabled(isl923x_emul), NULL);
+}
+
+ZTEST(isl923x, test_post_init)
+{
+ zassert_ok(isl923x_drv.post_init(CHARGER_NUM), NULL);
+}
+
+ZTEST(isl923x, test_set_ac_prochot)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ const struct device *i2c_dev = isl923x_emul_get_parent(isl923x_emul);
+ uint16_t expected_current_milli_amps[] = {
+ EXPECTED_INPUT_CURRENT_MA(0),
+ EXPECTED_INPUT_CURRENT_MA(128),
+ EXPECTED_INPUT_CURRENT_MA(256),
+ EXPECTED_INPUT_CURRENT_MA(512),
+ EXPECTED_INPUT_CURRENT_MA(1024),
+ EXPECTED_INPUT_CURRENT_MA(2048),
+ EXPECTED_INPUT_CURRENT_MA(4096)
+ };
+ uint16_t current_milli_amps;
+
+ /* Test can't set current above max */
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_set_ac_prochot(
+ CHARGER_NUM, ISL923X_AC_PROCHOT_CURRENT_MAX + 1),
+ NULL);
+
+ /* Test failed I2C write to prochot register */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_PROCHOT_AC);
+ zassert_equal(EC_ERROR_INVAL, isl923x_set_ac_prochot(CHARGER_NUM, 0),
+ NULL);
+
+ /* Clear write fail reg */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ for (int i = 0; i < ARRAY_SIZE(expected_current_milli_amps); ++i) {
+ uint8_t reg_addr = ISL923X_REG_PROCHOT_AC;
+
+ /*
+ * Due to resistor multiplying the current, the upper end of the
+ * test data might be out of bounds (which is already tested
+ * above). Skip the test.
+ */
+ if (expected_current_milli_amps[i] >
+ ISL923X_AC_PROCHOT_CURRENT_MAX) {
+ continue;
+ }
+
+ zassert_ok(isl923x_set_ac_prochot(
+ CHARGER_NUM, expected_current_milli_amps[i]),
+ "Failed to set AC prochot to %dmA",
+ expected_current_milli_amps[i]);
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr),
+ &current_milli_amps,
+ sizeof(current_milli_amps)),
+ "Failed to read AC prochot register");
+ zassert_equal(EXPECTED_INPUT_CURRENT_REG(
+ expected_current_milli_amps[i]),
+ current_milli_amps,
+ "AC prochot expected %dmA but got %dmA",
+ EXPECTED_INPUT_CURRENT_REG(
+ expected_current_milli_amps[i]),
+ current_milli_amps);
+ }
+}
+ZTEST(isl923x, test_set_dc_prochot)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ const struct device *i2c_dev = isl923x_emul_get_parent(isl923x_emul);
+ uint16_t expected_current_milli_amps[] = {
+ EXPECTED_CURRENT_MA(256), EXPECTED_CURRENT_MA(512),
+ EXPECTED_CURRENT_MA(1024), EXPECTED_CURRENT_MA(2048),
+ EXPECTED_CURRENT_MA(4096), EXPECTED_CURRENT_MA(8192)
+ };
+ uint16_t current_milli_amps;
+
+ /* Test can't set current above max */
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_set_dc_prochot(
+ CHARGER_NUM, ISL923X_DC_PROCHOT_CURRENT_MAX + 1),
+ NULL);
+
+ /* Test failed I2C write to prochot register */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_PROCHOT_DC);
+ zassert_equal(EC_ERROR_INVAL, isl923x_set_dc_prochot(CHARGER_NUM, 0),
+ NULL);
+
+ /* Clear write fail reg */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ for (int i = 0; i < ARRAY_SIZE(expected_current_milli_amps); ++i) {
+ uint8_t reg_addr = ISL923X_REG_PROCHOT_DC;
+
+ /*
+ * Due to resistor multiplying the current, the upper end of the
+ * test data might be out of bounds (which is already tested
+ * above). Skip the test.
+ */
+ if (expected_current_milli_amps[i] >
+ ISL923X_DC_PROCHOT_CURRENT_MAX) {
+ continue;
+ }
+ zassert_ok(isl923x_set_dc_prochot(
+ CHARGER_NUM, expected_current_milli_amps[i]),
+ "Failed to set DC prochot to %dmA",
+ expected_current_milli_amps[i]);
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr),
+ &current_milli_amps,
+ sizeof(current_milli_amps)),
+ "Failed to read DC prochot register");
+ zassert_equal(
+ EXPECTED_CURRENT_REG(expected_current_milli_amps[i]),
+ current_milli_amps,
+ "AC prochot expected %dmA but got %dmA",
+ EXPECTED_CURRENT_REG(expected_current_milli_amps[i]),
+ current_milli_amps);
+ }
+}
+
+ZTEST(isl923x, test_comparator_inversion)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ const struct device *i2c_dev = isl923x_emul_get_parent(isl923x_emul);
+ uint8_t reg_addr = ISL923X_REG_CONTROL2;
+ uint16_t reg_value;
+ uint8_t tx_buf[] = { reg_addr, 0, 0 };
+
+ /* Test failed read, should not write */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL2);
+ i2c_common_emul_set_write_func(COMMON_DATA, mock_write_fn_always_fail,
+ NULL);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_set_comparator_inversion(CHARGER_NUM, false),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_func(COMMON_DATA, NULL, NULL);
+
+ /* Test failed write */
+ zassert_ok(i2c_write(i2c_dev, tx_buf, sizeof(tx_buf),
+ isl923x_emul->bus.i2c->addr),
+ "Failed to clear CTRL2 register");
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL2);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_set_comparator_inversion(CHARGER_NUM, true),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test enable comparator inversion */
+ zassert_ok(isl923x_set_comparator_inversion(CHARGER_NUM, true), NULL);
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr), &reg_value,
+ sizeof(reg_value)),
+ "Failed to read CTRL 2 register");
+ zassert_true((reg_value & ISL923X_C2_INVERT_CMOUT) != 0, NULL);
+
+ /* Test disable comparator inversion */
+ zassert_ok(isl923x_set_comparator_inversion(CHARGER_NUM, false), NULL);
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr), &reg_value,
+ sizeof(reg_value)),
+ "Failed to read CTRL 2 register");
+ zassert_true((reg_value & ISL923X_C2_INVERT_CMOUT) == 0, NULL);
+}
+
+ZTEST(isl923x, test_discharge_on_ac)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ const struct device *i2c_dev = isl923x_emul_get_parent(isl923x_emul);
+ const struct i2c_common_emul_cfg *cfg =
+ isl923x_emul_get_cfg(isl923x_emul);
+ uint8_t reg_addr = ISL923X_REG_CONTROL1;
+ uint8_t tx_buf[] = { reg_addr, 0, 0 };
+ uint16_t reg_value;
+
+ /* Test failure to read CTRL1 register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.discharge_on_ac(CHARGER_NUM, true), NULL);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set CTRL1 register to 0 */
+ zassert_ok(i2c_write(i2c_dev, tx_buf, sizeof(tx_buf), cfg->addr), NULL);
+
+ /* Test failure to write CTRL1 register */
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL1);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.discharge_on_ac(CHARGER_NUM, true), NULL);
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr), &reg_value,
+ sizeof(reg_value)),
+ NULL);
+ zassert_equal(0, reg_value, NULL);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test enabling discharge on AC */
+ zassert_ok(isl923x_drv.discharge_on_ac(CHARGER_NUM, true), NULL);
+
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr), &reg_value,
+ sizeof(reg_value)),
+ NULL);
+ zassert_true((reg_value & ISL923X_C1_LEARN_MODE_ENABLE) != 0, NULL);
+
+ /* Test disabling discharge on AC */
+ zassert_ok(isl923x_drv.discharge_on_ac(CHARGER_NUM, false), NULL);
+
+ zassert_ok(i2c_write_read(i2c_dev, isl923x_emul->bus.i2c->addr,
+ &reg_addr, sizeof(reg_addr), &reg_value,
+ sizeof(reg_value)),
+ NULL);
+ zassert_true((reg_value & ISL923X_C1_LEARN_MODE_ENABLE) == 0, NULL);
+}
+
+ZTEST(isl923x, test_get_vbus_voltage)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ /* Standard fixed-power PD source voltages. */
+ int test_voltage_mv[] = { 5000, 9000, 15000, 20000 };
+ int voltage;
+
+ /* Test fail to read the ADC vbus register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, RAA489000_REG_ADC_VBUS);
+ zassert_equal(EC_ERROR_INVAL,
+ isl923x_drv.get_vbus_voltage(CHARGER_NUM, 0, &voltage),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ for (int i = 0; i < ARRAY_SIZE(test_voltage_mv); ++i) {
+ int expected_voltage_mv = test_voltage_mv[i];
+
+ isl923x_emul_set_adc_vbus(isl923x_emul, expected_voltage_mv);
+ zassert_ok(isl923x_drv.get_vbus_voltage(CHARGER_NUM, 0,
+ &voltage),
+ NULL);
+ /* isl923x_get_vbus_voltage treats the measured voltage as
+ * having an effective step size of 96 mV. This is slightly
+ * different than the scheme described in the ISL9238 datasheet.
+ * Reported VBUS should therefore be within 100 mV of nominal
+ * VBUS.
+ */
+ zassert_within(expected_voltage_mv, voltage, 100,
+ "Expected %dmV but got %dmV",
+ expected_voltage_mv, voltage);
+ }
+}
+
+ZTEST(isl923x, test_init)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ int input_current;
+
+ /* Test failed CTRL2 register read (prochot debounce) */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL2);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed CTRL2 register write */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL2);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed CTRL 0 read */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL0);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed CTRL 0 write */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL0);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed CTRL 3 read */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL9238_REG_CONTROL3);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed CTRL 3 write */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA, ISL9238_REG_CONTROL3);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+
+ /* Test failed write adapter current limit */
+ isl923x_emul_reset_registers(isl923x_emul);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ ISL923X_REG_ADAPTER_CURRENT_LIMIT1);
+ isl923x_drv.init(CHARGER_NUM);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_ok(isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ NULL);
+ zassert_equal(0, input_current,
+ "Expected input current 0mA but got %dmA", input_current);
+}
+
+ZTEST(isl923x, test_init_late_jump)
+{
+ int input_current;
+
+ isl923x_drv.init(CHARGER_NUM);
+
+ /* Init again with system_jumped_late() returning true and make sure
+ * the input current limit is still correct.
+ */
+
+ system_jumped_late_fake.return_val = 1;
+ isl923x_drv.init(CHARGER_NUM);
+
+ zassert_equal(EC_SUCCESS,
+ isl923x_drv.get_input_current_limit(CHARGER_NUM,
+ &input_current),
+ "Could not read input current limit.");
+ zassert_equal(CONFIG_CHARGER_INPUT_CURRENT, input_current,
+ "Input current (%d) not at (%d)", input_current,
+ CONFIG_CHARGER_INPUT_CURRENT);
+}
+
+ZTEST(isl923x, test_isl923x_is_acok)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ enum ec_error_list rv;
+ bool acok;
+
+ /* Part 1: invalid charger number */
+ rv = raa489000_is_acok(board_get_charger_chip_count() + 1, &acok);
+ zassert_equal(EC_ERROR_INVAL, rv,
+ "Invalid charger num, but AC OK check succeeded");
+
+ /* Part 2: error accessing register */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL9238_REG_INFO2);
+
+ rv = raa489000_is_acok(CHARGER_NUM, &acok);
+ zassert_equal(EC_ERROR_INVAL, rv,
+ "Register read failure, but AC OK check succeeded");
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Part 3: successful path - ACOK is true */
+ raa489000_emul_set_acok_pin(isl923x_emul, 1);
+
+ rv = raa489000_is_acok(CHARGER_NUM, &acok);
+ zassert_equal(EC_SUCCESS, rv, "AC OK check did not return success");
+ zassert_true(acok, "AC OK is false");
+
+ /* Part 3: successful path - ACOK is false */
+ raa489000_emul_set_acok_pin(isl923x_emul, 0);
+
+ rv = raa489000_is_acok(CHARGER_NUM, &acok);
+ zassert_equal(EC_SUCCESS, rv, "AC OK check did not return success");
+ zassert_false(acok, "AC OK is true");
+}
+
+ZTEST(isl923x, test_isl923x_enable_asgate)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ int rv;
+
+ /* Part 1: Try enabling the ASGATE */
+ rv = raa489000_enable_asgate(CHARGER_NUM, true);
+
+ zassert_equal(EC_SUCCESS, rv, "Expected return code of %d but got %d",
+ EC_SUCCESS, rv);
+ zassert_true(
+ isl923x_emul_peek_reg(isl923x_emul, RAA489000_REG_CONTROL8) &
+ RAA489000_C8_ASGATE_ON_READY,
+ "RAA489000_C8_ASGATE_ON_READY bit not set in Control Reg 8");
+
+ /* Part 2: Turn it back off */
+ rv = raa489000_enable_asgate(CHARGER_NUM, false);
+
+ zassert_equal(EC_SUCCESS, rv, "Expected return code of %d but got %d",
+ EC_SUCCESS, rv);
+ zassert_false(isl923x_emul_peek_reg(isl923x_emul,
+ RAA489000_REG_CONTROL8) &
+ RAA489000_C8_ASGATE_ON_READY,
+ "RAA489000_C8_ASGATE_ON_READY bit set in Control Reg 8");
+}
+
+/* Mock read and write functions to use in the hibernation test */
+FAKE_VALUE_FUNC(int, hibernate_mock_read_fn, const struct emul *, int,
+ uint8_t *, int, void *);
+FAKE_VALUE_FUNC(int, hibernate_mock_write_fn, const struct emul *, int, uint8_t,
+ int, void *);
+
+/**
+ * @brief Setup function for the hibernate tests.
+ */
+static void isl923x_hibernate_before(void *state)
+{
+ ARG_UNUSED(state);
+
+ /* Reset mocks and make the read/write mocks pass all data through */
+ RESET_FAKE(hibernate_mock_read_fn);
+ RESET_FAKE(hibernate_mock_write_fn);
+ hibernate_mock_read_fn_fake.return_val = 1;
+ hibernate_mock_write_fn_fake.return_val = 1;
+
+ i2c_common_emul_set_read_func(COMMON_DATA, hibernate_mock_read_fn,
+ NULL);
+ i2c_common_emul_set_write_func(COMMON_DATA, hibernate_mock_write_fn,
+ NULL);
+
+ /* Don't fail on any register access */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+/**
+ * @brief Teardown function for the hibernate tests.
+ */
+static void isl923x_hibernate_after(void *state)
+{
+ ARG_UNUSED(state);
+
+ /* Clear the mock read/write functions */
+ i2c_common_emul_set_read_func(COMMON_DATA, NULL, NULL);
+ i2c_common_emul_set_write_func(COMMON_DATA, NULL, NULL);
+
+ /* Don't fail on any register access */
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__happy_path)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ uint16_t actual;
+
+ raa489000_hibernate(CHARGER_NUM, false);
+
+ /* Check ISL923X_REG_CONTROL0 */
+ actual = isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL0);
+
+ zassert_false(actual & RAA489000_C0_EN_CHG_PUMPS_TO_100PCT,
+ "RAA489000_C0_EN_CHG_PUMPS_TO_100PCT should not be set");
+ zassert_false(actual & RAA489000_C0_BGATE_FORCE_ON,
+ "RAA489000_C0_BGATE_FORCE_ON should not be set");
+
+ /* Check ISL923X_REG_CONTROL1 */
+ actual = isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1);
+
+ zassert_false(
+ actual & RAA489000_C1_ENABLE_SUPP_SUPPORT_MODE,
+ "RAA489000_C1_ENABLE_SUPP_SUPPORT_MODE should not be set");
+ zassert_false(actual & ISL923X_C1_ENABLE_PSYS,
+ "ISL923X_C1_ENABLE_PSYS should not be set");
+ zassert_true(actual & RAA489000_C1_BGATE_FORCE_OFF,
+ "RAA489000_C1_BGATE_FORCE_OFF should be set");
+ zassert_true(actual & ISL923X_C1_DISABLE_MON,
+ "ISL923X_C1_DISABLE_MON should be set");
+
+ /* Check ISL9238_REG_CONTROL3 (disable_adc = false) */
+ actual = isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3);
+
+ zassert_true(actual & RAA489000_ENABLE_ADC,
+ "RAA489000_ENABLE_ADC should be set");
+
+ /* Check ISL9238_REG_CONTROL4 */
+ actual = isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL4);
+
+ zassert_true(actual & RAA489000_C4_DISABLE_GP_CMP,
+ "RAA489000_C4_DISABLE_GP_CMP should be set");
+
+ /* Ensure all expected register reads and writes happened */
+ int registers[] = { ISL923X_REG_CONTROL0, ISL923X_REG_CONTROL1,
+ ISL9238_REG_CONTROL3, ISL9238_REG_CONTROL4 };
+
+ for (int i = 0; i < ARRAY_SIZE(registers); i++) {
+ /* Each reg has 2 reads and 2 writes because they are 16-bit */
+ MOCK_ASSERT_I2C_READ(hibernate_mock_read_fn, i * 2,
+ registers[i]);
+ MOCK_ASSERT_I2C_READ(hibernate_mock_read_fn, (i * 2) + 1,
+ registers[i]);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, i * 2,
+ registers[i], MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, (i * 2) + 1,
+ registers[i], MOCK_IGNORE_VALUE);
+ }
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__invalid_charger_number)
+{
+ /* Mocks should just be pass-through */
+ RESET_FAKE(hibernate_mock_read_fn);
+ RESET_FAKE(hibernate_mock_write_fn);
+ hibernate_mock_read_fn_fake.return_val = 1;
+ hibernate_mock_write_fn_fake.return_val = 1;
+
+ raa489000_hibernate(board_get_charger_chip_count() + 1, false);
+
+ /* Make sure no I2C activity happened */
+ zassert_equal(hibernate_mock_read_fn_fake.call_count, 0,
+ "No I2C reads should have happened");
+ zassert_equal(hibernate_mock_write_fn_fake.call_count, 0,
+ "No I2C writes should have happened");
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL0)
+{
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL0);
+
+ raa489000_hibernate(CHARGER_NUM, false);
+
+ /*
+ * We have no return codes to check, so instead verify that the first
+ * successful I2C write is to CONTROL1 and not CONTROL0.
+ */
+
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 0, ISL923X_REG_CONTROL1,
+ MOCK_IGNORE_VALUE);
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL1)
+{
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL923X_REG_CONTROL1);
+
+ raa489000_hibernate(CHARGER_NUM, false);
+
+ /*
+ * Ensure we skipped CONTROL1. (NB: due to 16-bit regs, each write takes
+ * two calls to the mock_write_fn)
+ */
+
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 0, ISL923X_REG_CONTROL0,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 1, ISL923X_REG_CONTROL0,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 2, ISL9238_REG_CONTROL3,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 3, ISL9238_REG_CONTROL3,
+ MOCK_IGNORE_VALUE);
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL3)
+{
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL9238_REG_CONTROL3);
+
+ raa489000_hibernate(CHARGER_NUM, false);
+
+ /*
+ * Ensure we skipped CONTROL3. (NB: due to 16-bit regs, each write takes
+ * two calls to the mock_write_fn)
+ */
+
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 2, ISL923X_REG_CONTROL1,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 3, ISL923X_REG_CONTROL1,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 4, ISL9238_REG_CONTROL4,
+ MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 5, ISL9238_REG_CONTROL4,
+ MOCK_IGNORE_VALUE);
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL4)
+{
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, ISL9238_REG_CONTROL4);
+
+ raa489000_hibernate(CHARGER_NUM, false);
+
+ /*
+ * Ensure we skipped CONTROL4. (i.e. the last calls should be to write
+ * to CONTROL3)
+ */
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn,
+ hibernate_mock_write_fn_fake.call_count - 2,
+ ISL9238_REG_CONTROL3, MOCK_IGNORE_VALUE);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn,
+ hibernate_mock_write_fn_fake.call_count - 1,
+ ISL9238_REG_CONTROL3, MOCK_IGNORE_VALUE);
+}
+
+ZTEST(isl923x_hibernate, test_isl923x_hibernate__adc_disable)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ uint16_t expected;
+
+ raa489000_hibernate(CHARGER_NUM, true);
+
+ /* Check ISL9238_REG_CONTROL3 (disable_adc = true) */
+ expected = isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3);
+ expected &= ~RAA489000_ENABLE_ADC;
+
+ MOCK_ASSERT_I2C_READ(hibernate_mock_read_fn, 4, ISL9238_REG_CONTROL3);
+ MOCK_ASSERT_I2C_READ(hibernate_mock_read_fn, 5, ISL9238_REG_CONTROL3);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 4, ISL9238_REG_CONTROL3,
+ expected & 0xff);
+ MOCK_ASSERT_I2C_WRITE(hibernate_mock_write_fn, 5, ISL9238_REG_CONTROL3,
+ expected >> 8);
+}
+
+ZTEST(isl923x_hibernate, test_isl9238c_hibernate)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ uint16_t control1_expected, control2_expected, control3_expected;
+ int rv;
+
+ /* Part 1: Happy path */
+ control1_expected =
+ (isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1) &
+ ~ISL923X_C1_ENABLE_PSYS) |
+ ISL923X_C1_DISABLE_MON;
+ control2_expected =
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2) |
+ ISL923X_C2_COMPARATOR;
+ control3_expected =
+ isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3) |
+ ISL9238_C3_BGATE_OFF;
+
+ rv = isl9238c_hibernate(CHARGER_NUM);
+
+ zassert_equal(EC_SUCCESS, rv, "Expected return code %d but got %d",
+ EC_SUCCESS, rv);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1),
+ control1_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1),
+ control1_expected);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2),
+ control2_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2),
+ control2_expected);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3),
+ control3_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3),
+ control3_expected);
+
+ /* Part 2: Fail reading each register and check for error code */
+ int registers[] = { ISL923X_REG_CONTROL1, ISL923X_REG_CONTROL2,
+ ISL9238_REG_CONTROL3 };
+
+ for (int i = 0; i < ARRAY_SIZE(registers); i++) {
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, registers[i]);
+
+ rv = isl9238c_hibernate(CHARGER_NUM);
+
+ zassert_equal(EC_ERROR_INVAL, rv,
+ "Wrong return code. Expected %d but got %d",
+ EC_ERROR_INVAL, rv);
+ }
+}
+
+ZTEST(isl923x_hibernate, test_isl9238c_resume)
+{
+ const struct emul *isl923x_emul = ISL923X_EMUL;
+ uint16_t control1_expected, control2_expected, control3_expected;
+ int rv;
+
+ /* Part 1: Happy path */
+ control1_expected =
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1) |
+ ISL923X_C1_ENABLE_PSYS;
+ control2_expected =
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2) &
+ ~ISL923X_C2_COMPARATOR;
+ control3_expected =
+ isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3) &
+ ~ISL9238_C3_BGATE_OFF;
+
+ rv = isl9238c_resume(CHARGER_NUM);
+
+ zassert_equal(EC_SUCCESS, rv, "Expected return code %d but got %d",
+ EC_SUCCESS, rv);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1),
+ control1_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL1),
+ control1_expected);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2),
+ control2_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL923X_REG_CONTROL2),
+ control2_expected);
+ zassert_equal(isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3),
+ control3_expected,
+ "Unexpected register value 0x%02x. Should be 0x%02x",
+ isl923x_emul_peek_reg(isl923x_emul, ISL9238_REG_CONTROL3),
+ control3_expected);
+
+ /* Part 2: Fail reading each register and check for error code */
+ int registers[] = { ISL923X_REG_CONTROL1, ISL923X_REG_CONTROL2,
+ ISL9238_REG_CONTROL3 };
+
+ for (int i = 0; i < ARRAY_SIZE(registers); i++) {
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, registers[i]);
+
+ rv = isl9238c_resume(CHARGER_NUM);
+
+ zassert_equal(EC_ERROR_INVAL, rv,
+ "Wrong return code. Expected %d but got %d",
+ EC_ERROR_INVAL, rv);
+ }
+}
+
+ZTEST_SUITE(isl923x, drivers_predicate_pre_main, NULL, NULL, NULL, NULL);
+
+ZTEST_SUITE(isl923x_hibernate, drivers_predicate_post_main, NULL,
+ isl923x_hibernate_before, isl923x_hibernate_after, NULL);
diff --git a/zephyr/test/drivers/default/src/led.c b/zephyr/test/drivers/default/src/led.c
new file mode 100644
index 0000000000..e89a3d8b66
--- /dev/null
+++ b/zephyr/test/drivers/default/src/led.c
@@ -0,0 +1,92 @@
+/* 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 <zephyr/ztest_assert.h>
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/pwm.h>
+
+#include "ec_commands.h"
+#include "led.h"
+#include "led_common.h"
+#include "pwm_mock.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+ZTEST_SUITE(pwm_led_driver, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST(pwm_led_driver, test_led_set_brightness)
+{
+ const uint8_t brightness_off[EC_LED_COLOR_COUNT] = {};
+ const uint8_t brightness_white[EC_LED_COLOR_COUNT] = {
+ [EC_LED_COLOR_WHITE] = 1
+ };
+ const uint8_t brightness_amber[EC_LED_COLOR_COUNT] = {
+ [EC_LED_COLOR_AMBER] = 1
+ };
+ const struct device *pwm_blue_left =
+ DEVICE_DT_GET(DT_NODELABEL(pwm_blue_left));
+ const struct device *pwm_white_left =
+ DEVICE_DT_GET(DT_NODELABEL(pwm_white_left));
+ const struct device *pwm_amber_right =
+ DEVICE_DT_GET(DT_NODELABEL(pwm_amber_right));
+ const struct device *pwm_white_right =
+ DEVICE_DT_GET(DT_NODELABEL(pwm_white_right));
+
+ /* Turn off all LEDs */
+ led_set_brightness(EC_LED_ID_LEFT_LED, brightness_off);
+ led_set_brightness(EC_LED_ID_RIGHT_LED, brightness_off);
+ zassert_equal(pwm_mock_get_duty(pwm_blue_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_amber_right, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_right, 0), 0, NULL);
+
+ /* Call led_set_color(LED_WHITE, LEFT_LED) */
+ led_set_brightness(EC_LED_ID_LEFT_LED, brightness_white);
+ zassert_equal(pwm_mock_get_duty(pwm_blue_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_left, 0), 100, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_amber_right, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_right, 0), 0, NULL);
+
+ /* Unsupporte, call led_set_color(LED_OFF, LEFT_LED) */
+ led_set_brightness(EC_LED_ID_LEFT_LED, brightness_amber);
+ zassert_equal(pwm_mock_get_duty(pwm_blue_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_amber_right, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_right, 0), 0, NULL);
+
+ /* Call led_set_color(AMBER, RIGHT_LED) */
+ led_set_brightness(EC_LED_ID_RIGHT_LED, brightness_amber);
+ zassert_equal(pwm_mock_get_duty(pwm_blue_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_left, 0), 0, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_amber_right, 0), 100, NULL);
+ zassert_equal(pwm_mock_get_duty(pwm_white_right, 0), 0, NULL);
+}
+
+ZTEST(pwm_led_driver, test_led_get_brightness)
+{
+ uint8_t brightness[EC_LED_COLOR_COUNT];
+ const uint8_t expected_left[EC_LED_COLOR_COUNT] = {
+ [EC_LED_COLOR_BLUE] = 100,
+ [EC_LED_COLOR_WHITE] = 100,
+ };
+ const uint8_t expected_right[EC_LED_COLOR_COUNT] = {
+ [EC_LED_COLOR_WHITE] = 100,
+ [EC_LED_COLOR_AMBER] = 100,
+ };
+
+ /* Verify LED colors defined in device tree are reflected in the
+ * brightness array.
+ */
+ memset(brightness, 255, sizeof(brightness));
+ led_get_brightness_range(EC_LED_ID_LEFT_LED, brightness);
+ zassert_mem_equal(brightness, expected_left, sizeof(brightness), NULL);
+
+ memset(brightness, 255, sizeof(brightness));
+ led_get_brightness_range(EC_LED_ID_RIGHT_LED, brightness);
+ zassert_mem_equal(brightness, expected_right, sizeof(brightness), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/lid_angle.c b/zephyr/test/drivers/default/src/lid_angle.c
new file mode 100644
index 0000000000..568057d95a
--- /dev/null
+++ b/zephyr/test/drivers/default/src/lid_angle.c
@@ -0,0 +1,70 @@
+/* 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 "ec_commands.h"
+#include "lid_angle.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+#define LID_ANGLE_MIN_LARGE_ANGLE 0
+#define LID_ANGLE_MAX_LARGE_ANGLE 360
+
+static void lid_angle_after(void *f)
+{
+ ARG_UNUSED(f);
+ /* Reset the wake angle */
+ lid_angle_set_wake_angle(180);
+ /* Flush the buffer */
+ lid_angle_update(LID_ANGLE_UNRELIABLE);
+ lid_angle_update(LID_ANGLE_UNRELIABLE);
+ lid_angle_update(LID_ANGLE_UNRELIABLE);
+ lid_angle_update(LID_ANGLE_UNRELIABLE);
+}
+
+ZTEST_SUITE(lid_angle, drivers_predicate_post_main, NULL, NULL, lid_angle_after,
+ NULL);
+
+ZTEST(lid_angle, test_get_set_wake_angle)
+{
+ lid_angle_set_wake_angle(LID_ANGLE_MIN_LARGE_ANGLE - 1);
+ zassert_equal(LID_ANGLE_MIN_LARGE_ANGLE, lid_angle_get_wake_angle(),
+ NULL);
+
+ lid_angle_set_wake_angle(LID_ANGLE_MAX_LARGE_ANGLE + 1);
+ zassert_equal(LID_ANGLE_MAX_LARGE_ANGLE, lid_angle_get_wake_angle(),
+ NULL);
+
+ lid_angle_set_wake_angle(
+ (LID_ANGLE_MIN_LARGE_ANGLE + LID_ANGLE_MAX_LARGE_ANGLE) / 2);
+ zassert_equal((LID_ANGLE_MIN_LARGE_ANGLE + LID_ANGLE_MAX_LARGE_ANGLE) /
+ 2,
+ lid_angle_get_wake_angle(), NULL);
+}
+
+ZTEST(lid_angle, test_no_wake_min_large_angle)
+{
+ lid_angle_set_wake_angle(LID_ANGLE_MIN_LARGE_ANGLE);
+ lid_angle_update(45);
+ lid_angle_update(45);
+ lid_angle_update(45);
+ lid_angle_update(45);
+
+ zassert_equal(1, lid_angle_peripheral_enable_fake.call_count, NULL);
+ zassert_equal(0, lid_angle_peripheral_enable_fake.arg0_val, NULL);
+}
+
+ZTEST(lid_angle, test_wake_max_large_angle)
+{
+ lid_angle_set_wake_angle(LID_ANGLE_MAX_LARGE_ANGLE);
+ lid_angle_update(45);
+ lid_angle_update(45);
+ lid_angle_update(45);
+ lid_angle_update(45);
+
+ zassert_equal(1, lid_angle_peripheral_enable_fake.call_count, NULL);
+ zassert_equal(1, lid_angle_peripheral_enable_fake.arg0_val, NULL);
+}
diff --git a/zephyr/test/drivers/default/src/lid_switch.c b/zephyr/test/drivers/default/src/lid_switch.c
new file mode 100644
index 0000000000..1647f73e00
--- /dev/null
+++ b/zephyr/test/drivers/default/src/lid_switch.c
@@ -0,0 +1,277 @@
+/* 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 <zephyr/drivers/emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <lid_switch.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <console.h>
+
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "ec_commands.h"
+#include "host_command.h"
+
+#define LID_GPIO_PATH DT_PATH(named_gpios, lid_open_ec)
+#define LID_GPIO_PIN DT_GPIO_PIN(LID_GPIO_PATH, gpios)
+
+int emul_lid_open(void)
+{
+ const struct device *lid_gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(LID_GPIO_PATH, gpios));
+
+ return gpio_emul_input_set(lid_gpio_dev, LID_GPIO_PIN, 1);
+}
+
+int emul_lid_close(void)
+{
+ const struct device *lid_gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(LID_GPIO_PATH, gpios));
+
+ return gpio_emul_input_set(lid_gpio_dev, LID_GPIO_PIN, 0);
+}
+
+static void *lid_switch_setup(void)
+{
+ /**
+ * Set chipset to S0 as chipset power on after opening lid may disturb
+ * test
+ */
+ test_set_chipset_to_s0();
+
+ return NULL;
+}
+
+static void lid_switch_before(void *unused)
+{
+ /* Make sure that interrupt fire at the next lid open/close */
+ zassume_ok(emul_lid_close(), NULL);
+ zassume_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+}
+
+static void lid_switch_after(void *unused)
+{
+ struct ec_params_force_lid_open params = {
+ .enabled = 0,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_FORCE_LID_OPEN, 0, params);
+ int res;
+
+ res = host_command_process(&args);
+ if (res)
+ TC_ERROR("host_command_process() failed (%d)\n", res);
+
+ if (args.result)
+ TC_ERROR("args.result != 0 (%d != 0)\n", args.result);
+
+ res = emul_lid_open();
+ if (res)
+ TC_ERROR("emul_lid_open() failed (%d)\n", res);
+ k_sleep(K_MSEC(100));
+}
+
+ZTEST(lid_switch, test_lid_open)
+{
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+}
+
+ZTEST(lid_switch, test_lid_debounce)
+{
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ /* Create interrupts quickly before they can be handled. */
+ zassert_ok(emul_lid_open(), NULL);
+ zassert_ok(emul_lid_close(), NULL);
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+}
+
+ZTEST(lid_switch, test_lid_close)
+{
+ /* Start open. */
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(200));
+ zassert_equal(lid_is_open(), 0, NULL);
+}
+
+ZTEST(lid_switch, test_cmd_lidopen)
+{
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ /* Forced override lid open. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidopen"),
+ NULL);
+ zassert_equal(lid_is_open(), 1, NULL);
+ k_sleep(K_MSEC(100));
+
+ printk("GPIO lid open/close\n");
+ /* Open & close with gpio. */
+ zassert_ok(emul_lid_open(), NULL);
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(500));
+ zassert_equal(lid_is_open(), 0, NULL);
+}
+
+ZTEST(lid_switch, test_cmd_lidopen_bounce)
+{
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ printk("Console lid open\n");
+ /* Forced override lid open. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidopen"),
+ NULL);
+ zassert_equal(lid_is_open(), 1, NULL);
+ k_sleep(K_MSEC(100));
+
+ printk("Console lid open\n");
+ /* Forced override lid open. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidopen"),
+ NULL);
+ zassert_equal(lid_is_open(), 1, NULL);
+ k_sleep(K_MSEC(100));
+
+ printk("GPIO lid open/close\n");
+ /* Open & close with gpio. */
+ zassert_ok(emul_lid_open(), NULL);
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(500));
+ zassert_equal(lid_is_open(), 0, NULL);
+}
+
+ZTEST(lid_switch, test_cmd_lidclose)
+{
+ /* Start open. */
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+
+ /* Forced override lid close. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidclose"),
+ NULL);
+ zassert_equal(lid_is_open(), 0, NULL);
+ k_sleep(K_MSEC(100));
+
+ printk("GPIO lid close/open\n");
+ /* Close & open with gpio. */
+ zassert_ok(emul_lid_close(), NULL);
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(500));
+ zassert_equal(lid_is_open(), 1, NULL);
+}
+
+ZTEST(lid_switch, test_cmd_lidclose_bounce)
+{
+ /* Start open. */
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+
+ /* Forced override lid close. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidclose"),
+ NULL);
+ zassert_equal(lid_is_open(), 0, NULL);
+ k_sleep(K_MSEC(100));
+
+ /* Forced override lid close. */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidclose"),
+ NULL);
+ zassert_equal(lid_is_open(), 0, NULL);
+ k_sleep(K_MSEC(100));
+
+ printk("GPIO lid close/open\n");
+ /* Close & open with gpio. */
+ zassert_ok(emul_lid_close(), NULL);
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(500));
+ zassert_equal(lid_is_open(), 1, NULL);
+}
+
+#if defined(CONFIG_SHELL_BACKEND_DUMMY)
+ZTEST(lid_switch, test_cmd_lidstate_open)
+{
+ const char *buffer;
+ size_t buffer_size;
+
+ /* Start open. */
+ zassert_ok(emul_lid_open(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+
+ /* Read the state with console. */
+ shell_backend_dummy_clear_output(get_ec_shell());
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidstate"),
+ NULL);
+ buffer = shell_backend_dummy_get_output(get_ec_shell(), &buffer_size);
+ zassert_true(strcmp(buffer, "\r\nlid state: open\r\n") == 0,
+ "Invalid console output %s", buffer);
+}
+
+ZTEST(lid_switch, test_cmd_lidstate_close)
+{
+ const char *buffer;
+ size_t buffer_size;
+
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ /* Read the state with console. */
+ shell_backend_dummy_clear_output(get_ec_shell());
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "lidstate"),
+ NULL);
+ buffer = shell_backend_dummy_get_output(get_ec_shell(), &buffer_size);
+ zassert_true(strcmp(buffer, "\r\nlid state: closed\r\n") == 0,
+ "Invalid console output %s", buffer);
+}
+#else
+#error This test requires CONFIG_SHELL_BACKEND_DUMMY
+#endif
+
+ZTEST(lid_switch, test_hc_force_lid_open)
+{
+ struct ec_params_force_lid_open params = {
+ .enabled = 1,
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_FORCE_LID_OPEN, 0, params);
+
+ /* Start closed. */
+ zassert_ok(emul_lid_close(), NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 0, NULL);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ k_sleep(K_MSEC(100));
+ zassert_equal(lid_is_open(), 1, NULL);
+}
+
+ZTEST_SUITE(lid_switch, drivers_predicate_post_main, lid_switch_setup,
+ lid_switch_before, lid_switch_after, NULL);
diff --git a/zephyr/test/drivers/default/src/lis2dw12.c b/zephyr/test/drivers/default/src/lis2dw12.c
new file mode 100644
index 0000000000..4cb29796f8
--- /dev/null
+++ b/zephyr/test/drivers/default/src/lis2dw12.c
@@ -0,0 +1,455 @@
+/* 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 <zephyr/drivers/emul.h>
+#include "driver/accel_lis2dw12.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_lis2dw12.h"
+#include "test/drivers/test_state.h"
+
+#define LIS2DW12_NODELABEL DT_NODELABEL(ms_lis2dw12_accel)
+#define LIS2DW12_SENSOR_ID SENSOR_ID(LIS2DW12_NODELABEL)
+#define LIS2DW12_EMUL_NODE DT_NODELABEL(lis2dw12_emul)
+
+#include <stdio.h>
+
+#define CHECK_XYZ_EQUALS(VEC1, VEC2) \
+ do { \
+ zassert_equal((VEC1)[X], (VEC2)[X], \
+ "Got %d for X, expected %d", (VEC1)[X], \
+ (VEC2)[X]); \
+ zassert_equal((VEC1)[Y], (VEC2)[Y], \
+ "Got %d for Y, expected %d", (VEC1)[Y], \
+ (VEC2)[Y]); \
+ zassert_equal((VEC1)[Z], (VEC2)[Z], \
+ "Got %d for Z, expected %d", (VEC1)[Z], \
+ (VEC2)[Z]); \
+ } while (0)
+
+/** Used with the LIS2DW12 set rate function to control rounding behavior */
+enum lis2dw12_round_mode {
+ ROUND_DOWN,
+ ROUND_UP,
+};
+
+static inline void lis2dw12_setup(void)
+{
+ lis2dw12_emul_reset(EMUL_DT_GET(LIS2DW12_EMUL_NODE));
+
+ /* Reset certain sensor struct values */
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+
+ ms->current_range = 0;
+}
+
+static void lis2dw12_before(void *state)
+{
+ ARG_UNUSED(state);
+ lis2dw12_setup();
+}
+
+static void lis2dw12_after(void *state)
+{
+ ARG_UNUSED(state);
+ lis2dw12_setup();
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_read_who_am_i)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_WHO_AM_I_REG);
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_INVAL, rv, NULL);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_who_am_i)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ lis2dw12_emul_set_who_am_i(emul, ~LIS2DW12_WHO_AM_I);
+
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_ACCESS_DENIED, rv,
+ "init returned %d but was expecting %d", rv,
+ EC_ERROR_ACCESS_DENIED);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_write_soft_reset)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_write_fail_reg(common_data,
+ LIS2DW12_SOFT_RESET_ADDR);
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_INVAL, rv, NULL);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__timeout_read_soft_reset)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ LIS2DW12_SOFT_RESET_ADDR);
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_TIMEOUT, rv, "init returned %d but expected %d",
+ rv, EC_ERROR_TIMEOUT);
+}
+
+static int lis2dw12_test_mock_write_fail_set_bdu(const struct emul *emul,
+ int reg, uint8_t val,
+ int bytes, void *data)
+{
+ if (reg == LIS2DW12_BDU_ADDR && bytes == 1 &&
+ (val & LIS2DW12_BDU_MASK) != 0) {
+ return -EIO;
+ }
+ return 1;
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_set_bdu)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_write_func(
+ common_data, lis2dw12_test_mock_write_fail_set_bdu, NULL);
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_INVAL, rv, "init returned %d but expected %d",
+ rv, EC_ERROR_INVAL);
+ zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0,
+ "expected at least one soft reset");
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_set_lir)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_LIR_ADDR);
+
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_INVAL, rv, "init returned %d but expected %d",
+ rv, EC_ERROR_INVAL);
+ zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0,
+ "expected at least one soft reset");
+}
+
+static int lis2dw12_test_mock_write_fail_set_power_mode(const struct emul *emul,
+ int reg, uint8_t val,
+ int bytes, void *data)
+{
+ if (reg == LIS2DW12_ACC_LPMODE_ADDR && bytes == 1 &&
+ (val & LIS2DW12_ACC_LPMODE_MASK) != 0) {
+ /* Cause an error when trying to set the LPMODE */
+ return -EIO;
+ }
+ return 1;
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__fail_set_power_mode)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ i2c_common_emul_set_write_func(
+ common_data, lis2dw12_test_mock_write_fail_set_power_mode,
+ NULL);
+
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_ERROR_INVAL, rv, "init returned %d but expected %d",
+ rv, EC_ERROR_INVAL);
+ zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0,
+ "expected at least one soft reset");
+}
+
+ZTEST(lis2dw12, test_lis2dw12_init__success)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ struct stprivate_data *drvdata = ms->drv_data;
+
+ int rv;
+
+ rv = ms->drv->init(ms);
+ zassert_equal(EC_SUCCESS, rv, "init returned %d but expected %d", rv,
+ EC_SUCCESS);
+ zassert_true(lis2dw12_emul_get_soft_reset_count(emul) > 0,
+ "expected at least one soft reset");
+ zassert_equal(LIS2DW12_RESOLUTION, drvdata->resol,
+ "Expected resolution of %d but got %d",
+ LIS2DW12_RESOLUTION, drvdata->resol);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_set_power_mode)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ /* Part 1: happy path */
+ rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER,
+ LIS2DW12_LOW_POWER_MODE_2);
+ zassert_equal(rv, EC_SUCCESS, "Expected %d but got %d", EC_SUCCESS, rv);
+
+ /* Part 2: unimplemented modes */
+ rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER,
+ LIS2DW12_LOW_POWER_MODE_1);
+ zassert_equal(rv, EC_ERROR_UNIMPLEMENTED, "Expected %d but got %d",
+ EC_ERROR_UNIMPLEMENTED, rv);
+
+ /* Part 3: attempt to set mode but cannot modify reg. */
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_ACC_MODE_ADDR);
+ rv = lis2dw12_set_power_mode(ms, LIS2DW12_LOW_POWER,
+ LIS2DW12_LOW_POWER_MODE_2);
+ zassert_equal(rv, EC_ERROR_INVAL, "Expected %d but got %d",
+ EC_ERROR_INVAL, rv);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_set_range)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ int rv;
+
+ /* Part 1: Happy path. Go above the max range; it will be automatically
+ * clamped.
+ */
+
+ rv = ms->drv->set_range(ms, LIS2DW12_ACCEL_FS_MAX_VAL + 1, 0);
+ zassert_equal(rv, EC_SUCCESS, "Expected %d but got %d", EC_SUCCESS, rv);
+ zassert_equal(ms->current_range, LIS2DW12_ACCEL_FS_MAX_VAL,
+ "Expected %d but got %d", LIS2DW12_ACCEL_FS_MAX_VAL,
+ ms->current_range);
+
+ /* Part 2: Error accessing register */
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_FS_ADDR);
+ rv = ms->drv->set_range(ms, LIS2DW12_ACCEL_FS_MAX_VAL, 0);
+ zassert_equal(rv, EC_ERROR_INVAL, "Expected %d but got %d",
+ EC_ERROR_INVAL, rv);
+}
+
+ZTEST(lis2dw12, test_lis2dw12_set_rate)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ struct stprivate_data *drv_data = ms->drv_data;
+ int rv;
+
+ /* Part 1: Turn off sensor with rate=0 */
+ rv = ms->drv->set_data_rate(ms, 0, 0);
+
+ zassert_equal(lis2dw12_emul_peek_odr(emul), LIS2DW12_ODR_POWER_OFF_VAL,
+ "Output data rate should be %d but got %d",
+ LIS2DW12_ODR_POWER_OFF_VAL, lis2dw12_emul_peek_odr(emul));
+ zassert_equal(drv_data->base.odr, LIS2DW12_ODR_POWER_OFF_VAL,
+ "Output data rate should be %d but got %d",
+ LIS2DW12_ODR_POWER_OFF_VAL, drv_data->base.odr);
+ zassert_equal(rv, EC_SUCCESS, "Returned %d but expected %d", rv,
+ EC_SUCCESS);
+
+ /* Part 2: Set some output data rates. We will request a certain rate
+ * and make sure the closest supported rate is used.
+ */
+
+ static const struct {
+ int requested_rate; /* millihertz */
+ enum lis2dw12_round_mode round;
+ int expected_norm_rate; /* millihertz */
+ uint8_t expected_reg_val;
+ } test_params[] = {
+ { 1000, ROUND_DOWN, LIS2DW12_ODR_MIN_VAL,
+ LIS2DW12_ODR_12HZ_VAL },
+ { 12501, ROUND_DOWN, 12500, LIS2DW12_ODR_12HZ_VAL },
+ { 25001, ROUND_DOWN, 25000, LIS2DW12_ODR_25HZ_VAL },
+ { 50001, ROUND_DOWN, 50000, LIS2DW12_ODR_50HZ_VAL },
+ { 100001, ROUND_DOWN, 100000, LIS2DW12_ODR_100HZ_VAL },
+ { 200001, ROUND_DOWN, 200000, LIS2DW12_ODR_200HZ_VAL },
+ { 400001, ROUND_DOWN, 400000, LIS2DW12_ODR_400HZ_VAL },
+ { 800001, ROUND_DOWN, 800000, LIS2DW12_ODR_800HZ_VAL },
+ { 1600001, ROUND_DOWN, 1600000, LIS2DW12_ODR_1_6kHZ_VAL },
+ { 3200001, ROUND_DOWN, LIS2DW12_ODR_MAX_VAL,
+ LIS2DW12_ODR_1_6kHZ_VAL },
+
+ { 1000, ROUND_UP, LIS2DW12_ODR_MIN_VAL, LIS2DW12_ODR_12HZ_VAL },
+ { 12501, ROUND_UP, 25000, LIS2DW12_ODR_25HZ_VAL },
+ { 25001, ROUND_UP, 50000, LIS2DW12_ODR_50HZ_VAL },
+ { 50001, ROUND_UP, 100000, LIS2DW12_ODR_100HZ_VAL },
+ { 100001, ROUND_UP, 200000, LIS2DW12_ODR_200HZ_VAL },
+ { 200001, ROUND_UP, 400000, LIS2DW12_ODR_400HZ_VAL },
+ { 400001, ROUND_UP, 800000, LIS2DW12_ODR_800HZ_VAL },
+ { 800001, ROUND_UP, 1600000, LIS2DW12_ODR_1_6kHZ_VAL },
+ { 1600001, ROUND_UP, LIS2DW12_ODR_MAX_VAL,
+ LIS2DW12_ODR_1_6kHZ_VAL },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(test_params); i++) {
+ /* For each test vector in the above array */
+ drv_data->base.odr = -1;
+ rv = ms->drv->set_data_rate(ms, test_params[i].requested_rate,
+ test_params[i].round);
+
+ /* Check the normalized rate the driver chose */
+ zassert_equal(
+ drv_data->base.odr, test_params[i].expected_norm_rate,
+ "For requested rate %d, output data rate should be %d but got %d",
+ test_params[i].requested_rate,
+ test_params[i].expected_norm_rate, drv_data->base.odr);
+
+ /* Read ODR and mode bits back from CTRL1 register */
+ uint8_t odr_bits = lis2dw12_emul_peek_odr(emul);
+
+ zassert_equal(
+ odr_bits, test_params[i].expected_reg_val,
+ "For requested rate %d, ODR bits should be 0x%x but got 0x%x - %d",
+ test_params[i].requested_rate,
+ test_params[i].expected_reg_val, odr_bits,
+ LIS2DW12_ODR_MAX_VAL);
+
+ /* Check if high performance mode was enabled if rate >
+ * 200,000mHz
+ */
+
+ uint8_t mode_bits = lis2dw12_emul_peek_mode(emul);
+ uint8_t lpmode_bits = lis2dw12_emul_peek_lpmode(emul);
+
+ if (odr_bits > LIS2DW12_ODR_200HZ_VAL) {
+ /* High performance mode, LP mode immaterial */
+ zassert_equal(mode_bits, LIS2DW12_HIGH_PERF,
+ "MODE[1:0] should be 0x%x, but got 0x%x",
+ LIS2DW12_HIGH_PERF, mode_bits);
+
+ } else {
+ /* Low power mode, LP mode 2 */
+ zassert_equal(mode_bits, LIS2DW12_LOW_POWER,
+ "MODE[1:0] should be 0x%x, but got 0x%x",
+ LIS2DW12_LOW_POWER, mode_bits);
+
+ zassert_equal(
+ lpmode_bits, LIS2DW12_LOW_POWER_MODE_2,
+ "LPMODE[1:0] should be 0x%x, but got 0x%x",
+ LIS2DW12_LOW_POWER_MODE_2, lpmode_bits);
+ }
+ }
+}
+
+ZTEST(lis2dw12, test_lis2dw12_read)
+{
+ const struct emul *emul = EMUL_DT_GET(LIS2DW12_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_lis2dw12_get_i2c_common_data(emul);
+
+ struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID];
+ struct stprivate_data *drvdata = ms->drv_data;
+ intv3_t sample = { 0, 0, 0 };
+ int rv;
+
+ /* Reading requires a range to be set. Use 1 so it has no effect
+ * when scaling samples. Also need to set the sensor resolution
+ * manually.
+ */
+
+ ms->drv->set_range(ms, 1, 0);
+ drvdata->resol = LIS2DW12_RESOLUTION;
+
+ /* Part 1: Try to read from sensor, but cannot check status register for
+ * ready bit
+ */
+
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_STATUS_REG);
+
+ rv = ms->drv->read(ms, sample);
+
+ zassert_equal(rv, EC_ERROR_INVAL,
+ "Expected return val of %d but got %d", EC_ERROR_INVAL,
+ rv);
+
+ /* Part 2: Try to read sensor, but no new data is available. In this
+ * case, the driver should return the reading in from `ms->raw_xyz`
+ */
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ lis2dw12_emul_clear_accel_reading(emul);
+ ms->raw_xyz[X] = 123;
+ ms->raw_xyz[Y] = 456;
+ ms->raw_xyz[Z] = 789;
+
+ rv = ms->drv->read(ms, sample);
+
+ zassert_equal(rv, EC_SUCCESS, "Expected return val of %d but got %d",
+ EC_SUCCESS, rv);
+ CHECK_XYZ_EQUALS(sample, ms->raw_xyz);
+
+ /* Part 3: Read from sensor w/ data ready, but an error occurs during
+ * read.
+ */
+ intv3_t fake_sample = { 100, 200, 300 };
+
+ i2c_common_emul_set_read_fail_reg(common_data, LIS2DW12_OUT_X_L_ADDR);
+ lis2dw12_emul_set_accel_reading(emul, fake_sample);
+
+ rv = ms->drv->read(ms, sample);
+
+ zassert_equal(rv, EC_ERROR_INVAL,
+ "Expected return val of %d but got %d", EC_ERROR_INVAL,
+ rv);
+
+ /* Part 4: Success */
+
+ intv3_t expected_sample;
+
+ for (int i = 0; i < ARRAY_SIZE(expected_sample); i++) {
+ /* The read routine will normalize `fake_sample` to use the full
+ * range of INT16, so we need to compensate in our expected
+ * output
+ */
+
+ expected_sample[i] =
+ fake_sample[i] * (1 << (16 - LIS2DW12_RESOLUTION));
+ }
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ lis2dw12_emul_set_accel_reading(emul, fake_sample);
+
+ rv = ms->drv->read(ms, sample);
+
+ zassert_equal(rv, EC_SUCCESS, "Expected return val of %d but got %d",
+ EC_SUCCESS, rv);
+ CHECK_XYZ_EQUALS(sample, expected_sample);
+}
+
+ZTEST_SUITE(lis2dw12, drivers_predicate_post_main, NULL, lis2dw12_before,
+ lis2dw12_after, NULL);
diff --git a/zephyr/test/drivers/default/src/ln9310.c b/zephyr/test/drivers/default/src/ln9310.c
new file mode 100644
index 0000000000..326e8480ef
--- /dev/null
+++ b/zephyr/test/drivers/default/src/ln9310.c
@@ -0,0 +1,685 @@
+/* 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/ztest.h>
+#include <zephyr/drivers/emul.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest_assert.h>
+#include <zephyr/drivers/i2c_emul.h>
+
+#include "driver/ln9310.h"
+#include "emul/emul_ln9310.h"
+#include "emul/emul_common_i2c.h"
+#include "timer.h"
+#include "test/drivers/test_state.h"
+
+/*
+ * TODO(b/201420132): Implement approach for tests to immediately schedule work
+ * to avoid any sleeping
+ */
+#define TEST_DELAY_MS 50
+
+#define EMUL_LN9310_NODE DT_NODELABEL(ln9310)
+
+/*
+ * Chip revisions below LN9310_BC_STS_C_CHIP_REV_FIXED require an alternative
+ * software startup to properly initialize and power up.
+ */
+#define REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV \
+ (LN9310_BC_STS_C_CHIP_REV_FIXED - 1)
+
+ZTEST(ln9310, test_ln9310_read_chip_fails)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ i2c_common_emul_set_read_fail_reg(common_data, LN9310_REG_BC_STS_C);
+
+ zassert_true(ln9310_init() != 0, NULL);
+ zassert_false(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST(ln9310, test_ln9310_2s_powers_up)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ ln9310_software_enable(true);
+
+ k_msleep(TEST_DELAY_MS);
+ zassert_true(ln9310_power_good(), NULL);
+}
+
+ZTEST(ln9310, test_ln9310_3s_powers_up)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_3S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ ln9310_software_enable(true);
+
+ k_msleep(TEST_DELAY_MS);
+ zassert_true(ln9310_power_good(), NULL);
+}
+
+struct startup_workaround_data {
+ bool startup_workaround_attempted;
+ bool startup_workaround_should_fail;
+};
+
+static int mock_write_fn_intercept_startup_workaround(const struct emul *emul,
+ int reg, uint8_t val,
+ int bytes, void *data)
+{
+ struct startup_workaround_data *test_data = data;
+
+ uint8_t startup_workaround_val =
+ (LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PRECHARGE_ON |
+ LN9310_TEST_MODE_CTRL_FORCE_SC_OUT_PREDISCHARGE_ON);
+
+ test_data->startup_workaround_attempted =
+ test_data->startup_workaround_attempted ||
+ ((reg == LN9310_REG_TEST_MODE_CTRL) &&
+ (val == startup_workaround_val));
+
+ if (test_data->startup_workaround_should_fail)
+ return -1;
+
+ return 1;
+}
+
+ZTEST(ln9310, test_ln9310_2s_cfly_precharge_startup)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ struct startup_workaround_data test_data = {
+ .startup_workaround_attempted = false,
+ .startup_workaround_should_fail = false,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator,
+ REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(
+ common_data, mock_write_fn_intercept_startup_workaround,
+ &test_data);
+
+ ln9310_software_enable(true);
+ zassert_true(test_data.startup_workaround_attempted, NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_true(ln9310_power_good(), NULL);
+
+ ln9310_software_enable(false);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_3s_cfly_precharge_startup)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ struct startup_workaround_data test_data = {
+ .startup_workaround_attempted = false,
+ .startup_workaround_should_fail = false,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_3S);
+ ln9310_emul_set_version(emulator,
+ REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(
+ common_data, mock_write_fn_intercept_startup_workaround,
+ &test_data);
+
+ ln9310_software_enable(true);
+ zassert_true(test_data.startup_workaround_attempted, NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_true(ln9310_power_good(), NULL);
+
+ ln9310_software_enable(false);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_cfly_precharge_exceeds_retries)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ struct startup_workaround_data test_data = {
+ .startup_workaround_attempted = false,
+ .startup_workaround_should_fail = true,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /*
+ * Battery and chip rev won't matter for statement
+ * coverage here so only testing one pair.
+ */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator,
+ REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(
+ common_data, mock_write_fn_intercept_startup_workaround,
+ &test_data);
+
+ ln9310_software_enable(true);
+ zassert_true(test_data.startup_workaround_attempted, NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_battery_unknown)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /*
+ * Chip rev won't matter for statement
+ * cov so only testing one version.
+ */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_UNKNOWN);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_true(ln9310_init() != 0, NULL);
+ zassert_false(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ ln9310_software_enable(true);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+}
+
+ZTEST(ln9310, test_ln9310_2s_battery_read_fails)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ i2c_common_emul_set_read_fail_reg(common_data, LN9310_REG_BC_STS_B);
+
+ zassert_true(ln9310_init() != 0, NULL);
+ zassert_false(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ /* For Battery 2S Versions: Test Read Battery Voltage Failure Too */
+ ln9310_emul_reset(emulator);
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ i2c_common_emul_set_read_fail_reg(common_data, LN9310_REG_TRACK_CTRL);
+
+ zassert_false(ln9310_init() == 0, NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST(ln9310, test_ln9310_lion_ctrl_reg_fails)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery won't matter here so only testing one version */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ i2c_common_emul_set_read_fail_reg(common_data, LN9310_REG_LION_CTRL);
+
+ zassert_true(ln9310_init() != 0, NULL);
+ zassert_false(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ ln9310_software_enable(true);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+struct precharge_timeout_data {
+ timestamp_t time_to_mock;
+ bool handled_clearing_standby_en_bit_timeout;
+};
+
+static int mock_intercept_startup_ctrl_reg(const struct emul *emulator, int reg,
+ uint8_t val, int bytes, void *data)
+{
+ struct precharge_timeout_data *test_data = data;
+
+ if (reg == LN9310_REG_STARTUP_CTRL &&
+ test_data->handled_clearing_standby_en_bit_timeout == false) {
+ if (val == 0) {
+ timestamp_t time = get_time();
+
+ time.val += 1 + LN9310_CFLY_PRECHARGE_TIMEOUT;
+ test_data->time_to_mock = time;
+ get_time_mock = &test_data->time_to_mock;
+ } else {
+ /* ln9310 aborts a startup attempt */
+ test_data->handled_clearing_standby_en_bit_timeout =
+ true;
+ get_time_mock = NULL;
+ }
+ }
+ return 1;
+}
+
+ZTEST(ln9310, test_ln9310_cfly_precharge_timesout)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct precharge_timeout_data test_data = {
+ .time_to_mock = {
+ .val = -1,
+ .le = {
+ .lo = -1,
+ .hi = -1,
+ },
+ },
+ .handled_clearing_standby_en_bit_timeout = false,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator,
+ REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(
+ common_data, mock_intercept_startup_ctrl_reg, &test_data);
+
+ ln9310_software_enable(true);
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_true(test_data.handled_clearing_standby_en_bit_timeout, NULL);
+ /* It only times out on one attempt, it should subsequently startup */
+ zassert_true(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+}
+
+struct reg_to_fail_data {
+ int reg_access_to_fail;
+ int reg_access_fail_countdown;
+};
+
+static int mock_read_intercept_reg_to_fail(const struct emul *emul, int reg,
+ uint8_t *val, int bytes, void *data)
+{
+ struct reg_to_fail_data *test_data = data;
+
+ if (reg == test_data->reg_access_to_fail) {
+ test_data->reg_access_fail_countdown--;
+ if (test_data->reg_access_fail_countdown <= 0)
+ return -1;
+ }
+ return 1;
+}
+
+ZTEST(ln9310, test_ln9310_interrupt_reg_fail)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct reg_to_fail_data test_data = {
+ .reg_access_to_fail = 0,
+ .reg_access_fail_countdown = 0,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ i2c_common_emul_set_read_func(
+ common_data, mock_read_intercept_reg_to_fail, &test_data);
+
+ /* Fail in beginning of software enable */
+ test_data.reg_access_to_fail = LN9310_REG_INT1;
+ test_data.reg_access_fail_countdown = 1;
+
+ ln9310_software_enable(true);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+ zassert_true(test_data.reg_access_fail_countdown <= 0, NULL);
+
+ /* Fail in irq interrupt handler */
+ test_data.reg_access_fail_countdown = 2;
+
+ ln9310_software_enable(true);
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+ zassert_false(ln9310_power_good(), NULL);
+ zassert_true(test_data.reg_access_fail_countdown <= 0, NULL);
+
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_sys_sts_reg_fail)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct reg_to_fail_data test_data = {
+ .reg_access_to_fail = 0,
+ .reg_access_fail_countdown = 0,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ i2c_common_emul_set_read_func(
+ common_data, &mock_read_intercept_reg_to_fail, &test_data);
+
+ /* Register only read once and in the interrupt handler */
+ test_data.reg_access_to_fail = LN9310_REG_SYS_STS;
+ test_data.reg_access_fail_countdown = 1;
+
+ ln9310_software_enable(1);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+
+ zassert_false(ln9310_power_good(), NULL);
+ zassert_true(test_data.reg_access_fail_countdown <= 0, NULL);
+
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+struct reg_to_intercept {
+ int reg;
+ uint8_t replace_val;
+};
+
+static int mock_read_interceptor(const struct emul *emul, int reg, uint8_t *val,
+ int bytes, void *data)
+{
+ struct reg_to_intercept *test_data = data;
+
+ if (test_data->reg == reg) {
+ *val = test_data->replace_val;
+ return 0;
+ }
+
+ return 1;
+}
+
+ZTEST(ln9310, test_ln9310_reset_explicit_detected_startup)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct reg_to_intercept test_data = {
+ .reg = LN9310_REG_LION_CTRL,
+ .replace_val = 0,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ i2c_common_emul_set_read_func(common_data, &mock_read_interceptor,
+ &test_data);
+
+ ln9310_software_enable(true);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+
+ zassert_true(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_update_startup_seq_fails)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct reg_to_fail_data test_data = {
+ .reg_access_to_fail = LN9310_REG_CFG_4,
+ .reg_access_fail_countdown = 1,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ /* Requires older version of chip */
+ ln9310_emul_set_version(emulator,
+ REQUIRES_CFLY_PRECHARGE_STARTUP_CHIP_REV);
+
+ i2c_common_emul_set_read_func(
+ common_data, &mock_read_intercept_reg_to_fail, &test_data);
+
+ zassert_false(ln9310_init() == 0, NULL);
+ zassert_false(ln9310_emul_is_init(emulator), NULL);
+
+ ln9310_software_enable(true);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+
+ zassert_false(ln9310_power_good(), NULL);
+ zassert_true(test_data.reg_access_fail_countdown <= 0, NULL);
+
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+ZTEST(ln9310, test_ln9310_state_change_only_on_mode_change_interrupt)
+{
+ const struct emul *emulator = EMUL_DT_GET(EMUL_LN9310_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_ln9310_get_i2c_common_data(emulator);
+ struct reg_to_intercept test_data = {
+ .reg = LN9310_REG_INT1,
+ .replace_val = 0,
+ };
+
+ zassert_not_null(emulator, NULL);
+
+ ln9310_emul_set_context(emulator);
+ ln9310_emul_reset(emulator);
+ /* Battery and chip rev won't matter here so only testing one pair */
+ ln9310_emul_set_battery_cell_type(emulator, BATTERY_CELL_TYPE_2S);
+ ln9310_emul_set_version(emulator, LN9310_BC_STS_C_CHIP_REV_FIXED);
+
+ zassert_ok(ln9310_init(), NULL);
+ zassert_true(ln9310_emul_is_init(emulator), NULL);
+
+ i2c_common_emul_set_read_func(common_data, &mock_read_interceptor,
+ &test_data);
+
+ ln9310_software_enable(true);
+
+ /* TODO(b/201420132) */
+ k_msleep(TEST_DELAY_MS);
+
+ zassert_false(ln9310_power_good(), NULL);
+
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+static inline void reset_ln9310_state(void)
+{
+ ln9310_reset_to_initial_state();
+ get_time_mock = NULL;
+}
+
+static void ln9310_before(void *state)
+{
+ ARG_UNUSED(state);
+ reset_ln9310_state();
+}
+
+static void ln9310_after(void *state)
+{
+ ARG_UNUSED(state);
+ reset_ln9310_state();
+}
+
+ZTEST_SUITE(ln9310, drivers_predicate_post_main, NULL, ln9310_before,
+ ln9310_after, NULL);
diff --git a/zephyr/test/drivers/default/src/locate_chip.c b/zephyr/test/drivers/default/src/locate_chip.c
new file mode 100644
index 0000000000..6842543971
--- /dev/null
+++ b/zephyr/test/drivers/default/src/locate_chip.c
@@ -0,0 +1,134 @@
+/* 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/fff.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "host_command.h"
+
+/**
+ * @brief TestPurpose: test the TCPC locate valid case.
+ */
+ZTEST_USER(locate_chip, test_hc_locate_chip_tcpc)
+{
+ int ret;
+ struct ec_params_locate_chip p;
+ struct ec_response_locate_chip r;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_LOCATE_CHIP, 0, r, p);
+
+ p.type = EC_CHIP_TYPE_TCPC;
+ p.index = 0;
+
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_SUCCESS, "Unexpected return value: %d", ret);
+ zassert_equal(r.bus_type, EC_BUS_TYPE_I2C, "Unexpected bus_type: %d",
+ r.bus_type);
+ zassert_equal(r.i2c_info.port, 2, "Unexpected port: %d",
+ r.i2c_info.port);
+ zassert_equal(r.i2c_info.addr_flags, 0x82, "Unexpected addr_flags: %d",
+ r.i2c_info.addr_flags);
+
+ p.type = EC_CHIP_TYPE_TCPC;
+ p.index = 1;
+
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_SUCCESS, "Unexpected return value: %d", ret);
+ zassert_equal(r.bus_type, EC_BUS_TYPE_I2C, "Unexpected bus_type: %d",
+ r.bus_type);
+ zassert_equal(r.i2c_info.port, 3, "Unexpected port: %d",
+ r.i2c_info.port);
+ zassert_equal(r.i2c_info.addr_flags, 0x0b, "Unexpected addr_flags: %d",
+ r.i2c_info.addr_flags);
+}
+
+/**
+ * @brief TestPurpose: test the TCPC index overflow case.
+ */
+ZTEST_USER(locate_chip, test_hc_locate_chip_tcpc_overflow)
+{
+ int ret;
+ struct ec_params_locate_chip p;
+ struct ec_response_locate_chip r;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_LOCATE_CHIP, 0, r, p);
+
+ p.type = EC_CHIP_TYPE_TCPC;
+ p.index = 10;
+
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_OVERFLOW, "Unexpected return value: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: test the EEPROM locate valid case.
+ */
+ZTEST_USER(locate_chip, test_hc_locate_chip_eeprom)
+{
+ int ret;
+ struct ec_params_locate_chip p;
+ struct ec_response_locate_chip r;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_LOCATE_CHIP, 0, r, p);
+
+ p.type = EC_CHIP_TYPE_CBI_EEPROM;
+ p.index = 0;
+
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_SUCCESS, "Unexpected return value: %d", ret);
+ zassert_equal(r.bus_type, EC_BUS_TYPE_I2C, "Unexpected bus_type: %d",
+ r.bus_type);
+ zassert_equal(r.i2c_info.port, I2C_PORT_EEPROM, "Unexpected port: %d",
+ r.i2c_info.port);
+ zassert_equal(r.i2c_info.addr_flags, I2C_ADDR_EEPROM_FLAGS,
+ "Unexpected addr_flags: %d", r.i2c_info.addr_flags);
+}
+
+/**
+ * @brief TestPurpose: test the EEPROM index overflow case.
+ */
+ZTEST_USER(locate_chip, test_hc_locate_chip_eeprom_overflow)
+{
+ int ret;
+ struct ec_params_locate_chip p;
+ struct ec_response_locate_chip r;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_LOCATE_CHIP, 0, r, p);
+
+ p.type = EC_CHIP_TYPE_CBI_EEPROM;
+ p.index = 1;
+
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_OVERFLOW, "Unexpected return value: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: test the invalid parameter case.
+ */
+ZTEST_USER(locate_chip, test_hc_locate_chip_invalid)
+{
+ int ret;
+ struct ec_params_locate_chip p;
+ struct ec_response_locate_chip r;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_LOCATE_CHIP, 0, r, p);
+
+ p.type = EC_CHIP_TYPE_COUNT;
+ ret = host_command_process(&args);
+
+ zassert_equal(ret, EC_RES_INVALID_PARAM, "Unexpected return value: %d",
+ ret);
+}
+
+ZTEST_SUITE(locate_chip, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/motion_sense/motion_sense.c b/zephyr/test/drivers/default/src/motion_sense/motion_sense.c
new file mode 100644
index 0000000000..d39c3ce335
--- /dev/null
+++ b/zephyr/test/drivers/default/src/motion_sense/motion_sense.c
@@ -0,0 +1,35 @@
+/* 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 "motion_sense.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(motion_sense, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
+
+ZTEST_USER(motion_sense, ec_motion_sensor_fill_values)
+{
+ struct ec_response_motion_sensor_data dst = {
+ .data = { 1, 2, 3 },
+ };
+ const int32_t v[] = { 4, 5, 6 };
+
+ ec_motion_sensor_fill_values(&dst, v);
+ zassert_equal(dst.data[0], v[0], NULL);
+ zassert_equal(dst.data[1], v[1], NULL);
+ zassert_equal(dst.data[2], v[2], NULL);
+}
+
+ZTEST_USER(motion_sense, ec_motion_sensor_clamp_i16)
+{
+ zassert_equal(ec_motion_sensor_clamp_i16(0), 0, NULL);
+ zassert_equal(ec_motion_sensor_clamp_i16(200), 200, NULL);
+ zassert_equal(ec_motion_sensor_clamp_i16(-512), -512, NULL);
+ zassert_equal(ec_motion_sensor_clamp_i16(INT16_MAX + 1), INT16_MAX,
+ NULL);
+ zassert_equal(ec_motion_sensor_clamp_i16(INT16_MIN - 1), INT16_MIN,
+ NULL);
+}
diff --git a/zephyr/test/drivers/default/src/panic.c b/zephyr/test/drivers/default/src/panic.c
new file mode 100644
index 0000000000..4b97ed63d9
--- /dev/null
+++ b/zephyr/test/drivers/default/src/panic.c
@@ -0,0 +1,108 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief Unit Tests for panic.
+ */
+
+#include <zephyr/device.h>
+
+#include <zephyr/logging/log.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include "panic.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/test_state.h"
+
+struct panic_test_fixture {
+ struct panic_data saved_pdata;
+};
+
+static void *panic_test_setup(void)
+{
+ static struct panic_test_fixture panic_fixture = { 0 };
+
+ return &panic_fixture;
+}
+
+static void panic_before(void *state)
+{
+ struct panic_test_fixture *fixture = state;
+ struct panic_data *pdata = get_panic_data_write();
+
+ ARG_UNUSED(state);
+
+ fixture->saved_pdata = *pdata;
+}
+
+static void panic_after(void *state)
+{
+ struct panic_test_fixture *fixture = state;
+ struct panic_data *pdata = get_panic_data_write();
+
+ ARG_UNUSED(state);
+
+ *pdata = fixture->saved_pdata;
+}
+
+/**
+ * @brief Test Suite: Verifies panic functionality.
+ */
+ZTEST_SUITE(panic, drivers_predicate_post_main, panic_test_setup, panic_before,
+ panic_after, NULL);
+
+/**
+ * @brief TestPurpose: Verify panic set/get reason.
+ *
+ * @details
+ * Validate panic set/get reason.
+ *
+ * Expected Results
+ * - Success
+ */
+ZTEST(panic, test_panic_reason)
+{
+ uint32_t reason;
+ uint32_t info;
+ uint8_t exception;
+ struct panic_data *pdata = panic_get_data();
+
+ zassert_is_null(pdata, NULL);
+ panic_set_reason(PANIC_SW_WATCHDOG, 0, 0);
+
+ panic_get_reason(&reason, &info, &exception);
+
+ zassert_equal(PANIC_SW_WATCHDOG, reason, NULL);
+ zassert_equal(0, info, NULL);
+ zassert_equal(0, exception, NULL);
+
+ pdata = panic_get_data();
+ zassert_not_null(pdata, NULL);
+ zassert_equal(pdata->struct_version, 2, NULL);
+ zassert_equal(pdata->magic, PANIC_DATA_MAGIC, NULL);
+ zassert_equal(pdata->struct_size, CONFIG_PANIC_DATA_SIZE, NULL);
+
+ panic_data_print(pdata);
+}
+
+ZTEST(panic, test_panic_data_start_bad_magic)
+{
+ struct panic_data *pdata = get_panic_data_write();
+
+ pdata->magic = PANIC_DATA_MAGIC + 1;
+ zassert_equal(0, get_panic_data_start(), NULL);
+}
+
+ZTEST(panic, test_get_panic_data_start)
+{
+ struct panic_data *pdata = get_panic_data_write();
+
+ pdata->magic = PANIC_DATA_MAGIC;
+ zassert_equal((uintptr_t)pdata, get_panic_data_start(), NULL);
+}
diff --git a/zephyr/test/drivers/default/src/panic_output.c b/zephyr/test/drivers/default/src/panic_output.c
new file mode 100644
index 0000000000..210c862901
--- /dev/null
+++ b/zephyr/test/drivers/default/src/panic_output.c
@@ -0,0 +1,74 @@
+/* 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 "panic.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(panic_output, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
+
+ZTEST(panic_output, test_panic_printf)
+{
+ panic_printf("test output string from %s\n", __func__);
+}
+
+ZTEST(panic_output, test_panic_puts)
+{
+ panic_puts("test output string\n");
+}
+
+ZTEST(panic_output, test_panic_sw_reason_is_valid)
+{
+ zassert_false(panic_sw_reason_is_valid(PANIC_SW_BASE - 1), NULL);
+ /* PANIC_SW_DIV_ZERO */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE), NULL);
+ /* PANIC_SW_STACK_OVERFLOW */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 1), NULL);
+ /* PANIC_SW_PD_CRASH */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 2), NULL);
+ /* PANIC_SW_ASSERT */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 3), NULL);
+ /* PANIC_SW_WATCHDOG */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 4), NULL);
+ /* PANIC_SW_RNG */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 5), NULL);
+ /* PANIC_SW_PMIC_FAULT */
+ zassert_true(panic_sw_reason_is_valid(PANIC_SW_BASE + 6), NULL);
+ zassert_false(panic_sw_reason_is_valid(PANIC_SW_BASE + 7), NULL);
+}
+
+ZTEST(panic_output, test_panic)
+{
+ panic(__func__);
+ zassert_equal(1, system_reset_fake.call_count,
+ "Expected system_reset() to be called once, but was "
+ "called %d times",
+ system_reset_fake.call_count);
+ zassert_equal(0, system_reset_fake.arg0_val,
+ "Expected system_reset() to be called with flags=0, but "
+ "got flags=%d",
+ system_reset_fake.arg0_val);
+}
+
+ZTEST(panic_output, test_panic_assert_fail)
+{
+ int line_num = __LINE__;
+
+ panic_assert_fail("Test panic message", __func__, __FILE__, line_num);
+ zassert_equal(1, software_panic_fake.call_count,
+ "Expected sofware_panic() to be called once, but was "
+ "called %d times",
+ software_panic_fake.call_count);
+ zassert_equal(PANIC_SW_ASSERT, software_panic_fake.arg0_val,
+ "Expected software_panic() to be called with "
+ "reason=%d (PANIC_SW_ASSERT) but got %d",
+ PANIC_SW_ASSERT, software_panic_fake.arg0_val);
+ zassert_equal(line_num, software_panic_fake.arg1_val,
+ "Expected software_panic() to be called with "
+ "line=%d but got %d",
+ line_num, software_panic_fake.arg1_val);
+}
diff --git a/zephyr/test/drivers/default/src/port80.c b/zephyr/test/drivers/default/src/port80.c
new file mode 100644
index 0000000000..8563c2e478
--- /dev/null
+++ b/zephyr/test/drivers/default/src/port80.c
@@ -0,0 +1,191 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief Unit Tests for ESPI port 80 writes
+ */
+
+#include <zephyr/logging/log.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "ec_commands.h"
+#include "host_command.h"
+#include "port80.h"
+
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/*
+ * Flush any existing writes.
+ */
+static void port80_flush(void)
+{
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "port80 flush"), NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify port 80 writes
+ *
+ * @details
+ * Validate that the port 80 writes are processed correctly.
+ *
+ * Expected Results
+ * - The port 80 writes are received
+ */
+ZTEST(port80, test_port80_write)
+{
+ struct ec_response_port80_read response;
+ struct ec_params_port80_read params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_PORT80_READ, 1, response, params);
+
+ port80_flush();
+ port_80_write(0x12);
+ port_80_write(0x34);
+ /* Check the buffer using the host cmd */
+
+ /* Get the buffer info */
+ params.subcmd = EC_PORT80_GET_INFO;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response.get_info), NULL);
+ zassert_equal(response.get_info.writes, 2, NULL);
+ /* Read the buffer */
+ params.subcmd = EC_PORT80_READ_BUFFER;
+ params.read_buffer.offset = 0;
+ params.read_buffer.num_entries = 2;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(uint16_t) * 2, NULL);
+ zassert_equal(response.data.codes[0], 0x12, NULL);
+ zassert_equal(response.data.codes[1], 0x34, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify port 80 read parameters
+ *
+ * @details
+ * Validate that the port 80 read parameters are checked
+ *
+ * Expected Results
+ * - The port 80 parameters are verified
+ */
+ZTEST(port80, test_port80_offset)
+{
+ struct ec_response_port80_read response;
+ struct ec_params_port80_read params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_PORT80_READ, 1, response, params);
+
+ port80_flush();
+
+ params.subcmd = EC_PORT80_READ_BUFFER;
+ params.read_buffer.offset = 0;
+ params.read_buffer.num_entries = 0;
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, NULL);
+ params.read_buffer.offset = 0xFFFF;
+ params.read_buffer.num_entries = 2;
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, NULL);
+ params.read_buffer.offset = 0;
+ params.read_buffer.num_entries = 0xFFFF;
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify port 80 reset event
+ *
+ * @details
+ * Validate that the port 80 handling works for the reset event
+ *
+ * Expected Results
+ * - The port 80 handling detects the reset event.
+ */
+ZTEST(port80, test_port80_special)
+{
+ struct ec_params_port80_read params;
+ struct ec_response_port80_last_boot response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_PORT80_READ, 0, response, params);
+
+ port80_flush();
+ port_80_write(0xDEAD);
+ port_80_write(0xAA); /* must be < 0x100 */
+ port_80_write(PORT_80_EVENT_RESET);
+ /* Check the buffer using the host cmd version 0*/
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.code, 0xAA, NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify port 80 subcommand
+ *
+ * @details
+ * Validate that the port 80 host subcommand is checked.
+ *
+ * Expected Results
+ * - The port 80 handling detects an invalid subcommand.
+ */
+ZTEST(port80, test_port80_subcmd)
+{
+ struct ec_params_port80_read params;
+ struct ec_response_port80_last_boot response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_PORT80_READ, 1, response, params);
+
+ params.subcmd = 0xFFFF;
+ zassert_ok(!host_command_process(&args), NULL);
+}
+
+/**
+ * @brief TestPurpose: Verify port 80 write wrap
+ *
+ * @details
+ * Validate that the port 80 host writes wrap around.
+ *
+ * Expected Results
+ * - The port 80 writes overwrites the history array.
+ */
+ZTEST(port80, test_port80_wrap)
+{
+ struct ec_params_port80_read params;
+ struct ec_response_port80_read response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_PORT80_READ, 1, response, params);
+ uint32_t size, count;
+
+ port80_flush();
+ /* Get the history array size */
+ params.subcmd = EC_PORT80_GET_INFO;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response.get_info), NULL);
+ size = response.get_info.history_size;
+ count = size + size / 2; /* Ensure write will wrap the history */
+ for (uint32_t i = 0; i < count; i++) {
+ port_80_write(i);
+ }
+ /*
+ * Retrieve the first entry in the history array.
+ * It should equal the size of the array.
+ */
+ params.subcmd = EC_PORT80_READ_BUFFER;
+ params.read_buffer.offset = 0;
+ params.read_buffer.num_entries = 1;
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(uint16_t), NULL);
+ zassert_equal(response.data.codes[0], size, NULL);
+}
+
+/**
+ * @brief Test Suite: Verifies port 80 writes.
+ */
+ZTEST_SUITE(port80, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/power_common.c b/zephyr/test/drivers/default/src/power_common.c
new file mode 100644
index 0000000000..3579cb7b3c
--- /dev/null
+++ b/zephyr/test/drivers/default/src/power_common.c
@@ -0,0 +1,696 @@
+/* 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 <string.h>
+#include <zephyr/ztest.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/shell/shell_uart.h>
+
+#include "chipset.h"
+#include "common.h"
+#include "extpower.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "power.h"
+#include "test/drivers/stubs.h"
+#include "task.h"
+#include "ec_tasks.h"
+#include "test/drivers/test_state.h"
+
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_smart_battery.h"
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "test/drivers/utils.h"
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+/* Description of all power states with chipset state masks */
+static struct {
+ /* Power state */
+ enum power_state p_state;
+ /*
+ * CHIPSET_STATE_* to which this state transition (the same as
+ * transition_from for static states)
+ */
+ int transition_to;
+ /* CHIPSET_STATE_* from which this state transition */
+ int transition_from;
+} test_power_state_desc[] = {
+ {
+ .p_state = POWER_G3,
+ .transition_to = CHIPSET_STATE_HARD_OFF,
+ .transition_from = CHIPSET_STATE_HARD_OFF,
+ },
+ {
+ .p_state = POWER_G3S5,
+ .transition_to = CHIPSET_STATE_SOFT_OFF,
+ .transition_from = CHIPSET_STATE_HARD_OFF,
+ },
+ {
+ .p_state = POWER_S5G3,
+ .transition_to = CHIPSET_STATE_HARD_OFF,
+ .transition_from = CHIPSET_STATE_SOFT_OFF,
+ },
+ {
+ .p_state = POWER_S5,
+ .transition_to = CHIPSET_STATE_SOFT_OFF,
+ .transition_from = CHIPSET_STATE_SOFT_OFF,
+ },
+ {
+ .p_state = POWER_S5S3,
+ .transition_to = CHIPSET_STATE_SUSPEND,
+ .transition_from = CHIPSET_STATE_SOFT_OFF,
+ },
+ {
+ .p_state = POWER_S3S5,
+ .transition_to = CHIPSET_STATE_SOFT_OFF,
+ .transition_from = CHIPSET_STATE_SUSPEND,
+ },
+ {
+ .p_state = POWER_S3,
+ .transition_to = CHIPSET_STATE_SUSPEND,
+ .transition_from = CHIPSET_STATE_SUSPEND,
+ },
+ {
+ .p_state = POWER_S3S0,
+ .transition_to = CHIPSET_STATE_ON,
+ .transition_from = CHIPSET_STATE_SUSPEND,
+ },
+ {
+ .p_state = POWER_S0S3,
+ .transition_to = CHIPSET_STATE_SUSPEND,
+ .transition_from = CHIPSET_STATE_ON,
+ },
+ {
+ .p_state = POWER_S0,
+ .transition_to = CHIPSET_STATE_ON,
+ .transition_from = CHIPSET_STATE_ON,
+ },
+};
+
+/*
+ * Chipset state masks used by chipset_in_state and
+ * chipset_in_or_transitioning_to_state tests
+ */
+static int in_state_test_masks[] = {
+ CHIPSET_STATE_HARD_OFF,
+ CHIPSET_STATE_SOFT_OFF,
+ CHIPSET_STATE_SUSPEND,
+ CHIPSET_STATE_ON,
+ CHIPSET_STATE_STANDBY,
+ CHIPSET_STATE_ANY_OFF,
+ CHIPSET_STATE_ANY_SUSPEND,
+ CHIPSET_STATE_ANY_SUSPEND | CHIPSET_STATE_SOFT_OFF,
+};
+
+/** Test chipset_in_state() for each state */
+ZTEST(power_common_no_tasks, test_power_chipset_in_state)
+{
+ bool expected_in_state;
+ bool transition_from;
+ bool transition_to;
+ bool in_state;
+ int mask;
+
+ for (int i = 0; i < ARRAY_SIZE(test_power_state_desc); i++) {
+ /* Set given power state */
+ power_set_state(test_power_state_desc[i].p_state);
+ /* Test with selected state masks */
+ for (int j = 0; j < ARRAY_SIZE(in_state_test_masks); j++) {
+ mask = in_state_test_masks[j];
+ /*
+ * Currently tested mask match with state if it match
+ * with transition_to and from chipset states
+ */
+ transition_to = mask &
+ test_power_state_desc[i].transition_to;
+ transition_from =
+ mask & test_power_state_desc[i].transition_from;
+ expected_in_state = transition_to && transition_from;
+ in_state = chipset_in_state(mask);
+ zassert_equal(expected_in_state, in_state,
+ "Wrong chipset_in_state() == %d, "
+ "should be %d; mask 0x%x; power state %d "
+ "in test case %d",
+ in_state, expected_in_state, mask,
+ test_power_state_desc[i].p_state, i);
+ }
+ }
+}
+
+/** Test chipset_in_or_transitioning_to_state() for each state */
+ZTEST(power_common_no_tasks, test_power_chipset_in_or_transitioning_to_state)
+{
+ bool expected_in_state;
+ bool in_state;
+ int mask;
+
+ for (int i = 0; i < ARRAY_SIZE(test_power_state_desc); i++) {
+ /* Set given power state */
+ power_set_state(test_power_state_desc[i].p_state);
+ /* Test with selected state masks */
+ for (int j = 0; j < ARRAY_SIZE(in_state_test_masks); j++) {
+ mask = in_state_test_masks[j];
+ /*
+ * Currently tested mask match with state if it match
+ * with transition_to chipset state
+ */
+ expected_in_state =
+ mask & test_power_state_desc[i].transition_to;
+ in_state = chipset_in_or_transitioning_to_state(mask);
+ zassert_equal(expected_in_state, in_state,
+ "Wrong "
+ "chipset_in_or_transitioning_to_state() "
+ "== %d, should be %d; mask 0x%x; "
+ "power state %d in test case %d",
+ in_state, expected_in_state, mask,
+ test_power_state_desc[i].p_state, i);
+ }
+ }
+}
+
+/* Test using chipset_exit_hard_off() in different power states. The only
+ * way to test the value of want_g3_exit is to set the power state to G3
+ * and then to see if test_power_common_state() transitions to G3S5 or not.
+ */
+ZTEST(power_common_no_tasks, test_power_exit_hard_off)
+{
+ /*
+ * Every test runs in a new thread, we need to add this thread to the
+ * dynamic shimmed tasks or this test will fail.
+ */
+ set_test_runner_tid();
+
+ /* Force initial state */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3, power_get_state(), NULL);
+
+ /* Test after exit hard off, we reach G3S5 */
+ chipset_exit_hard_off();
+ test_power_common_state();
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+
+ /* Go back to G3 and check we stay there */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3, power_get_state(), NULL);
+
+ /* Exit G3 again */
+ chipset_exit_hard_off();
+ test_power_common_state();
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+
+ /* Go to S5G3 */
+ power_set_state(POWER_S5G3);
+ test_power_common_state();
+ zassert_equal(POWER_S5G3, power_get_state(), NULL);
+
+ /* Test exit hard off in S5G3 -- should set want_g3_exit */
+ chipset_exit_hard_off();
+ /* Go back to G3 and check we exit it to G3S5 */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+
+ /* Test exit hard off is cleared on entering S5 */
+ chipset_exit_hard_off();
+ power_set_state(POWER_S5);
+ test_power_common_state();
+ zassert_equal(POWER_S5, power_get_state(), NULL);
+
+ /* Go back to G3 and check we stay in G3 */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3, power_get_state(), NULL);
+
+ /* Test exit hard off doesn't work on other states */
+ power_set_state(POWER_S5S3);
+ test_power_common_state();
+ zassert_equal(POWER_S5S3, power_get_state(), NULL);
+ chipset_exit_hard_off();
+ test_power_common_state();
+
+ /* Go back to G3 and check we stay in G3 */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3, power_get_state(), NULL);
+}
+
+/* Test reboot ap on g3 host command is triggering reboot */
+ZTEST(power_common_no_tasks, test_power_reboot_ap_at_g3)
+{
+ struct ec_params_reboot_ap_on_g3_v1 params;
+ struct host_cmd_handler_args args = {
+ .command = EC_CMD_REBOOT_AP_ON_G3,
+ .version = 0,
+ .send_response = stub_send_response_callback,
+ .params = &params,
+ .params_size = sizeof(params),
+ };
+ int delay_ms;
+ int64_t before_time;
+
+ /*
+ * Every test runs in a new thread, we need to add this thread to the
+ * dynamic shimmed tasks or this test will fail.
+ */
+ set_test_runner_tid();
+
+ /* Force initial state S0 */
+ power_set_state(POWER_S0);
+ test_power_common_state();
+ zassert_equal(POWER_S0, power_get_state(), NULL);
+
+ /* Test version 0 (no delay argument) */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ /* Go to G3 and check if reboot is triggered */
+ power_set_state(POWER_G3);
+ test_power_common_state();
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+
+ /* Test version 1 (with delay argument) */
+ args.version = 1;
+ delay_ms = 3000;
+ params.reboot_ap_at_g3_delay = delay_ms / 1000; /* in seconds */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ /* Go to G3 and check if reboot is triggered after delay */
+ power_set_state(POWER_G3);
+ before_time = k_uptime_get();
+ test_power_common_state();
+ zassert_true(k_uptime_delta(&before_time) >= 3000, NULL);
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+}
+
+/** Test setting cutoff and stay-up battery levels through host command */
+ZTEST(power_common, test_power_hc_smart_discharge)
+{
+ struct ec_response_smart_discharge response;
+ struct ec_params_smart_discharge params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_SMART_DISCHARGE, 0, response, params);
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ int hours_to_zero;
+ int hibern_drate;
+ int cutoff_drate;
+ int stayup_cap;
+ int cutoff_cap;
+
+ /* Set up host command parameters */
+ params.flags = EC_SMART_DISCHARGE_FLAGS_SET;
+
+ /* Test fail when battery capacity is not available */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_FULL_CHARGE_CAPACITY);
+ zassert_equal(EC_RES_UNAVAILABLE, host_command_process(&args), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup discharge rates */
+ params.drate.hibern = 10;
+ params.drate.cutoff = 100;
+ /* Test fail on higher discahrge in hibernation than cutoff */
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL);
+
+ /* Setup discharge rates */
+ params.drate.hibern = 10;
+ params.drate.cutoff = 0;
+ /* Test fail on only one discharge rate set to 0 */
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL);
+
+ /* Setup correct parameters */
+ hours_to_zero = 1000;
+ hibern_drate = 100; /* uA */
+ cutoff_drate = 10; /* uA */
+ /* Need at least 100 mA capacity to stay 1000h using 0.1mAh */
+ stayup_cap = hibern_drate * hours_to_zero / 1000;
+ /* Need at least 10 mA capacity to stay 1000h using 0.01mAh */
+ cutoff_cap = cutoff_drate * hours_to_zero / 1000;
+
+ params.drate.hibern = hibern_drate;
+ params.drate.cutoff = cutoff_drate;
+ params.hours_to_zero = hours_to_zero;
+
+ /* Test if correct values are set */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ zassert_equal(hibern_drate, response.drate.hibern, NULL);
+ zassert_equal(cutoff_drate, response.drate.cutoff, NULL);
+ zassert_equal(hours_to_zero, response.hours_to_zero, NULL);
+ zassert_equal(stayup_cap, response.dzone.stayup, NULL);
+ zassert_equal(cutoff_cap, response.dzone.cutoff, NULL);
+
+ /* Setup discharge rate to 0 */
+ params.drate.hibern = 0;
+ params.drate.cutoff = 0;
+ /* Update hours to zero */
+ hours_to_zero = 2000;
+ params.hours_to_zero = hours_to_zero;
+ /* Need at least 200 mA capacity to stay 2000h using 0.1mAh */
+ stayup_cap = hibern_drate * hours_to_zero / 1000;
+ /* Need at least 20 mA capacity to stay 2000h using 0.01mAh */
+ cutoff_cap = cutoff_drate * hours_to_zero / 1000;
+
+ /* Test that command doesn't change drate but apply new hours to zero */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ zassert_equal(hibern_drate, response.drate.hibern, NULL);
+ zassert_equal(cutoff_drate, response.drate.cutoff, NULL);
+ zassert_equal(hours_to_zero, response.hours_to_zero, NULL);
+ zassert_equal(stayup_cap, response.dzone.stayup, NULL);
+ zassert_equal(cutoff_cap, response.dzone.cutoff, NULL);
+
+ /* Setup any parameters != 0 */
+ params.drate.hibern = 1000;
+ params.drate.cutoff = 1000;
+ /* Clear set flag */
+ params.flags = 0;
+
+ /* Test that command doesn't change drate and dzone */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ zassert_equal(hibern_drate, response.drate.hibern, NULL);
+ zassert_equal(cutoff_drate, response.drate.cutoff, NULL);
+ zassert_equal(hours_to_zero, response.hours_to_zero, NULL);
+ zassert_equal(stayup_cap, response.dzone.stayup, NULL);
+ zassert_equal(cutoff_cap, response.dzone.cutoff, NULL);
+}
+
+/**
+ * Test if default board_system_is_idle() recognize cutoff and stay-up
+ * levels correctly.
+ */
+ZTEST(power_common, test_power_board_system_is_idle)
+{
+ struct ec_response_smart_discharge response;
+ struct ec_params_smart_discharge params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_SMART_DISCHARGE, 0, response, params);
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ uint64_t last_shutdown_time = 0;
+ uint64_t target;
+ uint64_t now;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Set up host command parameters */
+ params.drate.hibern = 100; /* uA */
+ params.drate.cutoff = 10; /* uA */
+ params.hours_to_zero = 1000; /* h */
+ params.flags = EC_SMART_DISCHARGE_FLAGS_SET;
+ /* Set stay-up and cutoff zones */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ /* Test shutdown ignore is send when target time is in future */
+ target = 1125;
+ now = 1000;
+ zassert_equal(CRITICAL_SHUTDOWN_IGNORE,
+ board_system_is_idle(last_shutdown_time, &target, now),
+ NULL);
+
+ /* Set "now" time after target time */
+ now = target + 30;
+
+ /*
+ * Test hibernation is requested when battery remaining capacity
+ * is not available
+ */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_REMAINING_CAPACITY);
+ zassert_equal(CRITICAL_SHUTDOWN_HIBERNATE,
+ board_system_is_idle(last_shutdown_time, &target, now),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Setup remaining capacity to trigger cutoff */
+ bat->cap = response.dzone.cutoff - 5;
+ zassert_equal(CRITICAL_SHUTDOWN_CUTOFF,
+ board_system_is_idle(last_shutdown_time, &target, now),
+ NULL);
+
+ /* Setup remaining capacity to trigger stay-up and ignore shutdown */
+ bat->cap = response.dzone.stayup - 5;
+ zassert_equal(CRITICAL_SHUTDOWN_IGNORE,
+ board_system_is_idle(last_shutdown_time, &target, now),
+ NULL);
+
+ /* Setup remaining capacity to be in safe zone to hibernate */
+ bat->cap = response.dzone.stayup + 5;
+ zassert_equal(CRITICAL_SHUTDOWN_HIBERNATE,
+ board_system_is_idle(last_shutdown_time, &target, now),
+ NULL);
+}
+
+/**
+ * Test power console command
+ */
+ZTEST(power_common, power_console_cmd)
+{
+ const char *buffer;
+ size_t buffer_size;
+
+ test_set_chipset_to_g3();
+ shell_backend_dummy_clear_output(get_ec_shell());
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "power"),
+ NULL);
+ buffer = shell_backend_dummy_get_output(get_ec_shell(), &buffer_size);
+ zassert_true(strcmp(buffer, "\r\noff\r\n") == 0 ||
+ strcmp(buffer, "\r\nOFF\r\n") == 0,
+ "Invalid console output %s", buffer);
+
+ test_set_chipset_to_s0();
+ shell_backend_dummy_clear_output(get_ec_shell());
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "power"),
+ NULL);
+ buffer = shell_backend_dummy_get_output(get_ec_shell(), &buffer_size);
+ zassert_true(strcmp(buffer, "\r\non\r\n") == 0 ||
+ strcmp(buffer, "\r\nON\r\n") == 0,
+ "Invalid console output %s", buffer);
+
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "power x"), NULL);
+
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "power on"),
+ NULL);
+
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "power off"), NULL);
+}
+
+/**
+ * Common setup for hibernation delay tests. Smart discharge zone is setup,
+ * battery is set in safe zone (which trigger hibernation), power state is
+ * set to G3 and AC is disabled. system_hibernate mock is reset.
+ */
+static void setup_hibernation_delay(void *state)
+{
+ struct ec_response_smart_discharge response;
+ struct ec_params_smart_discharge params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_SMART_DISCHARGE, 0, response, params);
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ ARG_UNUSED(state);
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Setup smart discharge zone and set capacity to safe zone */
+ params.drate.hibern = 100; /* uA */
+ params.drate.cutoff = 10; /* uA */
+ params.hours_to_zero = 10000; /* h */
+ params.flags = EC_SMART_DISCHARGE_FLAGS_SET;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ /*
+ * Make sure that battery is in safe zone in good condition to
+ * not trigger hibernate in charge_state_v2.c
+ */
+ bat->cap = response.dzone.stayup + 5;
+ bat->volt = battery_get_info()->voltage_normal;
+
+ /* Force initial state */
+ test_set_chipset_to_g3();
+
+ /* Disable AC */
+ set_ac_enabled(false);
+
+ RESET_FAKE(system_hibernate);
+}
+
+/** Test setting hibernation delay through host command */
+ZTEST(power_common_hibernation, test_power_hc_hibernation_delay)
+{
+ struct ec_response_hibernation_delay response;
+ struct ec_params_hibernation_delay params;
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND(
+ EC_CMD_HIBERNATION_DELAY, 0, response, params);
+ uint32_t h_delay;
+ int sleep_time;
+
+ /* Ensure the lid is closed so AC connect does not boot system */
+ zassert_ok(shell_execute_cmd(get_ec_shell(), "lidclose"), NULL);
+
+ zassert_equal(power_get_state(), POWER_G3,
+ "Power state is %d, expected G3", power_get_state());
+ /* This is a no-op, but it will reset the last_shutdown_time. */
+ power_set_state(POWER_G3);
+
+ /* Set hibernate delay */
+ h_delay = 9;
+ params.seconds = h_delay;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ zassert_equal(0, response.time_g3, "Time from last G3 enter %d != 0",
+ response.time_g3);
+ zassert_equal(h_delay, response.time_remaining,
+ "Time to hibernation %d != %d", response.time_remaining,
+ h_delay);
+ zassert_equal(h_delay, response.hibernate_delay,
+ "Hibernation delay %d != %d", h_delay,
+ response.hibernate_delay);
+
+ /* Kick chipset task to process new hibernation delay */
+ task_wake(TASK_ID_CHIPSET);
+ /* Wait some arbitrary time less than hibernate delay */
+ sleep_time = 6;
+ k_msleep(sleep_time * 1000);
+
+ /* Get hibernate delay */
+ params.seconds = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ zassert_equal(sleep_time, response.time_g3,
+ "Time from last G3 enter %d != %d", response.time_g3,
+ sleep_time);
+ zassert_equal(h_delay - sleep_time, response.time_remaining,
+ "Time to hibernation %d != %d", response.time_remaining,
+ h_delay - sleep_time);
+ zassert_equal(h_delay, response.hibernate_delay,
+ "Hibernation delay %d != %d", h_delay,
+ response.hibernate_delay);
+ zassert_equal(0, system_hibernate_fake.call_count,
+ "system_hibernate() shouldn't be called before delay");
+
+ /* Wait to end of the hibenate delay */
+ k_msleep((h_delay - sleep_time) * 1000);
+
+ /* Get hibernate delay */
+ params.seconds = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ zassert_equal(h_delay, response.time_g3,
+ "Time from last G3 enter %d != %d", response.time_g3,
+ h_delay);
+ zassert_equal(0, response.time_remaining, "Time to hibernation %d != 0",
+ response.time_remaining);
+ zassert_equal(h_delay, response.hibernate_delay,
+ "Hibernation delay %d != %d", h_delay,
+ response.hibernate_delay);
+ zassert_equal(1, system_hibernate_fake.call_count,
+ "system_hibernate() should be called after delay %d",
+ system_hibernate_fake.call_count);
+
+ /* Wait some more time */
+ k_msleep(2000);
+
+ /* Get hibernate delay */
+ params.seconds = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ /* After hibernation, remaining time shouldn't be negative */
+ zassert_equal(0, response.time_remaining, "Time to hibernation %d != 0",
+ response.time_remaining);
+
+ /* Enable AC */
+ set_ac_enabled(true);
+
+ /* Reset system_hibernate fake to check that it is not called on AC */
+ RESET_FAKE(system_hibernate);
+ /* Allow chipset task to spin with enabled AC */
+ task_wake(TASK_ID_CHIPSET);
+ k_msleep(1);
+
+ /* Get hibernate delay */
+ params.seconds = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ zassert_equal(0, response.time_g3,
+ "Time from last G3 enter %d should be 0 on AC",
+ response.time_g3);
+ zassert_equal(0, system_hibernate_fake.call_count,
+ "system_hibernate() shouldn't be called on AC");
+
+ /* Disable AC */
+ set_ac_enabled(false);
+
+ /* Go to different state */
+ power_set_state(POWER_G3S5);
+ zassert_equal(POWER_G3S5, power_get_state(), NULL);
+
+ /* Get hibernate delay */
+ params.seconds = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+
+ zassert_equal(0, response.time_g3,
+ "Time from last G3 enter %d should be 0 on state != G3",
+ response.time_g3);
+}
+
+/** Test setting hibernation delay through UART command */
+ZTEST(power_common_hibernation, test_power_cmd_hibernation_delay)
+{
+ uint32_t h_delay;
+ int sleep_time;
+
+ zassert_equal(power_get_state(), POWER_G3,
+ "Power state is %d, expected G3", power_get_state());
+ /* This is a no-op, but it will reset the last_shutdown_time. */
+ power_set_state(POWER_G3);
+
+ /* Test success on call without argument */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "hibdelay"),
+ NULL);
+
+ /* Test error on hibernation delay argument that is not a number */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "hibdelay test1"),
+ NULL);
+
+ /* Set hibernate delay */
+ h_delay = 3;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "hibdelay 3"), NULL);
+
+ /* Kick chipset task to process new hibernation delay */
+ task_wake(TASK_ID_CHIPSET);
+ /* Wait some arbitrary time less than hibernate delay */
+ sleep_time = 2;
+ k_msleep(sleep_time * 1000);
+
+ zassert_equal(0, system_hibernate_fake.call_count,
+ "system_hibernate() shouldn't be called before delay");
+
+ /* Wait to end of the hibenate delay */
+ k_msleep((h_delay - sleep_time) * 1000);
+
+ zassert_equal(1, system_hibernate_fake.call_count,
+ "system_hibernate() should be called after delay %d",
+ system_hibernate_fake.call_count);
+}
+
+ZTEST_SUITE(power_common_no_tasks, drivers_predicate_pre_main, NULL, NULL, NULL,
+ NULL);
+
+ZTEST_SUITE(power_common, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
+
+ZTEST_SUITE(power_common_hibernation, drivers_predicate_post_main, NULL,
+ setup_hibernation_delay, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/ppc_sn5s330.c b/zephyr/test/drivers/default/src/ppc_sn5s330.c
new file mode 100644
index 0000000000..c9ba62cf20
--- /dev/null
+++ b/zephyr/test/drivers/default/src/ppc_sn5s330.c
@@ -0,0 +1,689 @@
+/* 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/device.h>
+#include <zephyr/devicetree.h>
+#include <zephyr/drivers/emul.h>
+#include <zephyr/ztest.h>
+#include <zephyr/fff.h>
+
+#include "driver/ppc/sn5s330.h"
+#include "driver/ppc/sn5s330_public.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_sn5s330.h"
+#include "usbc_ppc.h"
+#include "test/drivers/test_mocks.h"
+#include "test/drivers/test_state.h"
+
+/** This must match the index of the sn5s330 in ppc_chips[] */
+#define SN5S330_PORT 0
+#define EMUL EMUL_DT_GET(DT_NODELABEL(sn5s330_emul))
+#define COMMON_DATA emul_sn5s330_get_i2c_common_data(EMUL)
+#define FUNC_SET1_ILIMPP1_MSK 0x1F
+#define SN5S330_INTERRUPT_DELAYMS 15
+
+FAKE_VOID_FUNC(sn5s330_emul_interrupt_set_stub);
+
+/*
+ * TODO(b/203364783): Exclude other threads from interacting with the emulator
+ * to avoid test flakiness
+ */
+
+struct intercept_write_data {
+ int reg_to_intercept;
+ uint8_t val_intercepted;
+};
+
+struct intercept_read_data {
+ int reg_to_intercept;
+ bool replace_reg_val;
+ uint8_t replacement_val;
+};
+
+static int intercept_read_func(const struct emul *emul, int reg, uint8_t *val,
+ int bytes, void *data)
+{
+ struct intercept_read_data *test_data = data;
+
+ if (test_data->reg_to_intercept && test_data->replace_reg_val)
+ *val = test_data->replacement_val;
+
+ return EC_SUCCESS;
+}
+
+static int intercept_write_func(const struct emul *emul, int reg, uint8_t val,
+ int bytes, void *data)
+{
+ struct intercept_write_data *test_data = data;
+
+ if (test_data->reg_to_intercept == reg)
+ test_data->val_intercepted = val;
+
+ return 1;
+}
+
+static int fail_until_write_func(const struct emul *emul, int reg, uint8_t val,
+ int bytes, void *data)
+{
+ uint32_t *count = data;
+
+ if (*count != 0) {
+ *count -= 1;
+ return -EIO;
+ }
+ return 1;
+}
+
+ZTEST(ppc_sn5s330, test_fail_once_func_set1)
+{
+ const struct emul *emul = EMUL;
+ uint32_t count = 1;
+ uint8_t func_set1_value;
+
+ i2c_common_emul_set_write_func(COMMON_DATA, fail_until_write_func,
+ &count);
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+ zassert_equal(count, 0, NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, &func_set1_value);
+ zassert_true((func_set1_value & SN5S330_ILIM_1_62) != 0, NULL);
+ i2c_common_emul_set_write_func(COMMON_DATA, NULL, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_dead_battery_boot_force_pp2_fets_set)
+{
+ struct intercept_write_data test_write_data = {
+ .reg_to_intercept = SN5S330_FUNC_SET3,
+ .val_intercepted = 0,
+ };
+ struct intercept_read_data test_read_data = {
+ .reg_to_intercept = SN5S330_INT_STATUS_REG4,
+ .replace_reg_val = true,
+ .replacement_val = SN5S330_DB_BOOT,
+ };
+
+ i2c_common_emul_set_write_func(COMMON_DATA, intercept_write_func,
+ &test_write_data);
+ i2c_common_emul_set_read_func(COMMON_DATA, intercept_read_func,
+ &test_read_data);
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /*
+ * Although the device enables PP2_FET on dead battery boot by setting
+ * the PP2_EN bit, the driver also force sets this bit during dead
+ * battery boot by writing that bit to the FUNC_SET3 reg.
+ *
+ * TODO(b/207034759): Verify need or remove redundant PP2 set.
+ */
+ zassert_true(test_write_data.val_intercepted & SN5S330_PP2_EN, NULL);
+ zassert_false(sn5s330_drv.is_sourcing_vbus(SN5S330_PORT), NULL);
+}
+
+ZTEST(ppc_sn5s330, test_enter_low_power_mode)
+{
+ const struct emul *emul = EMUL;
+
+ uint8_t func_set2_reg;
+ uint8_t func_set3_reg;
+ uint8_t func_set4_reg;
+ uint8_t func_set9_reg;
+
+ /*
+ * Requirements were extracted from TI's recommended changes for octopus
+ * to lower power use during hibernate as well as the follow up changes
+ * we made to allow the device to wake up from hibernate.
+ *
+ * For Reference: b/111006203#comment35
+ */
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+ zassert_ok(sn5s330_drv.enter_low_power_mode(SN5S330_PORT), NULL);
+
+ /* 1) Verify VBUS power paths are off */
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_equal(func_set3_reg & SN5S330_PP1_EN, 0, NULL);
+ zassert_equal(func_set3_reg & SN5S330_PP2_EN, 0, NULL);
+
+ /* 2) Verify VCONN power path is off */
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET4, &func_set4_reg);
+ zassert_not_equal(func_set4_reg & SN5S330_CC_EN, 0, NULL);
+ zassert_equal(func_set4_reg & SN5S330_VCONN_EN, 0, NULL);
+
+ /* 3) Verify SBU FET is off */
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET2, &func_set2_reg);
+ zassert_equal(func_set2_reg & SN5S330_SBU_EN, 0, NULL);
+
+ /* 4) Verify VBUS and SBU OVP comparators are off */
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET9, &func_set9_reg);
+ zassert_equal(func_set9_reg & SN5S330_FORCE_OVP_EN_SBU, 0, NULL);
+ zassert_equal(func_set9_reg & SN5S330_PWR_OVR_VBUS, 0, NULL);
+ zassert_not_equal(func_set9_reg & SN5S330_OVP_EN_CC, 0, NULL);
+ zassert_equal(func_set9_reg & SN5S330_FORCE_ON_VBUS_OVP, 0, NULL);
+ zassert_equal(func_set9_reg & SN5S330_FORCE_ON_VBUS_UVP, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_vbus_source_sink_enable)
+{
+ const struct emul *emul = EMUL;
+ uint8_t func_set3_reg;
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /* Test enable/disable VBUS source FET */
+ zassert_ok(sn5s330_drv.vbus_source_enable(SN5S330_PORT, true), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_not_equal(func_set3_reg & SN5S330_PP1_EN, 0, NULL);
+
+ zassert_ok(sn5s330_drv.vbus_source_enable(SN5S330_PORT, false), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_equal(func_set3_reg & SN5S330_PP1_EN, 0, NULL);
+
+ /* Test enable/disable VBUS sink FET */
+ zassert_ok(sn5s330_drv.vbus_sink_enable(SN5S330_PORT, true), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_not_equal(func_set3_reg & SN5S330_PP2_EN, 0, NULL);
+
+ zassert_ok(sn5s330_drv.vbus_sink_enable(SN5S330_PORT, false), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_equal(func_set3_reg & SN5S330_PP2_EN, 0, NULL);
+}
+
+/* This test depends on EC GIPO initialization happening before I2C */
+BUILD_ASSERT(CONFIG_PLATFORM_EC_GPIO_INIT_PRIORITY < CONFIG_I2C_INIT_PRIORITY,
+ "GPIO initialization must happen before I2C");
+ZTEST(ppc_sn5s330, test_vbus_discharge)
+{
+ const struct emul *emul = EMUL;
+ uint8_t func_set3_reg;
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /* Test enable/disable VBUS discharging */
+ zassert_ok(sn5s330_drv.discharge_vbus(SN5S330_PORT, true), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_not_equal(func_set3_reg & SN5S330_VBUS_DISCH_EN, 0, NULL);
+
+ zassert_ok(sn5s330_drv.discharge_vbus(SN5S330_PORT, false), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET3, &func_set3_reg);
+ zassert_equal(func_set3_reg & SN5S330_VBUS_DISCH_EN, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_set_vbus_source_current_limit)
+{
+ const struct emul *emul = EMUL;
+ uint8_t func_set1_reg;
+
+ /* Test every TCPC Pull Resistance Value */
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /* USB */
+ zassert_ok(sn5s330_drv.set_vbus_source_current_limit(SN5S330_PORT,
+ TYPEC_RP_USB),
+ NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, &func_set1_reg);
+ zassert_equal(func_set1_reg & FUNC_SET1_ILIMPP1_MSK, SN5S330_ILIM_0_63,
+ NULL);
+
+ /* 1.5A */
+ zassert_ok(sn5s330_drv.set_vbus_source_current_limit(SN5S330_PORT,
+ TYPEC_RP_1A5),
+ NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, &func_set1_reg);
+ zassert_equal(func_set1_reg & FUNC_SET1_ILIMPP1_MSK, SN5S330_ILIM_1_62,
+ NULL);
+
+ /* 3.0A */
+ zassert_ok(sn5s330_drv.set_vbus_source_current_limit(SN5S330_PORT,
+ TYPEC_RP_3A0),
+ NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, &func_set1_reg);
+ zassert_equal(func_set1_reg & FUNC_SET1_ILIMPP1_MSK, SN5S330_ILIM_3_06,
+ NULL);
+
+ /* Unknown/Reserved - We set result as USB */
+ zassert_ok(sn5s330_drv.set_vbus_source_current_limit(SN5S330_PORT,
+ TYPEC_RP_RESERVED),
+ NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, &func_set1_reg);
+ zassert_equal(func_set1_reg & FUNC_SET1_ILIMPP1_MSK, SN5S330_ILIM_0_63,
+ NULL);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_set_sbu)
+#ifdef CONFIG_USBC_PPC_SBU
+{
+ const struct emul *emul = EMUL;
+ uint8_t func_set2_reg;
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /* Verify driver enables SBU FET */
+ zassert_ok(sn5s330_drv.set_sbu(SN5S330_PORT, true), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET2, &func_set2_reg);
+ zassert_not_equal(func_set2_reg & SN5S330_SBU_EN, 0, NULL);
+
+ /* Verify driver disables SBU FET */
+ zassert_ok(sn5s330_drv.set_sbu(SN5S330_PORT, false), NULL);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET2, &func_set2_reg);
+ zassert_equal(func_set2_reg & SN5S330_SBU_EN, 0, NULL);
+}
+#else
+{
+ ztest_test_skip();
+}
+#endif /* CONFIG_USBC_PPC_SBU */
+
+ZTEST(ppc_sn5s330, test_sn5s330_vbus_overcurrent)
+{
+ const struct emul *emul = EMUL;
+ uint8_t int_trip_rise_reg1;
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ sn5s330_emul_make_vbus_overcurrent(emul);
+ /*
+ * TODO(b/201420132): Replace arbitrary sleeps.
+ */
+ /* Make sure interrupt happens first. */
+ k_msleep(SN5S330_INTERRUPT_DELAYMS);
+ zassert_true(sn5s330_emul_interrupt_set_stub_fake.call_count > 0, NULL);
+
+ /*
+ * Verify we cleared vbus overcurrent interrupt trip rise bit so the
+ * driver can detect future overcurrent clamping interrupts.
+ */
+ sn5s330_emul_peek_reg(emul, SN5S330_INT_TRIP_RISE_REG1,
+ &int_trip_rise_reg1);
+ zassert_equal(int_trip_rise_reg1 & SN5S330_ILIM_PP1_MASK, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_vbus_overcurrent_late_jump)
+{
+ const struct emul *emul = EMUL;
+ uint8_t int_trip_rise_reg1;
+
+ /* Simulate the system jumping late. The second call to init() will
+ * skip certain interrupt setup work. Make sure the interrupt continues
+ * to function.
+ */
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+ system_jumped_late_fake.return_val = 1;
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ sn5s330_emul_make_vbus_overcurrent(emul);
+ /*
+ * TODO(b/201420132): Replace arbitrary sleeps.
+ */
+ /* Make sure interrupt happens first. */
+ k_msleep(SN5S330_INTERRUPT_DELAYMS);
+ zassert_true(sn5s330_emul_interrupt_set_stub_fake.call_count > 0, NULL);
+
+ /*
+ * Verify we cleared vbus overcurrent interrupt trip rise bit so the
+ * driver can detect future overcurrent clamping interrupts.
+ */
+ sn5s330_emul_peek_reg(emul, SN5S330_INT_TRIP_RISE_REG1,
+ &int_trip_rise_reg1);
+ zassert_equal(int_trip_rise_reg1 & SN5S330_ILIM_PP1_MASK, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_disable_vbus_low_interrupt)
+{
+ const struct emul *emul = EMUL;
+
+ /* Interrupt disabled here */
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+ /* Would normally cause a vbus low interrupt */
+ sn5s330_emul_lower_vbus_below_minv(emul);
+ zassert_equal(sn5s330_emul_interrupt_set_stub_fake.call_count, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_disable_vbus_low_interrupt_late_jump)
+{
+ const struct emul *emul = EMUL;
+
+ /* Simulate the system jumping late. The second call to init() will
+ * skip certain interrupt setup work. Make sure the interrupt continues
+ * to function.
+ */
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+ system_jumped_late_fake.return_val = 1;
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ /* Would normally cause a vbus low interrupt */
+ sn5s330_emul_lower_vbus_below_minv(emul);
+ zassert_equal(sn5s330_emul_interrupt_set_stub_fake.call_count, 0, NULL);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_set_vconn_fet)
+{
+ if (!IS_ENABLED(CONFIG_USBC_PPC_VCONN)) {
+ ztest_test_skip();
+ return;
+ }
+
+ const struct emul *emul = EMUL;
+ uint8_t func_set4_reg;
+
+ zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL);
+
+ sn5s330_drv.set_vconn(SN5S330_PORT, false);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET4, &func_set4_reg);
+ zassert_equal(func_set4_reg & SN5S330_VCONN_EN, 0, NULL);
+
+ sn5s330_drv.set_vconn(SN5S330_PORT, true);
+ sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET4, &func_set4_reg);
+ zassert_not_equal(func_set4_reg & SN5S330_VCONN_EN, 0, NULL);
+}
+
+/* Make an I2C emulator mock read func wrapped in FFF */
+FAKE_VALUE_FUNC(int, dump_read_fn, const struct emul *, int, uint8_t *, int,
+ void *);
+
+ZTEST(ppc_sn5s330, test_dump)
+{
+ int ret;
+
+ /* Set up our fake read function to pass through to the real emul */
+ RESET_FAKE(dump_read_fn);
+ dump_read_fn_fake.return_val = 1;
+ i2c_common_emul_set_read_func(COMMON_DATA, dump_read_fn, NULL);
+
+ ret = sn5s330_drv.reg_dump(SN5S330_PORT);
+
+ zassert_equal(EC_SUCCESS, ret, "Expected EC_SUCCESS, got %d", ret);
+
+ /* Check that all the expected I2C reads were performed. */
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 0, SN5S330_FUNC_SET1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 1, SN5S330_FUNC_SET2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 2, SN5S330_FUNC_SET3);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 3, SN5S330_FUNC_SET4);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 4, SN5S330_FUNC_SET5);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 5, SN5S330_FUNC_SET6);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 6, SN5S330_FUNC_SET7);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 7, SN5S330_FUNC_SET8);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 8, SN5S330_FUNC_SET9);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 9, SN5S330_FUNC_SET10);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 10, SN5S330_FUNC_SET11);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 11, SN5S330_FUNC_SET12);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 12, SN5S330_INT_STATUS_REG1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 13, SN5S330_INT_STATUS_REG2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 14, SN5S330_INT_STATUS_REG3);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 15, SN5S330_INT_STATUS_REG4);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 16, SN5S330_INT_TRIP_RISE_REG1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 17, SN5S330_INT_TRIP_RISE_REG2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 18, SN5S330_INT_TRIP_RISE_REG3);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 19, SN5S330_INT_TRIP_FALL_REG1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 20, SN5S330_INT_TRIP_FALL_REG2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 21, SN5S330_INT_TRIP_FALL_REG3);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 22, SN5S330_INT_MASK_RISE_REG1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 23, SN5S330_INT_MASK_RISE_REG2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 24, SN5S330_INT_MASK_RISE_REG3);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 25, SN5S330_INT_MASK_FALL_REG1);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 26, SN5S330_INT_MASK_FALL_REG2);
+ MOCK_ASSERT_I2C_READ(dump_read_fn, 27, SN5S330_INT_MASK_FALL_REG3);
+}
+
+enum i2c_operation {
+ I2C_WRITE,
+ I2C_READ,
+};
+
+#define INIT_I2C_FAIL_HELPER(COMMON_DATA, RW, REG) \
+ do { \
+ if ((RW) == I2C_READ) { \
+ i2c_common_emul_set_read_fail_reg((COMMON_DATA), \
+ (REG)); \
+ i2c_common_emul_set_write_fail_reg( \
+ (COMMON_DATA), I2C_COMMON_EMUL_NO_FAIL_REG); \
+ } else if ((RW) == I2C_WRITE) { \
+ i2c_common_emul_set_read_fail_reg( \
+ (COMMON_DATA), I2C_COMMON_EMUL_NO_FAIL_REG); \
+ i2c_common_emul_set_write_fail_reg((COMMON_DATA), \
+ (REG)); \
+ } else { \
+ zassert_true(false, "Invalid I2C operation"); \
+ } \
+ zassert_equal( \
+ EC_ERROR_INVAL, sn5s330_drv.init(SN5S330_PORT), \
+ "Did not get EC_ERROR_INVAL when reg %s (0x%02x)" \
+ "could not be %s", \
+ #REG, (REG), ((RW) == I2C_READ) ? "read" : "written"); \
+ } while (0)
+
+ZTEST(ppc_sn5s330, test_init_reg_fails)
+{
+ /* Fail on each of the I2C operations the init function does to ensure
+ * we get the correct return value. This includes operations made by
+ * clr_flags() and set_flags().
+ */
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET5);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_FUNC_SET6);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET6);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET2);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET9);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET11);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_FUNC_SET8);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET8);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_FUNC_SET4);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET4);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_FUNC_SET3);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET3);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_FUNC_SET10);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_FUNC_SET10);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE, SN5S330_INT_STATUS_REG4);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_RISE_REG1);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_FALL_REG1);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_RISE_REG2);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_FALL_REG2);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_RISE_REG3);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_MASK_FALL_REG3);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_READ, SN5S330_INT_STATUS_REG4);
+
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_RISE_REG1);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_RISE_REG2);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_RISE_REG3);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_FALL_REG1);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_FALL_REG2);
+ INIT_I2C_FAIL_HELPER(COMMON_DATA, I2C_WRITE,
+ SN5S330_INT_TRIP_FALL_REG3);
+}
+
+static int pp_fet_test_mock_read_fn(const struct emul *emul, int reg,
+ uint8_t *val, int bytes, void *data)
+{
+ int *counter = data;
+
+ zassert_true(counter, "data cannot be a NULL pointer");
+
+ /* Pretend to be in dead battery mode (needed for part 2 of the test) */
+ if (reg == SN5S330_INT_STATUS_REG4) {
+ *val = SN5S330_DB_BOOT;
+ return 0;
+ }
+
+ /* Fail if we try to read SN5S330_FUNC_SET3 after the counter hits 0 */
+ if (reg == SN5S330_FUNC_SET3 && (*counter)-- <= 0) {
+ printf("Failing\n");
+ return -EIO;
+ }
+
+ return 1;
+}
+
+ZTEST(ppc_sn5s330, test_pp_fet_enable_fail)
+{
+ /* We attempt to enable the PP (power path) FET at two points during
+ * the init function, constituting the second and third accesses to the
+ * FUNC_SET3 register. We need to allow the first N reads/writes to
+ * succeed to test failure handling of each call to
+ * sn5s330_pp_fet_enable(). The second call requires us to be in dead
+ * battery mode, which we take care of in the mock read function.
+ */
+
+ int counter;
+ int ret;
+
+ i2c_common_emul_set_read_func(COMMON_DATA, pp_fet_test_mock_read_fn,
+ &counter);
+
+ /* Allow only the first access to the reg to succeed. This tests the
+ * error handling of the first call to sn5s330_pp_fet_enable().
+ */
+
+ counter = 1;
+ ret = sn5s330_drv.init(SN5S330_PORT);
+
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+
+ /* Allow only the first two accesses to succeed. This tests the error
+ * handling of the second call to sn5s330_pp_fet_enable().
+ */
+
+ counter = 2;
+ ret = sn5s330_drv.init(SN5S330_PORT);
+
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+}
+
+ZTEST(ppc_sn5s330, test_set_polarity)
+{
+ int ret;
+ uint8_t reg_val;
+
+ /* Ensure flags start cleared */
+ sn5s330_emul_peek_reg(EMUL, SN5S330_FUNC_SET4, &reg_val);
+ zassert_false(reg_val & SN5S330_CC_POLARITY,
+ "Polarity flags should not be set after reset.");
+
+ /* Set polarity flags */
+ ret = sn5s330_drv.set_polarity(SN5S330_PORT, 1);
+ zassert_equal(EC_SUCCESS, ret, "Expected EC_SUCCESS but got %d", ret);
+
+ sn5s330_emul_peek_reg(EMUL, SN5S330_FUNC_SET4, &reg_val);
+ zassert_true(reg_val & SN5S330_CC_POLARITY,
+ "Polarity flags should be set.");
+
+ /* Clear polarity flags */
+ ret = sn5s330_drv.set_polarity(SN5S330_PORT, 0);
+ zassert_equal(EC_SUCCESS, ret, "Expected EC_SUCCESS but got %d", ret);
+
+ sn5s330_emul_peek_reg(EMUL, SN5S330_FUNC_SET4, &reg_val);
+ zassert_false(reg_val & SN5S330_CC_POLARITY,
+ "Polarity flags should be cleared.");
+}
+
+ZTEST(ppc_sn5s330, test_set_vbus_source_current_limit_fail)
+{
+ int ret;
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET1);
+
+ ret = sn5s330_drv.set_vbus_source_current_limit(SN5S330_PORT,
+ TYPEC_RP_3A0);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_discharge_vbus_fail)
+{
+ int ret;
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET3);
+
+ ret = sn5s330_drv.discharge_vbus(SN5S330_PORT, false);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+}
+
+ZTEST(ppc_sn5s330, test_low_power_mode_fail)
+{
+ /* Test failed I2C operations in the enter low power mode function */
+
+ int ret;
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET3);
+ ret = sn5s330_drv.enter_low_power_mode(SN5S330_PORT);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET4);
+ ret = sn5s330_drv.enter_low_power_mode(SN5S330_PORT);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET2);
+ ret = sn5s330_drv.enter_low_power_mode(SN5S330_PORT);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET9);
+ ret = sn5s330_drv.enter_low_power_mode(SN5S330_PORT);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+}
+
+ZTEST(ppc_sn5s330, test_sn5s330_set_vconn_fail)
+{
+ /* Test failed I2C operations in the set Vconn function */
+
+ int ret;
+
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA, SN5S330_FUNC_SET4);
+ ret = sn5s330_drv.set_vconn(SN5S330_PORT, 0);
+ zassert_equal(EC_ERROR_INVAL, ret, "Expected EC_ERROR_INVAL but got %d",
+ ret);
+}
+
+static inline void reset_sn5s330_state(void)
+{
+ i2c_common_emul_set_write_func(COMMON_DATA, NULL, NULL);
+ i2c_common_emul_set_read_func(COMMON_DATA, NULL, NULL);
+ i2c_common_emul_set_write_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_read_fail_reg(COMMON_DATA,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ sn5s330_emul_reset(EMUL);
+ RESET_FAKE(sn5s330_emul_interrupt_set_stub);
+}
+
+static void ppc_sn5s330_before(void *state)
+{
+ ARG_UNUSED(state);
+ reset_sn5s330_state();
+}
+
+static void ppc_sn5s330_after(void *state)
+{
+ ARG_UNUSED(state);
+ reset_sn5s330_state();
+}
+
+ZTEST_SUITE(ppc_sn5s330, drivers_predicate_post_main, NULL, ppc_sn5s330_before,
+ ppc_sn5s330_after, NULL);
diff --git a/zephyr/test/drivers/default/src/ppc_syv682x.c b/zephyr/test/drivers/default/src/ppc_syv682x.c
new file mode 100644
index 0000000000..edfbd45171
--- /dev/null
+++ b/zephyr/test/drivers/default/src/ppc_syv682x.c
@@ -0,0 +1,815 @@
+/* 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/device.h>
+#include <zephyr/devicetree/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/fff.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+#include <zephyr/ztest_assert.h>
+
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_syv682x.h"
+#include "test/drivers/stubs.h"
+#include "syv682x.h"
+#include "timer.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+#include "usbc_ppc.h"
+
+#define SYV682X_NODE DT_NODELABEL(syv682x_emul)
+#define GPIO_USB_C1_FRS_EN_PATH DT_PATH(named_gpios, usb_c1_frs_en)
+
+struct ppc_syv682x_fixture {
+ const struct emul *ppc_emul;
+ struct i2c_common_emul_data *common_data;
+ const struct device *frs_en_gpio_port;
+ int frs_en_gpio_pin;
+};
+
+/* Configuration for a mock I2C access function that sometimes fails. */
+struct reg_to_fail_data {
+ int reg_access_to_fail;
+ int reg_access_fail_countdown;
+};
+
+static const int syv682x_port = 1;
+
+static void *syv682x_test_setup(void)
+{
+ static struct ppc_syv682x_fixture fixture;
+
+ fixture.ppc_emul = EMUL_DT_GET(SYV682X_NODE);
+ fixture.common_data =
+ emul_syv682x_get_i2c_common_data(fixture.ppc_emul);
+ zassume_not_null(fixture.ppc_emul, NULL);
+ fixture.frs_en_gpio_port =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_USB_C1_FRS_EN_PATH, gpios));
+ zassume_not_null(fixture.frs_en_gpio_port, NULL);
+ fixture.frs_en_gpio_pin = DT_GPIO_PIN(GPIO_USB_C1_FRS_EN_PATH, gpios);
+
+ return &fixture;
+}
+
+static void syv682x_test_after(void *data)
+{
+ struct ppc_syv682x_fixture *fixture = data;
+ const struct emul *emul = fixture->ppc_emul;
+ struct i2c_common_emul_data *common_data = fixture->common_data;
+
+ /* Disable the power path and clear interrupt conditions. */
+ zassume_ok(syv682x_emul_set_reg(emul, SYV682X_CONTROL_1_REG,
+ SYV682X_CONTROL_1_PWR_ENB),
+ NULL);
+ syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_NONE);
+
+ /* Clear the mock read/write functions */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+ i2c_common_emul_set_write_func(common_data, NULL, NULL);
+
+ /* Don't fail on any register access */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_SUITE(ppc_syv682x, drivers_predicate_post_main, syv682x_test_setup, NULL,
+ syv682x_test_after, NULL);
+
+ZTEST_F(ppc_syv682x, test_syv682x_board_is_syv682c)
+{
+ /*
+ * The SYV682x driver should assume a version-C part in the absence of a
+ * board override.
+ */
+ zassert_true(syv682x_board_is_syv682c(syv682x_port), NULL);
+}
+
+static void check_control_1_default_init(uint8_t control_1)
+{
+ /*
+ * During init, when not in dead battery mode, the driver should
+ * configure the high-voltage channel as sink but leave the power path
+ * disabled. The driver should set the current limits according to
+ * configuration.
+ */
+ int ilim;
+
+ zassert_true(control_1 & SYV682X_CONTROL_1_PWR_ENB,
+ "Default init, but power path enabled");
+ ilim = (control_1 & SYV682X_HV_ILIM_MASK) >> SYV682X_HV_ILIM_BIT_SHIFT;
+ zassert_equal(ilim, CONFIG_PLATFORM_EC_USBC_PPC_SYV682X_HV_ILIM,
+ "Default init, but HV current limit set to %d", ilim);
+ zassert_false(control_1 & SYV682X_CONTROL_1_HV_DR,
+ "Default init, but source mode selected");
+ zassert_true(control_1 & SYV682X_CONTROL_1_CH_SEL,
+ "Default init, but 5V power path selected");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_init_dead_battery)
+{
+ uint8_t reg;
+
+ /*
+ * With a dead battery, the device powers up sinking VBUS, and the
+ * driver should keep that going.
+ */
+ zassume_ok(syv682x_emul_set_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG,
+ SYV682X_CONTROL_1_CH_SEL),
+ NULL);
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_VSAFE_5V,
+ SYV682X_CONTROL_4_NONE);
+ zassert_ok(ppc_init(syv682x_port), "PPC init failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+ zassert_true(reg & SYV682X_CONTROL_1_CH_SEL,
+ "Dead battery init, but CH_SEL set to 5V power path");
+ zassert_false(reg & (SYV682X_CONTROL_1_PWR_ENB |
+ SYV682X_CONTROL_1_HV_DR),
+ "Dead battery init, but CONTROL_1 is 0x%x", reg);
+ zassert_false(ppc_is_sourcing_vbus(syv682x_port),
+ "Dead battery init, but VBUS source enabled");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_init_vsafe0v)
+{
+ uint8_t reg;
+
+ /* With VBUS at vSafe0V, init should set the default configuration. */
+ zassume_ok(syv682x_emul_set_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG,
+ SYV682X_CONTROL_1_PWR_ENB),
+ NULL);
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_VSAFE_0V,
+ SYV682X_CONTROL_4_NONE);
+ zassert_ok(ppc_init(syv682x_port), "PPC init failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+ check_control_1_default_init(reg);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_init_sink_disabled)
+{
+ uint8_t reg;
+
+ /* With sink disabled, init should do the same thing. */
+ zassume_ok(syv682x_emul_set_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG,
+ SYV682X_CONTROL_1_CH_SEL),
+ NULL);
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_VSAFE_0V,
+ SYV682X_CONTROL_4_NONE);
+ zassert_ok(ppc_init(syv682x_port), "PPC init failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+ check_control_1_default_init(reg);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_init_common)
+{
+ uint8_t reg;
+ int ilim;
+
+ zassert_ok(ppc_init(syv682x_port), "PPC init failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+
+ /*
+ * Any init sequence should also disable the FRS GPIO, set the 5V
+ * current limit according to configuration, set over-current, over-
+ * voltage, and discharge parameters appropriately, and enable CC lines.
+ */
+ zassert_equal(gpio_emul_output_get(fixture->frs_en_gpio_port,
+ fixture->frs_en_gpio_pin),
+ 0, "FRS enabled, but FRS GPIO not asserted");
+ ilim = (reg & SYV682X_5V_ILIM_MASK) >> SYV682X_5V_ILIM_BIT_SHIFT;
+ zassert_equal(ilim, CONFIG_PLATFORM_EC_USB_PD_PULLUP,
+ "Default init, but 5V current limit set to %d", ilim);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_2_REG, &reg),
+ NULL);
+ zassert_equal(reg,
+ (SYV682X_OC_DELAY_10MS << SYV682X_OC_DELAY_SHIFT) |
+ (SYV682X_DSG_RON_200_OHM
+ << SYV682X_DSG_RON_SHIFT) |
+ (SYV682X_DSG_TIME_50MS << SYV682X_DSG_TIME_SHIFT),
+ "Default init, but CONTROL_2 is 0x%x", reg);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_3_REG, &reg),
+ NULL);
+ zassert_equal(reg,
+ (SYV682X_OVP_23_7 << SYV682X_OVP_BIT_SHIFT) |
+ SYV682X_RVS_MASK,
+ "Default init, but CONTROL_3 is 0x%x", reg);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ NULL);
+ zassert_equal(reg & ~SYV682X_CONTROL_4_INT_MASK,
+ SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS,
+ "Default init, but CONTROL_4 is 0x%x", reg);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_source_enable)
+{
+ uint8_t reg;
+
+ zassert_ok(ppc_vbus_source_enable(syv682x_port, true),
+ "VBUS enable failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB, 0,
+ "VBUS sourcing enabled but power path disabled");
+ zassert_true(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is not sourcing VBUS after VBUS enabled");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_source_disable)
+{
+ zassert_ok(ppc_vbus_source_enable(syv682x_port, false),
+ "VBUS disable failed");
+ zassert_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC sourcing VBUS after disable");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_source_oc)
+{
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, true),
+ "VBUS enable failed");
+ /* An OC event less than 100 ms should not cause VBUS to turn off. */
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_OC_5V,
+ SYV682X_CONTROL_4_NONE);
+ msleep(50);
+ zassert_true(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is not sourcing VBUS after 50 ms OC");
+ /* But one greater than 100 ms should. */
+ msleep(60);
+ zassert_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is sourcing VBUS after 100 ms OC");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_tsd)
+{
+ /*
+ * A TSD event should cause the driver to disable source and sink paths.
+ * (The device will have already physically disabled them.) The state of
+ * the sink path is not part of the driver's API.
+ */
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, true),
+ "Source enable failed");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_TSD,
+ SYV682X_CONTROL_4_NONE);
+ msleep(1);
+ zassert_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is sourcing power after TSD");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_vbus_ovp)
+{
+ /* An OVP event should cause the driver to disable the source path. */
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, true),
+ "Source enable failed");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_OVP,
+ SYV682X_CONTROL_4_NONE);
+ msleep(1);
+ zassert_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is sourcing power after OVP");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_vbus_hv_oc)
+{
+ uint8_t reg;
+
+ /*
+ * A high-voltage OC while sinking should cause the driver to try to
+ * re-enable the sink path until the OC count limit is reached, at which
+ * point the driver should leave it disabled.
+ */
+ zassume_ok(ppc_vbus_sink_enable(syv682x_port, true),
+ "Sink enable failed");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_OC_HV,
+ SYV682X_CONTROL_4_NONE);
+ msleep(1);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB, 0,
+ "Power path disabled after HV_OC handled");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_OC_HV,
+ SYV682X_CONTROL_4_NONE);
+ /* Alert GPIO doesn't change so wait for delayed syv682x interrupt */
+ msleep(15);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB, 0,
+ "Power path disabled after HV_OC handled");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_OC_HV,
+ SYV682X_CONTROL_4_NONE);
+ /* Alert GPIO doesn't change so wait for delayed syv682x interrupt */
+ msleep(15);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB,
+ SYV682X_CONTROL_1_PWR_ENB,
+ "Power path enabled after HV_OC handled 3 times");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_vconn_oc)
+{
+ uint8_t reg;
+
+ /*
+ * A VCONN OC event less than 100 ms should not cause the driver to turn
+ * VCONN off.
+ */
+ ppc_set_vconn(syv682x_port, true);
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_VCONN_OCP);
+ msleep(1);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_true(reg & (SYV682X_CONTROL_4_VCONN1 |
+ SYV682X_CONTROL_4_VCONN2),
+ "VCONN disabled after initial VCONN OC");
+ msleep(50);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_true(reg & (SYV682X_CONTROL_4_VCONN1 |
+ SYV682X_CONTROL_4_VCONN2),
+ "VCONN disabled after short VCONN OC");
+ /*
+ * But if the event keeps going for over 100 ms continuously, the driver
+ * should turn VCONN off.
+ */
+ msleep(60);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_false(reg & (SYV682X_CONTROL_4_VCONN1 |
+ SYV682X_CONTROL_4_VCONN2),
+ "VCONN enabled after long VCONN OC");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_interrupt_vconn_ov)
+{
+ uint8_t reg;
+
+ /*
+ * A VCONN over-voltage (VBAT_OVP) event will cause the device to
+ * disconnect CC and VCONN. The driver should then reinitialize the
+ * device, which will enable both CC lines but leave VCONN disabled. The
+ * driver should then run generic CC over-voltage handling.
+ */
+ ppc_set_vconn(syv682x_port, true);
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_VBAT_OVP);
+ msleep(1);
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_true(reg & SYV682X_CONTROL_4_CC1_BPS,
+ "CC1 disabled after handling VBAT_OVP");
+ zassert_true(reg & SYV682X_CONTROL_4_CC2_BPS,
+ "CC2 disabled after handling VBAT_OVP");
+ zassert_false(reg & (SYV682X_CONTROL_4_VCONN1 |
+ SYV682X_CONTROL_4_VCONN2),
+ "VCONN enabled after handling VBAT_OVP");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_frs_enable)
+{
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_USB_C1_FRS_EN_PATH, gpios));
+ uint8_t reg;
+
+ /*
+ * Enabling FRS should enable only the appropriate CC line based on
+ * polarity. Disabling FRS should enable both CC lines.
+ */
+ ppc_vbus_sink_enable(syv682x_port, true);
+ zassume_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is sourcing VBUS after sink enabled");
+ ppc_set_polarity(syv682x_port, 0 /* CC1 */);
+ ppc_set_frs_enable(syv682x_port, true);
+ zassert_equal(gpio_emul_output_get(gpio_dev, fixture->frs_en_gpio_pin),
+ 1, "FRS enabled, but FRS GPIO not asserted");
+ zassert_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_equal(
+ reg & (SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS),
+ SYV682X_CONTROL_4_CC1_BPS,
+ "FRS enabled with CC1 polarity, but CONTROL_4 is 0x%x", reg);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_frs_disable)
+{
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_USB_C1_FRS_EN_PATH, gpios));
+ uint8_t reg;
+
+ ppc_vbus_sink_enable(syv682x_port, true);
+ zassume_false(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is sourcing VBUS after sink enabled");
+ ppc_set_polarity(syv682x_port, 0 /* CC1 */);
+
+ ppc_set_frs_enable(syv682x_port, false);
+ zassert_equal(gpio_emul_output_get(gpio_dev, fixture->frs_en_gpio_pin),
+ 0, "FRS disabled, but FRS GPIO not deasserted");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_4_REG, &reg),
+ "Reading CONTROL_4 failed");
+ zassert_equal(
+ reg & (SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS),
+ SYV682X_CONTROL_4_CC1_BPS | SYV682X_CONTROL_4_CC2_BPS,
+ "FRS disabled with CC1 polarity, but CONTROL_4 is 0x%x", reg);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_frs_trigger)
+{
+ /*
+ * An FRS event when the PPC is Sink should cause the PPC to switch from
+ * Sink to Source.
+ */
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_FRS,
+ SYV682X_CONTROL_4_NONE);
+ msleep(1);
+ zassert_true(ppc_is_sourcing_vbus(syv682x_port),
+ "PPC is not sourcing VBUS after FRS signal handled");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_NONE);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_source_current_limit_usb_default)
+{
+ uint8_t reg;
+ int ilim_val;
+
+ zassert_ok(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_USB),
+ "Could not set source current limit");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ ilim_val = (reg & SYV682X_5V_ILIM_MASK) >> SYV682X_5V_ILIM_BIT_SHIFT;
+ zassert_equal(reg & SYV682X_5V_ILIM_MASK, SYV682X_5V_ILIM_1_25,
+ "Set USB Rp value, but 5V_ILIM is %d", ilim_val);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_source_current_limit_1500ma)
+{
+ uint8_t reg;
+ int ilim_val;
+
+ zassert_ok(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_1A5),
+ "Could not set source current limit");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ ilim_val = (reg & SYV682X_5V_ILIM_MASK) >> SYV682X_5V_ILIM_BIT_SHIFT;
+ zassert_equal(ilim_val, SYV682X_5V_ILIM_1_75,
+ "Set 1.5A Rp value, but 5V_ILIM is %d", ilim_val);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_source_current_limit_3000ma)
+{
+ uint8_t reg;
+ int ilim_val;
+
+ zassert_ok(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_3A0),
+ "Could not set source current limit");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ "Reading CONTROL_1 failed");
+ ilim_val = (reg & SYV682X_5V_ILIM_MASK) >> SYV682X_5V_ILIM_BIT_SHIFT;
+ zassert_equal(ilim_val, SYV682X_5V_ILIM_3_30,
+ "Set 3.0A Rp value, but 5V_ILIM is %d", ilim_val);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_write_busy)
+{
+ /*
+ * Writes should fail while the BUSY bit is set, except that writes to
+ * CONTROL_4 should succeed on the SYV682C. 1000 reads is intentionally
+ * many more than the driver is expected to make before reaching its
+ * timeout. It is not a goal of this test to verify the frequency of
+ * polling or the exact value of the timeout.
+ */
+ syv682x_emul_set_busy_reads(fixture->ppc_emul, 1000);
+ zassert_equal(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_USB),
+ EC_ERROR_TIMEOUT, "SYV682 busy, but write completed");
+ zassert_ok(ppc_set_frs_enable(syv682x_port, false),
+ "Could not set CONTROL_4 while busy on SYV682C");
+
+ /*
+ * If the busy bit clears before the driver reaches its timeout, the
+ * write should succeed.
+ */
+ syv682x_emul_set_busy_reads(fixture->ppc_emul, 1);
+ zassert_equal(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_USB),
+ 0, "SYV682 not busy, but write failed");
+
+ syv682x_emul_set_busy_reads(fixture->ppc_emul, 0);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_dev_is_connected)
+{
+ uint8_t reg;
+
+ zassert_ok(ppc_dev_is_connected(syv682x_port, PPC_DEV_SRC),
+ "Could not connect device as source");
+ zassert_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_2_REG, &reg),
+ "Reading CONTROL_2 failed");
+ zassert_false(reg & SYV682X_CONTROL_2_FDSG,
+ "Connected as source, but force discharge enabled");
+
+ zassert_ok(ppc_dev_is_connected(syv682x_port, PPC_DEV_DISCONNECTED),
+ "Could not disconnect device");
+ zassert_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_2_REG, &reg),
+ "Reading CONTROL_2 failed");
+ zassert_true(reg & SYV682X_CONTROL_2_FDSG,
+ "Disconnected, but force discharge disabled");
+
+ zassert_ok(ppc_dev_is_connected(syv682x_port, PPC_DEV_SNK),
+ "Could not connect device as source");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_sink_enable_trivial)
+{
+ /*
+ * If VBUS source is already enabled, disabling VBUS sink should
+ * trivially succeed.
+ */
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, true),
+ "VBUS enable failed");
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, false),
+ "Sink disable failed");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_sink_enable_power_path)
+{
+ uint8_t reg;
+ int ilim;
+
+ /*
+ * After enabling VBUS sink, the HV power path should be enabled in sink
+ * mode with the configured current limit.
+ */
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, false),
+ "VBUS enable failed");
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, true),
+ "Sink disable failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+ zassert_true(reg & SYV682X_CONTROL_1_CH_SEL,
+ "Sink enabled, but CH_SEL set to 5V power path");
+ zassert_false(reg & SYV682X_CONTROL_1_PWR_ENB,
+ "Sink enabled, but power path disabled");
+ zassert_false(reg & SYV682X_CONTROL_1_HV_DR,
+ "Sink enabled, but high-voltage path in source mode");
+ ilim = (reg & SYV682X_HV_ILIM_MASK) >> SYV682X_HV_ILIM_BIT_SHIFT;
+ zassert_equal(ilim, CONFIG_PLATFORM_EC_USBC_PPC_SYV682X_HV_ILIM,
+ "Sink enabled, but HV current limit set to %d", ilim);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_sink_disable)
+{
+ uint8_t reg;
+
+ zassume_ok(ppc_vbus_source_enable(syv682x_port, false),
+ "VBUS enable failed");
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, true),
+ "Sink disable failed");
+
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, false),
+ "Sink disable failed");
+ zassume_ok(syv682x_emul_get_reg(fixture->ppc_emul,
+ SYV682X_CONTROL_1_REG, &reg),
+ NULL);
+ zassert_true(reg & SYV682X_CONTROL_1_PWR_ENB,
+ "Sink disabled, but power path enabled");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_vbus_sink_oc_limit)
+{
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, true),
+ "Sink enable failed");
+
+ /* Generate 4 consecutive sink over-current interrupts. After reaching
+ * this count, the driver should prevent sink enable until the count is
+ * cleared by sink disable.
+ */
+ for (int i = 0; i < 4; ++i) {
+ syv682x_emul_set_condition(fixture->ppc_emul,
+ SYV682X_STATUS_OC_HV,
+ SYV682X_CONTROL_4_NONE);
+ msleep(15);
+ }
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_NONE);
+
+ zassert_not_equal(ppc_vbus_sink_enable(syv682x_port, true), EC_SUCCESS,
+ "VBUS sink enable succeeded after 4 OC events");
+
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, false),
+ "Sink disable failed");
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, true),
+ "Sink enable failed");
+ zassert_ok(ppc_vbus_sink_enable(syv682x_port, false),
+ "Sink disable failed");
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_set_vconn)
+{
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_VBAT_OVP);
+ zassert_not_equal(ppc_set_vconn(syv682x_port, true), EC_SUCCESS,
+ "VBAT OVP, but ppc_set_vconn succeeded");
+}
+
+ZTEST(ppc_syv682x, test_syv682x_ppc_dump)
+{
+ /*
+ * The ppc_dump command should succeed for this port. Don't check the
+ * output, since there are no standard requirements for that.
+ */
+ const struct ppc_drv *drv = ppc_chips[syv682x_port].drv;
+
+ zassert_ok(drv->reg_dump(syv682x_port), "ppc_dump command failed");
+}
+
+/* Intercepts I2C reads as a mock. Fails to read for the register at offset
+ * reg_access_to_fail on read number N, where N is the initial value of
+ * reg_access_fail_countdown.
+ */
+static int mock_read_intercept_reg_fail(const struct emul *emul, int reg,
+ uint8_t *val, int bytes, void *data)
+{
+ struct reg_to_fail_data *test_data = data;
+
+ if (reg == test_data->reg_access_to_fail) {
+ test_data->reg_access_fail_countdown--;
+ if (test_data->reg_access_fail_countdown <= 0)
+ return -1;
+ }
+ return 1;
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_i2c_error_status)
+{
+ /* Failed STATUS read should cause init to fail. */
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ SYV682X_STATUS_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "STATUS read error, but init succeeded");
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_i2c_error_control_1)
+{
+ const struct ppc_drv *drv = ppc_chips[syv682x_port].drv;
+ struct reg_to_fail_data reg_fail = {
+ .reg_access_to_fail = 0,
+ .reg_access_fail_countdown = 0,
+ };
+
+ /* Failed CONTROL_1 read */
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_1_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_1 read error, but init succeeded");
+ zassert_not_equal(ppc_vbus_source_enable(syv682x_port, true),
+ EC_SUCCESS,
+ "CONTROL_1 read error, but VBUS source enable "
+ "succeeded");
+ zassert_not_equal(ppc_vbus_sink_enable(syv682x_port, true), EC_SUCCESS,
+ "CONTROL_1 read error, but VBUS sink enable "
+ "succeeded");
+ zassert_not_equal(ppc_set_vbus_source_current_limit(syv682x_port,
+ TYPEC_RP_USB),
+ EC_SUCCESS,
+ "CONTROL_1 read error, but set current limit "
+ "succeeded");
+ zassert_ok(drv->reg_dump(syv682x_port),
+ "CONTROL_1 read error, and ppc_dump failed");
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Init reads CONTROL_1 several times. The 3rd read happens while
+ * setting the source current limit. Check that init fails when that
+ * read fails.
+ */
+ i2c_common_emul_set_read_func(fixture->common_data,
+ &mock_read_intercept_reg_fail, &reg_fail);
+ reg_fail.reg_access_to_fail = SYV682X_CONTROL_1_REG;
+ reg_fail.reg_access_fail_countdown = 3;
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_1 read error, but init succeeded");
+ i2c_common_emul_set_read_func(fixture->common_data, NULL, NULL);
+
+ /* Failed CONTROL_1 write */
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_1_REG);
+
+ /* During init, the driver will write CONTROL_1 either to disable all
+ * power paths (normal case) or to enable the sink path (dead battery
+ * case). vSafe0V in STATUS is one indication of the normal case.
+ */
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_VSAFE_0V,
+ SYV682X_CONTROL_4_NONE);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_1 write error, but init succeeded");
+ syv682x_emul_set_condition(fixture->ppc_emul, SYV682X_STATUS_NONE,
+ SYV682X_CONTROL_4_NONE);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_1 write error, but init succeeded");
+
+ zassert_not_equal(ppc_vbus_source_enable(syv682x_port, true),
+ EC_SUCCESS,
+ "CONTROL_1 write error, but VBUS source "
+ "enable succeeded");
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_i2c_error_control_2)
+{
+ /* Failed CONTROL_2 read */
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_2_REG);
+ zassert_not_equal(ppc_discharge_vbus(syv682x_port, true), EC_SUCCESS,
+ "CONTROL_2 read error, but VBUS discharge succeeded");
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Failed CONTROL_2 write */
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_2_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_2 write error, but init succeeded");
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_i2c_error_control_3)
+{
+ /* Failed CONTROL_3 read */
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_3_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_3 read error, but VBUS discharge succeeded");
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Failed CONTROL_3 write */
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_3_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_3 write error, but init succeeded");
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
+
+ZTEST_F(ppc_syv682x, test_syv682x_i2c_error_control_4)
+{
+ /* Failed CONTROL_4 read */
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_4_REG);
+ zassert_not_equal(ppc_set_vconn(syv682x_port, true), EC_SUCCESS,
+ "CONTROL_2 read error, but VCONN set succeeded");
+ i2c_common_emul_set_read_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Failed CONTROL_4 write */
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ SYV682X_CONTROL_4_REG);
+ zassert_not_equal(ppc_init(syv682x_port), EC_SUCCESS,
+ "CONTROL_4 write error, but init succeeded");
+ zassert_not_equal(ppc_set_vconn(syv682x_port, true), EC_SUCCESS,
+ "CONTROL_4 write error, but VCONN set succeeded");
+ i2c_common_emul_set_write_fail_reg(fixture->common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+}
diff --git a/zephyr/test/drivers/default/src/ps8xxx.c b/zephyr/test/drivers/default/src/ps8xxx.c
new file mode 100644
index 0000000000..29d720a639
--- /dev/null
+++ b/zephyr/test/drivers/default/src/ps8xxx.c
@@ -0,0 +1,1311 @@
+/* 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 "common.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "emul/tcpc/emul_ps8xxx.h"
+#include "timer.h"
+#include "i2c.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/tcpci_test_common.h"
+
+#include "tcpm/tcpci.h"
+#include "driver/tcpm/ps8xxx.h"
+#include "driver/tcpm/ps8xxx_public.h"
+#include "test/drivers/test_state.h"
+
+#define PS8XXX_EMUL_NODE DT_NODELABEL(ps8xxx_emul)
+
+/** Test PS8xxx init fail conditions common for all PS8xxx devices */
+static void test_ps8xxx_init_fail(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ /* Test fail on FW reg read */
+ i2c_common_emul_set_read_fail_reg(common_data, PS8XXX_REG_FW_REV);
+ zassert_equal(EC_ERROR_TIMEOUT, ps8xxx_tcpm_drv.init(USBC_PORT_C1),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on FW reg set to 0 */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x0);
+ zassert_equal(EC_ERROR_TIMEOUT, ps8xxx_tcpm_drv.init(USBC_PORT_C1),
+ NULL);
+
+ /* Set arbitrary FW reg value != 0 for rest of the test */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+
+ /* Test fail on TCPCI init */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_UNINIT);
+ zassert_equal(EC_ERROR_TIMEOUT, ps8xxx_tcpm_drv.init(USBC_PORT_C1),
+ NULL);
+}
+
+ZTEST(ps8805, test_init_fail)
+{
+ test_ps8xxx_init_fail();
+}
+
+ZTEST(ps8815, test_init_fail)
+{
+ test_ps8xxx_init_fail();
+}
+
+/**
+ * Test PS8805 init and indirectly ps8705_dci_disable which is
+ * used by PS8805
+ */
+ZTEST(ps8805, test_ps8805_init)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+ struct i2c_common_emul_data *p1_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_1);
+
+ /* Set arbitrary FW reg value != 0 for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+ /* Set correct power status for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_POWER_STATUS, 0x0);
+
+ /* Test fail on read I2C debug reg */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ PS8XXX_REG_I2C_DEBUGGING_ENABLE);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on read DCI reg */
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ PS8XXX_P1_REG_MUX_USB_DCI_CFG);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test successful init */
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ check_tcpci_reg(ps8xxx_emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE,
+ PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON);
+ zassert_equal(PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF,
+ ps8xxx_emul_get_dci_cfg(ps8xxx_emul) &
+ PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK,
+ NULL);
+}
+
+/** Test PS8815 init */
+ZTEST(ps8815, test_ps8815_init)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *p1_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_1);
+
+ /* Set arbitrary FW reg value != 0 for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+ /* Set correct power status for rest of the test */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_POWER_STATUS, 0x0);
+
+ /* Test fail on reading HW revision register */
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ PS8815_P1_REG_HW_REVISION);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test successful init */
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+}
+
+/** Test PS8xxx release */
+static void test_ps8xxx_release(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ uint64_t start_ms;
+
+ /* Test successful release with correct FW reg read */
+ start_ms = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.release(USBC_PORT_C1), NULL);
+ zassert_true(k_uptime_get() - start_ms < 10,
+ "release on correct FW reg read shouldn't wait for chip");
+
+ /* Test delay on FW reg read fail */
+ i2c_common_emul_set_read_fail_reg(common_data, PS8XXX_REG_FW_REV);
+ start_ms = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.release(USBC_PORT_C1), NULL);
+ zassert_true(k_uptime_get() - start_ms >= 10,
+ "release on FW reg read fail should wait for chip");
+}
+
+ZTEST(ps8805, test_release)
+{
+ test_ps8xxx_release();
+}
+
+ZTEST(ps8815, test_release)
+{
+ test_ps8xxx_release();
+}
+
+/**
+ * Check if PS8815 set_cc write correct value to ROLE_CTRL register and if
+ * PS8815 specific workaround is applied to RP_DETECT_CONTROL.
+ */
+static void check_ps8815_set_cc(enum tcpc_rp_value rp, enum tcpc_cc_pull cc,
+ uint16_t rp_detect_ctrl, const char *test_case)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ uint16_t reg_val, exp_role_ctrl;
+
+ /* Clear RP detect register to see if it is set after test */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_RP_DETECT_CONTROL, 0);
+
+ exp_role_ctrl = TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, rp, cc, cc);
+
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.select_rp_value(USBC_PORT_C1, rp),
+ "Failed to set RP for case: %s", test_case);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.set_cc(USBC_PORT_C1, cc),
+ "Failed to set CC for case: %s", test_case);
+
+ zassert_ok(tcpci_emul_get_reg(ps8xxx_emul, TCPC_REG_ROLE_CTRL,
+ &reg_val),
+ "Failed tcpci_emul_get_reg() for case: %s", test_case);
+ zassert_equal(exp_role_ctrl, reg_val,
+ "0x%x != (role_ctrl = 0x%x) for case: %s", exp_role_ctrl,
+ reg_val, test_case);
+ zassert_ok(tcpci_emul_get_reg(ps8xxx_emul, PS8XXX_REG_RP_DETECT_CONTROL,
+ &reg_val),
+ "Failed tcpci_emul_get_reg() for case: %s", test_case);
+ zassert_equal(rp_detect_ctrl, reg_val,
+ "0x%x != (rp detect = 0x%x) for case: %s", rp_detect_ctrl,
+ reg_val, test_case);
+}
+
+/** Test PS8815 set cc and device specific workarounds */
+ZTEST(ps8815, test_ps8815_set_cc)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ int64_t start_time;
+ int64_t delay;
+
+ /*
+ * Set other hw revision to disable workaround for b/171430855 (delay
+ * 1 ms on role control reg update). Delay could introduce thread switch
+ * which may disturb this test.
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a02);
+
+ /* Set firmware version <= 0x10 to set "disable rp detect" workaround */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x8);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, RP_DETECT_DISABLE,
+ "fw rev 0x8 \"disable rp detect\" workaround");
+
+ /* First call to set_cc should disarm workaround */
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, 0,
+ "second call without workaround");
+
+ /* drp_toggle should rearm "disable rp detect" workaround */
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, RP_DETECT_DISABLE,
+ "drp_toggle rearm workaround");
+
+ /*
+ * Set firmware version <= 0x10 to set "disable rp detect" workaround
+ * again
+ */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0xa);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ /* CC RD shouldn't trigger "disable rp detect" workaround */
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RD, 0,
+ "CC RD not trigger workaround");
+
+ /*
+ * Set firmware version > 0x10 to unset "disable rp detect"
+ * workaround
+ */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x12);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ /* Firmware > 0x10 shouldn't trigger "disable rp detect" workaround */
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, 0,
+ "fw rev > 0x10 not trigger workaround");
+
+ /*
+ * Set hw revision 0x0a00 to enable workaround for b/171430855 (delay
+ * 1 ms on role control reg update)
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a00);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ start_time = k_uptime_get();
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, 0,
+ "delay on HW rev 0x0a00");
+ delay = k_uptime_delta(&start_time);
+ zassert_true(delay >= 1, "expected delay on HW rev 0x0a00 (delay %lld)",
+ delay);
+
+ /*
+ * Set hw revision 0x0a01 to enable workaround for b/171430855 (delay
+ * 1 ms on role control reg update)
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a01);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ start_time = k_uptime_get();
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, 0,
+ "delay on HW rev 0x0a01");
+ delay = k_uptime_delta(&start_time);
+ zassert_true(delay >= 1, "expected delay on HW rev 0x0a01 (delay %lld)",
+ delay);
+
+ /*
+ * Set other hw revision to disable workaround for b/171430855 (delay
+ * 1 ms on role control reg update)
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a02);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ start_time = k_uptime_get();
+ check_ps8815_set_cc(TYPEC_RP_1A5, TYPEC_CC_RP, 0,
+ "no delay on other HW rev");
+ delay = k_uptime_delta(&start_time);
+ zassert_true(delay == 0,
+ "unexpected delay on HW rev 0x0a02 (delay %lld)", delay);
+}
+
+/** Test PS8xxx set vconn */
+static void test_ps8xxx_set_vconn(void)
+{
+ uint64_t start_ms;
+
+ /* Test vconn enable */
+ start_ms = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.set_vconn(USBC_PORT_C1, 1),
+ NULL);
+ zassert_true(k_uptime_get() - start_ms < 10,
+ "VCONN enable should be without delay");
+
+ /* Test vconn disable */
+ start_ms = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.set_vconn(USBC_PORT_C1, 0),
+ NULL);
+ /* Delay for VCONN disable is required because of issue b/185202064 */
+ zassert_true(k_uptime_get() - start_ms >= 10,
+ "VCONN disable require minimum 10ms delay");
+}
+
+ZTEST(ps8805, test_set_vconn)
+{
+ test_ps8xxx_set_vconn();
+}
+
+ZTEST(ps8815, test_set_vconn)
+{
+ test_ps8xxx_set_vconn();
+}
+
+/** Test PS8xxx transmitting message from TCPC */
+static void test_ps8xxx_transmit(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ struct tcpci_emul_msg *msg;
+ uint64_t exp_cnt, cnt;
+ uint16_t reg_val;
+
+ msg = tcpci_emul_get_tx_msg(ps8xxx_emul);
+
+ /* Test fail on transmitting BIST MODE 2 message */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TRANSMIT);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8xxx_tcpm_drv.transmit(
+ USBC_PORT_C1, TCPCI_MSG_TX_BIST_MODE_2, 0, NULL),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test sending BIST MODE 2 message */
+ exp_cnt = PS8751_BIST_COUNTER;
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.transmit(
+ USBC_PORT_C1, TCPCI_MSG_TX_BIST_MODE_2, 0, NULL),
+ NULL);
+ check_tcpci_reg(ps8xxx_emul, PS8XXX_REG_BIST_CONT_MODE_CTR, 0);
+ zassert_equal(TCPCI_MSG_TX_BIST_MODE_2, msg->sop_type, NULL);
+
+ /* Check BIST counter value */
+ zassert_ok(tcpci_emul_get_reg(ps8xxx_emul,
+ PS8XXX_REG_BIST_CONT_MODE_BYTE2,
+ &reg_val),
+ NULL);
+ cnt = reg_val;
+ cnt <<= 8;
+ zassert_ok(tcpci_emul_get_reg(ps8xxx_emul,
+ PS8XXX_REG_BIST_CONT_MODE_BYTE1,
+ &reg_val),
+ NULL);
+ cnt |= reg_val;
+ cnt <<= 8;
+ zassert_ok(tcpci_emul_get_reg(ps8xxx_emul,
+ PS8XXX_REG_BIST_CONT_MODE_BYTE0,
+ &reg_val),
+ NULL);
+ cnt |= reg_val;
+ zassert_equal(exp_cnt, cnt, "0x%llx != 0x%llx", exp_cnt, cnt);
+}
+
+ZTEST(ps8805, test_transmit)
+{
+ test_ps8xxx_transmit();
+}
+
+ZTEST(ps8815, test_transmit)
+{
+ test_ps8xxx_transmit();
+}
+
+/** Test PS8805 and PS8815 drp toggle */
+static void test_ps88x5_drp_toggle(bool delay_expected)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ uint16_t exp_role_ctrl;
+ int64_t start_time;
+ int64_t delay;
+
+ /* Test fail on command write */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_COMMAND);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+
+ /* Test fail on role control write */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ROLE_CTRL);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on CC status read */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_CC_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set CC status as snk, CC lines set arbitrary */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_CC_STATUS,
+ TCPC_REG_CC_STATUS_SET(1, TYPEC_CC_VOLT_OPEN,
+ TYPEC_CC_VOLT_RA));
+
+ /*
+ * TODO(b/203858808): PS8815 sleep here if specific FW rev.
+ * Find way to test 1 ms delay
+ */
+ /* Test drp toggle when CC is snk. Role control CC lines should be RP */
+ exp_role_ctrl = TCPC_REG_ROLE_CTRL_SET(TYPEC_DRP, TYPEC_RP_USB,
+ TYPEC_CC_RP, TYPEC_CC_RP);
+ start_time = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+ delay = k_uptime_delta(&start_time);
+ if (delay_expected) {
+ zassert_true(delay >= 1, "expected delay (%lld ms)", delay);
+ } else {
+ zassert_true(delay == 0, "unexpected delay (%lld ms)", delay);
+ }
+ check_tcpci_reg(ps8xxx_emul, TCPC_REG_ROLE_CTRL, exp_role_ctrl);
+ check_tcpci_reg(ps8xxx_emul, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_LOOK4CONNECTION);
+
+ /* Set CC status as src, CC lines set arbitrary */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_CC_STATUS,
+ TCPC_REG_CC_STATUS_SET(0, TYPEC_CC_VOLT_OPEN,
+ TYPEC_CC_VOLT_RA));
+
+ /* Test drp toggle when CC is src. Role control CC lines should be RD */
+ exp_role_ctrl = TCPC_REG_ROLE_CTRL_SET(TYPEC_DRP, TYPEC_RP_USB,
+ TYPEC_CC_RD, TYPEC_CC_RD);
+ start_time = k_uptime_get();
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.drp_toggle(USBC_PORT_C1),
+ NULL);
+ delay = k_uptime_delta(&start_time);
+ if (delay_expected) {
+ zassert_true(delay >= 1, "expected delay (%lld ms)", delay);
+ } else {
+ zassert_true(delay == 0, "unexpected delay (%lld ms)", delay);
+ }
+ check_tcpci_reg(ps8xxx_emul, TCPC_REG_ROLE_CTRL, exp_role_ctrl);
+ check_tcpci_reg(ps8xxx_emul, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_LOOK4CONNECTION);
+}
+
+/** Test PS8815 drp toggle */
+ZTEST(ps8815, test_ps8815_drp_toggle)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+
+ /*
+ * Set hw revision 0x0a00 to enable workaround for b/171430855 (delay
+ * 1 ms on role control reg update)
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a00);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ test_ps88x5_drp_toggle(true);
+
+ /*
+ * Set other hw revision to disable workaround for b/171430855 (delay
+ * 1 ms on role control reg update)
+ */
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, 0x0a02);
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+ test_ps88x5_drp_toggle(false);
+}
+
+/** Test PS8805 drp toggle */
+ZTEST(ps8805, test_drp_toggle)
+{
+ test_ps88x5_drp_toggle(false);
+}
+
+/** Test PS8xxx get chip info code used by all PS8xxx devices */
+static void test_ps8xxx_get_chip_info(uint16_t current_product_id)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ struct ec_response_pd_chip_info_v1 info;
+ uint16_t vendor, product, device_id, fw_rev;
+
+ /* Setup chip info */
+ vendor = PS8XXX_VENDOR_ID;
+ /* Get currently used product ID */
+ product = current_product_id;
+ /* Arbitrary choose device ID that doesn't require fixing */
+ device_id = 0x2;
+ /* Arbitrary revision */
+ fw_rev = 0x32;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_PRODUCT_ID, product);
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_BCD_DEV, device_id);
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, fw_rev);
+
+ /* Test fail on reading FW revision */
+ i2c_common_emul_set_read_fail_reg(common_data, PS8XXX_REG_FW_REV);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test reading chip info */
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+ zassert_equal(vendor, info.vendor_id, NULL);
+ zassert_equal(product, info.product_id, NULL);
+ zassert_equal(device_id, info.device_id, NULL);
+ zassert_equal(fw_rev, info.fw_version_number, NULL);
+
+ /* Test fail on wrong vendor id */
+ vendor = 0x0;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /* Set correct vendor id */
+ vendor = PS8XXX_VENDOR_ID;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+
+ /* Set firmware revision to 0 */
+ fw_rev = 0x0;
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, fw_rev);
+
+ /*
+ * Test fail on firmware revision equals to 0 when getting chip info
+ * from live device
+ */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /*
+ * Test if firmware revision 0 is accepted when getting chip info from
+ * not live device
+ */
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 0, &info),
+ NULL);
+ zassert_equal(vendor, info.vendor_id, NULL);
+ zassert_equal(product, info.product_id, NULL);
+ zassert_equal(device_id, info.device_id, NULL);
+ zassert_equal(fw_rev, info.fw_version_number, NULL);
+
+ /* Set wrong vendor id */
+ vendor = 0;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+
+ /* Test fail on vendor id mismatch on live device */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /* Test that vendor id is fixed on not live device */
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 0, &info),
+ NULL);
+ zassert_equal(PS8XXX_VENDOR_ID, info.vendor_id, NULL);
+ zassert_equal(product, info.product_id, NULL);
+ zassert_equal(device_id, info.device_id, NULL);
+ zassert_equal(fw_rev, info.fw_version_number, NULL);
+
+ /* Set correct vendor id */
+ vendor = PS8XXX_VENDOR_ID;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+
+ /* Set wrong product id */
+ product = 0;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_PRODUCT_ID, product);
+
+ /* Test fail on product id mismatch on live device */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /* Test that product id is fixed on not live device */
+ zassert_equal(EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 0, &info),
+ NULL);
+ zassert_equal(vendor, info.vendor_id, NULL);
+ zassert_equal(board_get_ps8xxx_product_id(USBC_PORT_C1),
+ info.product_id, NULL);
+ zassert_equal(device_id, info.device_id, NULL);
+ zassert_equal(fw_rev, info.fw_version_number, NULL);
+
+ zassert_equal(false, check_ps8755_chip(USBC_PORT_C1), NULL);
+}
+
+ZTEST(ps8805, test_ps8805_get_chip_info)
+{
+ test_ps8xxx_get_chip_info(PS8805_PRODUCT_ID);
+}
+
+ZTEST(ps8815, test_ps8815_get_chip_info)
+{
+ test_ps8xxx_get_chip_info(PS8815_PRODUCT_ID);
+}
+
+/** Test PS8805 get chip info and indirectly ps8805_make_device_id */
+ZTEST(ps8805, test_ps8805_get_chip_info_fix_dev_id)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *p0_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_0);
+ struct ec_response_pd_chip_info_v1 info;
+ uint16_t vendor, product, device_id, fw_rev;
+ uint16_t chip_rev;
+
+ struct {
+ uint16_t exp_dev_id;
+ uint16_t chip_rev;
+ } test_param[] = {
+ /* Test A3 chip revision */
+ {
+ .exp_dev_id = 0x2,
+ .chip_rev = 0xa0,
+ },
+ /* Test A2 chip revision */
+ {
+ .exp_dev_id = 0x1,
+ .chip_rev = 0x0,
+ },
+ };
+
+ /* Setup chip info */
+ vendor = PS8XXX_VENDOR_ID;
+ product = PS8805_PRODUCT_ID;
+ /* Arbitrary revision */
+ fw_rev = 0x32;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_PRODUCT_ID, product);
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, fw_rev);
+
+ /* Set correct power status for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_POWER_STATUS, 0x0);
+ /* Init to allow access to "hidden" I2C ports */
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ /* Set device id which requires fixing */
+ device_id = 0x1;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_BCD_DEV, device_id);
+
+ /* Test error on fixing device id because of fail chip revision read */
+ i2c_common_emul_set_read_fail_reg(p0_i2c_common_data,
+ PS8805_P0_REG_CHIP_REVISION);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(p0_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set wrong chip revision */
+ chip_rev = 0x32;
+ ps8xxx_emul_set_chip_rev(ps8xxx_emul, chip_rev);
+
+ /* Test error on fixing device id */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /* Test fixing device id for specific chip revisions */
+ for (int i = 0; i < ARRAY_SIZE(test_param); i++) {
+ ps8xxx_emul_set_chip_rev(ps8xxx_emul, test_param[i].chip_rev);
+
+ /* Test correct device id after fixing */
+ zassert_equal(
+ EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ "Failed to get chip info in test case %d (chip_rev 0x%x)",
+ i, test_param[i].chip_rev);
+ zassert_equal(
+ vendor, info.vendor_id,
+ "0x%x != (vendor = 0x%x) in test case %d (chip_rev 0x%x)",
+ vendor, info.vendor_id, i, test_param[i].chip_rev);
+ zassert_equal(
+ product, info.product_id,
+ "0x%x != (product = 0x%x) in test case %d (chip_rev 0x%x)",
+ product, info.product_id, i, test_param[i].chip_rev);
+ zassert_equal(
+ test_param[i].exp_dev_id, info.device_id,
+ "0x%x != (device = 0x%x) in test case %d (chip_rev 0x%x)",
+ test_param[i].exp_dev_id, info.device_id, i,
+ test_param[i].chip_rev);
+ zassert_equal(
+ fw_rev, info.fw_version_number,
+ "0x%x != (FW rev = 0x%x) in test case %d (chip_rev 0x%x)",
+ fw_rev, info.fw_version_number, i,
+ test_param[i].chip_rev);
+ }
+}
+
+/** Test PS8815 get chip info and indirectly ps8815_make_device_id */
+ZTEST(ps8815, test_ps8815_get_chip_info_fix_dev_id)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *p1_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_1);
+ struct ec_response_pd_chip_info_v1 info;
+ uint16_t vendor, product, device_id, fw_rev;
+ uint16_t hw_rev;
+
+ struct {
+ uint16_t exp_dev_id;
+ uint16_t hw_rev;
+ } test_param[] = {
+ /* Test A0 HW revision */
+ {
+ .exp_dev_id = 0x1,
+ .hw_rev = 0x0a00,
+ },
+ /* Test A1 HW revision */
+ {
+ .exp_dev_id = 0x2,
+ .hw_rev = 0x0a01,
+ },
+ /* Test A2 HW revision */
+ {
+ .exp_dev_id = 0x3,
+ .hw_rev = 0x0a02,
+ },
+ };
+
+ /* Setup chip info */
+ vendor = PS8XXX_VENDOR_ID;
+ product = PS8815_PRODUCT_ID;
+ /* Arbitrary revision */
+ fw_rev = 0x32;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_VENDOR_ID, vendor);
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_PRODUCT_ID, product);
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, fw_rev);
+
+ /* Set device id which requires fixing */
+ device_id = 0x1;
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_BCD_DEV, device_id);
+
+ /* Test error on fixing device id because of fail hw revision read */
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ PS8815_P1_REG_HW_REVISION);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set wrong hw revision */
+ hw_rev = 0x32;
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, hw_rev);
+
+ /* Test error on fixing device id */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ NULL);
+
+ /* Test fixing device id for specific HW revisions */
+ for (int i = 0; i < ARRAY_SIZE(test_param); i++) {
+ ps8xxx_emul_set_hw_rev(ps8xxx_emul, test_param[i].hw_rev);
+
+ /* Test correct device id after fixing */
+ zassert_equal(
+ EC_SUCCESS,
+ ps8xxx_tcpm_drv.get_chip_info(USBC_PORT_C1, 1, &info),
+ "Failed to get chip info in test case %d (hw_rev 0x%x)",
+ i, test_param[i].hw_rev);
+ zassert_equal(
+ vendor, info.vendor_id,
+ "0x%x != (vendor = 0x%x) in test case %d (hw_rev 0x%x)",
+ vendor, info.vendor_id, i, test_param[i].hw_rev);
+ zassert_equal(
+ product, info.product_id,
+ "0x%x != (product = 0x%x) in test case %d (hw_rev 0x%x)",
+ product, info.product_id, i, test_param[i].hw_rev);
+ zassert_equal(
+ test_param[i].exp_dev_id, info.device_id,
+ "0x%x != (device = 0x%x) in test case %d (hw_rev 0x%x)",
+ test_param[i].exp_dev_id, info.device_id, i,
+ test_param[i].hw_rev);
+ zassert_equal(
+ fw_rev, info.fw_version_number,
+ "0x%x != (FW rev = 0x%x) in test case %d (hw_rev 0x%x)",
+ fw_rev, info.fw_version_number, i,
+ test_param[i].hw_rev);
+ }
+}
+
+/** Test PS8805 get/set gpio */
+ZTEST(ps8805, test_ps8805_gpio)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *gpio_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_GPIO);
+ uint8_t exp_ctrl, gpio_ctrl;
+ int level;
+
+ struct {
+ enum ps8805_gpio signal;
+ uint16_t gpio_reg;
+ int level;
+ } test_param[] = {
+ /* Chain of set and unset GPIO to test */
+ {
+ .gpio_reg = PS8805_REG_GPIO_0,
+ .signal = PS8805_GPIO_0,
+ .level = 1,
+ },
+ {
+ .gpio_reg = PS8805_REG_GPIO_1,
+ .signal = PS8805_GPIO_1,
+ .level = 1,
+ },
+ {
+ .gpio_reg = PS8805_REG_GPIO_2,
+ .signal = PS8805_GPIO_2,
+ .level = 1,
+ },
+ /* Test setting GPIO 0 which is already set */
+ {
+ .gpio_reg = PS8805_REG_GPIO_0,
+ .signal = PS8805_GPIO_0,
+ .level = 1,
+ },
+ /* Test clearing GPIOs */
+ {
+ .gpio_reg = PS8805_REG_GPIO_0,
+ .signal = PS8805_GPIO_0,
+ .level = 0,
+ },
+ {
+ .gpio_reg = PS8805_REG_GPIO_1,
+ .signal = PS8805_GPIO_1,
+ .level = 0,
+ },
+ {
+ .gpio_reg = PS8805_REG_GPIO_2,
+ .signal = PS8805_GPIO_2,
+ .level = 0,
+ },
+ /* Test clearing GPIO 0 which is already unset */
+ {
+ .gpio_reg = PS8805_REG_GPIO_0,
+ .signal = PS8805_GPIO_0,
+ .level = 1,
+ },
+ };
+
+ /* Set arbitrary FW reg value != 0 for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+ /* Set correct power status for this test */
+ tcpci_emul_set_reg(ps8xxx_emul, TCPC_REG_POWER_STATUS, 0x0);
+ /* Init to allow access to "hidden" I2C ports */
+ zassert_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+
+ /* Test fail on invalid signal for gpio control reg */
+ zassert_equal(EC_ERROR_INVAL,
+ ps8805_gpio_set_level(USBC_PORT_C1, PS8805_GPIO_NUM, 1),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8805_gpio_get_level(USBC_PORT_C1, PS8805_GPIO_NUM,
+ &level),
+ NULL);
+
+ /* Setup fail on gpio control reg read */
+ i2c_common_emul_set_read_fail_reg(gpio_i2c_common_data,
+ PS8805_REG_GPIO_CONTROL);
+
+ /* Test fail on reading gpio control reg */
+ zassert_equal(EC_ERROR_INVAL,
+ ps8805_gpio_set_level(USBC_PORT_C1, PS8805_GPIO_0, 1),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8805_gpio_get_level(USBC_PORT_C1, PS8805_GPIO_0,
+ &level),
+ NULL);
+
+ /* Do not fail on gpio control reg read */
+ i2c_common_emul_set_read_fail_reg(gpio_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on writing gpio control reg */
+ i2c_common_emul_set_write_fail_reg(gpio_i2c_common_data,
+ PS8805_REG_GPIO_CONTROL);
+ zassert_equal(EC_ERROR_INVAL,
+ ps8805_gpio_set_level(USBC_PORT_C1, PS8805_GPIO_0, 1),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(gpio_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Clear gpio control reg */
+ ps8xxx_emul_set_gpio_ctrl(ps8xxx_emul, 0x0);
+ exp_ctrl = 0;
+
+ /* Test set and unset GPIO */
+ for (int i = 0; i < ARRAY_SIZE(test_param); i++) {
+ if (test_param[i].level) {
+ exp_ctrl |= test_param[i].gpio_reg;
+ } else {
+ exp_ctrl &= ~test_param[i].gpio_reg;
+ }
+ zassert_equal(
+ EC_SUCCESS,
+ ps8805_gpio_set_level(USBC_PORT_C1,
+ test_param[i].signal,
+ test_param[i].level),
+ "Failed gpio_set in test case %d (gpio %d, level %d)",
+ i, test_param[i].signal, test_param[i].level);
+ zassert_equal(
+ EC_SUCCESS,
+ ps8805_gpio_get_level(USBC_PORT_C1,
+ test_param[i].signal, &level),
+ "Failed gpio_get in test case %d (gpio %d, level %d)",
+ i, test_param[i].signal, test_param[i].level);
+ zassert_equal(
+ test_param[i].level, level,
+ "%d != (gpio_get_level = %d) in test case %d (gpio %d, level %d)",
+ test_param[i].level, level, i, test_param[i].signal,
+ test_param[i].level);
+ gpio_ctrl = ps8xxx_emul_get_gpio_ctrl(ps8xxx_emul);
+ zassert_equal(
+ exp_ctrl, gpio_ctrl,
+ "0x%x != (gpio_ctrl = 0x%x) in test case %d (gpio %d, level %d)",
+ exp_ctrl, gpio_ctrl, i, test_param[i].signal,
+ test_param[i].level);
+ }
+}
+
+/** Test TCPCI init and vbus level */
+static void test_ps8xxx_tcpci_init(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_init(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_init)
+{
+ test_ps8xxx_tcpci_init();
+}
+
+ZTEST(ps8815, test_tcpci_init)
+{
+ test_ps8xxx_tcpci_init();
+}
+
+/** Test TCPCI release */
+static void test_ps8xxx_tcpci_release(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_release(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_release)
+{
+ test_ps8xxx_tcpci_release();
+}
+
+ZTEST(ps8815, test_tcpci_release)
+{
+ test_ps8xxx_tcpci_release();
+}
+
+/** Test TCPCI get cc */
+static void test_ps8xxx_tcpci_get_cc(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_get_cc(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_get_cc)
+{
+ test_ps8xxx_tcpci_get_cc();
+}
+
+ZTEST(ps8815, test_tcpci_get_cc)
+{
+ test_ps8xxx_tcpci_get_cc();
+}
+
+/** Test TCPCI set cc */
+static void test_ps8xxx_tcpci_set_cc(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_set_cc(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_set_cc)
+{
+ test_ps8xxx_tcpci_set_cc();
+}
+
+ZTEST(ps8815, test_tcpci_set_cc)
+{
+ test_ps8xxx_tcpci_set_cc();
+}
+
+/** Test TCPCI set polarity */
+static void test_ps8xxx_tcpci_set_polarity(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_set_polarity(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_set_polarity)
+{
+ test_ps8xxx_tcpci_set_polarity();
+}
+
+ZTEST(ps8815, test_tcpci_set_polarity)
+{
+ test_ps8xxx_tcpci_set_polarity();
+}
+
+/** Test TCPCI set vconn */
+static void test_ps8xxx_tcpci_set_vconn(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_set_vconn(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_set_vconn)
+{
+ test_ps8xxx_tcpci_set_vconn();
+}
+
+ZTEST(ps8815, test_tcpci_set_vconn)
+{
+ test_ps8xxx_tcpci_set_vconn();
+}
+
+/** Test TCPCI set msg header */
+static void test_ps8xxx_tcpci_set_msg_header(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_set_msg_header(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_set_msg_header)
+{
+ test_ps8xxx_tcpci_set_msg_header();
+}
+
+ZTEST(ps8815, test_tcpci_set_msg_header)
+{
+ test_ps8xxx_tcpci_set_msg_header();
+}
+
+/** Test TCPCI get raw message */
+static void test_ps8xxx_tcpci_get_rx_message_raw(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_get_rx_message_raw(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_get_rx_message_raw)
+{
+ test_ps8xxx_tcpci_get_rx_message_raw();
+}
+
+ZTEST(ps8815, test_tcpci_get_rx_message_raw)
+{
+ test_ps8xxx_tcpci_get_rx_message_raw();
+}
+
+/** Test TCPCI transmitting message */
+static void test_ps8xxx_tcpci_transmit(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_transmit(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_transmit)
+{
+ test_ps8xxx_tcpci_transmit();
+}
+
+ZTEST(ps8815, test_tcpci_transmit)
+{
+ test_ps8xxx_tcpci_transmit();
+}
+
+/** Test TCPCI alert */
+static void test_ps8xxx_tcpci_alert(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_alert(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_alert)
+{
+ test_ps8xxx_tcpci_alert();
+}
+
+ZTEST(ps8815, test_tcpci_alert)
+{
+ test_ps8xxx_tcpci_alert();
+}
+
+/** Test TCPCI alert RX message */
+static void test_ps8xxx_tcpci_alert_rx_message(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_alert_rx_message(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_alert_rx_message)
+{
+ test_ps8xxx_tcpci_alert_rx_message();
+}
+
+ZTEST(ps8815, test_tcpci_alert_rx_message)
+{
+ test_ps8xxx_tcpci_alert_rx_message();
+}
+
+/** Test TCPCI enter low power mode */
+static void test_ps8xxx_tcpci_low_power_mode(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+ /*
+ * PS8751/PS8815 has the auto sleep function that enters
+ * low power mode on its own in ~2 seconds. Other chips
+ * don't have it. Stub it out for PS8751/PS8815.
+ */
+ if (board_get_ps8xxx_product_id(USBC_PORT_C1) == PS8751_PRODUCT_ID ||
+ board_get_ps8xxx_product_id(USBC_PORT_C1) == PS8815_PRODUCT_ID)
+ return;
+ test_tcpci_low_power_mode(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_low_power_mode)
+{
+ test_ps8xxx_tcpci_low_power_mode();
+}
+
+ZTEST(ps8815, test_tcpci_low_power_mode)
+{
+ test_ps8xxx_tcpci_low_power_mode();
+}
+
+/** Test TCPCI set bist test mode */
+static void test_ps8xxx_tcpci_set_bist_mode(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ test_tcpci_set_bist_mode(ps8xxx_emul, common_data, USBC_PORT_C1);
+}
+
+ZTEST(ps8805, test_tcpci_set_bist_mode)
+{
+ test_ps8xxx_tcpci_set_bist_mode();
+}
+
+ZTEST(ps8815, test_tcpci_set_bist_mode)
+{
+ test_ps8xxx_tcpci_set_bist_mode();
+}
+
+/* Setup no fail for all I2C devices associated with PS8xxx emulator */
+static void setup_no_fail_all(void)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(ps8xxx_emul);
+
+ struct i2c_common_emul_data *p0_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_0);
+ struct i2c_common_emul_data *p1_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_1);
+ struct i2c_common_emul_data *gpio_i2c_common_data =
+ ps8xxx_emul_get_i2c_common_data(ps8xxx_emul,
+ PS8XXX_EMUL_PORT_GPIO);
+
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ if (p0_i2c_common_data != NULL) {
+ i2c_common_emul_set_read_fail_reg(p0_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(p0_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ }
+
+ if (p1_i2c_common_data != NULL) {
+ i2c_common_emul_set_read_fail_reg(p1_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(p1_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ }
+
+ if (gpio_i2c_common_data != NULL) {
+ i2c_common_emul_set_read_fail_reg(gpio_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ i2c_common_emul_set_write_fail_reg(gpio_i2c_common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ }
+}
+
+/**
+ * Setup PS8xxx emulator to mimic PS8805 and setup no fail for all I2C devices
+ * associated with PS8xxx emulator
+ */
+static void ps8805_before(void *state)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ ARG_UNUSED(state);
+
+ board_set_ps8xxx_product_id(PS8805_PRODUCT_ID);
+ ps8xxx_emul_set_product_id(ps8xxx_emul, PS8805_PRODUCT_ID);
+ setup_no_fail_all();
+ zassume_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+}
+
+static void ps8805_after(void *state)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ ARG_UNUSED(state);
+
+ /* Set correct firmware revision */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+}
+
+/**
+ * Setup PS8xxx emulator to mimic PS8815 and setup no fail for all I2C devices
+ * associated with PS8xxx emulator
+ */
+static void ps8815_before(void *state)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ ARG_UNUSED(state);
+
+ board_set_ps8xxx_product_id(PS8815_PRODUCT_ID);
+ ps8xxx_emul_set_product_id(ps8xxx_emul, PS8815_PRODUCT_ID);
+ setup_no_fail_all();
+ zassume_equal(EC_SUCCESS, ps8xxx_tcpm_drv.init(USBC_PORT_C1), NULL);
+}
+
+static void ps8815_after(void *state)
+{
+ const struct emul *ps8xxx_emul = EMUL_DT_GET(PS8XXX_EMUL_NODE);
+ ARG_UNUSED(state);
+
+ /* Set correct firmware revision */
+ tcpci_emul_set_reg(ps8xxx_emul, PS8XXX_REG_FW_REV, 0x31);
+}
+
+ZTEST_SUITE(ps8805, drivers_predicate_pre_main, NULL, ps8805_before,
+ ps8805_after, NULL);
+
+ZTEST_SUITE(ps8815, drivers_predicate_pre_main, NULL, ps8815_before,
+ ps8815_after, NULL);
diff --git a/zephyr/test/drivers/default/src/smart.c b/zephyr/test/drivers/default/src/smart.c
new file mode 100644
index 0000000000..96200f1b91
--- /dev/null
+++ b/zephyr/test/drivers/default/src/smart.c
@@ -0,0 +1,568 @@
+/* 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/shell/shell.h>
+#include <zephyr/shell/shell_uart.h>
+
+#include "common.h"
+#include "console.h"
+#include "i2c.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/emul_smart_battery.h"
+
+#include "battery.h"
+#include "battery_smart.h"
+#include "test/drivers/test_state.h"
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+/** Test all simple getters */
+ZTEST_USER(smart_battery, test_battery_getters)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ char block[32];
+ int expected;
+ int word;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ zassert_equal(EC_SUCCESS, battery_get_mode(&word), NULL);
+ zassert_equal(bat->mode, word, "%d != %d", bat->mode, word);
+
+ expected = 100 * bat->cap / bat->design_cap;
+ zassert_equal(EC_SUCCESS, battery_state_of_charge_abs(&word), NULL);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ zassert_equal(EC_SUCCESS, battery_cycle_count(&word), NULL);
+ zassert_equal(bat->cycle_count, word, "%d != %d", bat->cycle_count,
+ word);
+ zassert_equal(EC_SUCCESS, battery_design_voltage(&word), NULL);
+ zassert_equal(bat->design_mv, word, "%d != %d", bat->design_mv, word);
+ zassert_equal(EC_SUCCESS, battery_serial_number(&word), NULL);
+ zassert_equal(bat->sn, word, "%d != %d", bat->sn, word);
+ zassert_equal(EC_SUCCESS, get_battery_manufacturer_name(block, 32),
+ NULL);
+ zassert_mem_equal(block, bat->mf_name, bat->mf_name_len, "%s != %s",
+ block, bat->mf_name);
+ zassert_equal(EC_SUCCESS, battery_device_name(block, 32), NULL);
+ zassert_mem_equal(block, bat->dev_name, bat->dev_name_len, "%s != %s",
+ block, bat->dev_name);
+ zassert_equal(EC_SUCCESS, battery_device_chemistry(block, 32), NULL);
+ zassert_mem_equal(block, bat->dev_chem, bat->dev_chem_len, "%s != %s",
+ block, bat->dev_chem);
+ word = battery_get_avg_current();
+ zassert_equal(bat->avg_cur, word, "%d != %d", bat->avg_cur, word);
+ word = battery_get_avg_voltage();
+ zassert_equal(bat->volt, word, "%d != %d", bat->volt, word);
+
+ bat->avg_cur = 200;
+ expected = (bat->full_cap - bat->cap) * 60 / bat->avg_cur;
+ zassert_equal(EC_SUCCESS, battery_time_to_full(&word), NULL);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ bat->cur = -200;
+ expected = bat->cap * 60 / (-bat->cur);
+ zassert_equal(EC_SUCCESS, battery_run_time_to_empty(&word), NULL);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ bat->avg_cur = -200;
+ expected = bat->cap * 60 / (-bat->avg_cur);
+ zassert_equal(EC_SUCCESS, battery_time_to_empty(&word), NULL);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+}
+
+/** Test getting capacity. These functions should force mAh mode */
+ZTEST_USER(smart_battery, test_battery_get_capacity)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ int word;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Test fail when checking battery mode */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_BATTERY_MODE);
+ zassert_equal(EC_ERROR_INVAL, battery_remaining_capacity(&word), NULL);
+ zassert_equal(EC_ERROR_INVAL, battery_full_charge_capacity(&word),
+ NULL);
+ zassert_equal(EC_ERROR_INVAL, battery_design_capacity(&word), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test getting remaining capacity and if mAh mode is forced */
+ bat->mode |= MODE_CAPACITY;
+ zassert_equal(EC_SUCCESS, battery_remaining_capacity(&word), NULL);
+ zassert_equal(bat->cap, word, "%d != %d", bat->cap, word);
+ zassert_false(bat->mode & MODE_CAPACITY, "mAh mode not forced");
+
+ /* Test getting full charge capacity and if mAh mode is forced */
+ bat->mode |= MODE_CAPACITY;
+ zassert_equal(EC_SUCCESS, battery_full_charge_capacity(&word), NULL);
+ zassert_equal(bat->full_cap, word, "%d != %d", bat->full_cap, word);
+ zassert_false(bat->mode & MODE_CAPACITY, "mAh mode not forced");
+
+ /* Test getting design capacity and if mAh mode is forced */
+ bat->mode |= MODE_CAPACITY;
+ zassert_equal(EC_SUCCESS, battery_design_capacity(&word), NULL);
+ zassert_equal(bat->design_cap, word, "%d != %d", bat->design_cap, word);
+ zassert_false(bat->mode & MODE_CAPACITY, "mAh mode not forced");
+}
+
+/** Test battery status */
+ZTEST_USER(smart_battery, test_battery_status)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ int expected;
+ int status;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ bat->status = 0;
+ bat->cur = -200;
+ bat->cap_alarm = 0;
+ bat->time_alarm = 0;
+ bat->cap = bat->full_cap / 2;
+ bat->error_code = STATUS_CODE_OVERUNDERFLOW;
+
+ expected = 0;
+ expected |= STATUS_DISCHARGING;
+ expected |= STATUS_CODE_OVERUNDERFLOW;
+
+ zassert_equal(EC_SUCCESS, battery_status(&status), NULL);
+ zassert_equal(expected, status, "%d != %d", expected, status);
+}
+
+/** Test wait for stable function */
+ZTEST_USER(smart_battery, test_battery_wait_for_stable)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+
+ /* Should fail when read function always fail */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ zassert_equal(EC_ERROR_NOT_POWERED, battery_wait_for_stable(), NULL);
+
+ /* Should be ok with default handler */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_equal(EC_SUCCESS, battery_wait_for_stable(), NULL);
+}
+
+/** Test manufacture date */
+ZTEST_USER(smart_battery, test_battery_manufacture_date)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ int day, month, year;
+ int exp_month = 5;
+ int exp_year = 2018;
+ int exp_day = 19;
+ uint16_t date;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ date = sbat_emul_date_to_word(exp_day, exp_month, exp_year);
+ bat->mf_date = date;
+
+ zassert_equal(EC_SUCCESS, battery_manufacture_date(&year, &month, &day),
+ NULL);
+ zassert_equal(exp_day, day, "%d != %d", exp_day, day);
+ zassert_equal(exp_month, month, "%d != %d", exp_month, month);
+ zassert_equal(exp_year, year, "%d != %d", exp_year, year);
+}
+
+/** Test time at rate */
+ZTEST_USER(smart_battery, test_battery_time_at_rate)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ int expect_time;
+ int minutes;
+ int rate;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Test fail on rate 0 */
+ rate = 0;
+ zassert_equal(EC_ERROR_INVAL, battery_time_at_rate(rate, &minutes),
+ NULL);
+
+ /* 10mAh at rate 6000mA will be discharged in 6s */
+ bat->cap = 10;
+ rate = -6000;
+
+ /* Test fail on writing at rate register */
+ i2c_common_emul_set_write_fail_reg(common_data, SB_AT_RATE);
+ zassert_equal(EC_ERROR_INVAL, battery_time_at_rate(rate, &minutes),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on reading at rate ok register */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_AT_RATE_OK);
+ zassert_equal(EC_ERROR_INVAL, battery_time_at_rate(rate, &minutes),
+ NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /*
+ * Expected discharging rate is less then 10s,
+ * so AtRateOk() register should return 0
+ */
+ zassert_equal(EC_ERROR_TIMEOUT, battery_time_at_rate(rate, &minutes),
+ NULL);
+
+ /* 3000mAh at rate 300mA will be discharged in 10h */
+ bat->cap = 3000;
+ rate = -300;
+ expect_time = 600;
+
+ zassert_equal(EC_SUCCESS, battery_time_at_rate(rate, &minutes), NULL);
+ zassert_equal(expect_time, minutes, "%d != %d", expect_time, minutes);
+
+ /* 1000mAh at rate 1000mA will be charged in 1h */
+ bat->cap = bat->full_cap - 1000;
+ rate = 1000;
+ /* battery_time_at_rate report time to full as negative number */
+ expect_time = -60;
+
+ zassert_equal(EC_SUCCESS, battery_time_at_rate(rate, &minutes), NULL);
+ zassert_equal(expect_time, minutes, "%d != %d", expect_time, minutes);
+}
+
+/** Test battery get params */
+ZTEST_USER(smart_battery, test_battery_get_params)
+{
+ struct sbat_emul_bat_data *bat;
+ struct batt_params batt;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ int flags;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Fail temperature read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_TEMPERATURE);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_TEMPERATURE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail state of charge read; want charge cannot be set */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ SB_RELATIVE_STATE_OF_CHARGE);
+ flags = BATT_FLAG_RESPONSIVE | BATT_FLAG_BAD_STATE_OF_CHARGE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail voltage read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_VOLTAGE);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_VOLTAGE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail current read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_CURRENT);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_CURRENT;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail average current read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_AVERAGE_CURRENT);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_AVERAGE_CURRENT;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail charging voltage read; want charge cannot be set */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_CHARGING_VOLTAGE);
+ flags = BATT_FLAG_RESPONSIVE | BATT_FLAG_BAD_DESIRED_VOLTAGE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail charging voltage read; want charge cannot be set */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_CHARGING_CURRENT);
+ flags = BATT_FLAG_RESPONSIVE | BATT_FLAG_BAD_DESIRED_CURRENT;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail remaining capacity read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_REMAINING_CAPACITY);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_REMAINING_CAPACITY;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail full capacity read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_FULL_CHARGE_CAPACITY);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_FULL_CAPACITY;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail status read */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_BATTERY_STATUS);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_STATUS;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Fail all */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ flags = BATT_FLAG_BAD_ANY;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+
+ /* Use default handler, everything should be ok */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+}
+
+struct mfgacc_data {
+ int reg;
+ uint8_t *buf;
+ int len;
+};
+
+static int mfgacc_read_func(const struct emul *emul, int reg, uint8_t *val,
+ int bytes, void *data)
+{
+ struct mfgacc_data *conf = data;
+
+ if (bytes == 0 && conf->reg == reg) {
+ sbat_emul_set_response(emul, reg, conf->buf, conf->len, false);
+ }
+
+ return 1;
+}
+
+/** Test battery manufacturer access */
+ZTEST_USER(smart_battery, test_battery_mfacc)
+{
+ struct sbat_emul_bat_data *bat;
+ struct mfgacc_data mfacc_conf;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ uint8_t recv_buf[10];
+ uint8_t mf_data[10];
+ uint16_t cmd;
+ int len;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Select arbitrary command number for the test */
+ cmd = 0x1234;
+
+ /* Test fail on to short receive buffer */
+ len = 2;
+ zassert_equal(EC_ERROR_INVAL,
+ sb_read_mfgacc(cmd, SB_ALT_MANUFACTURER_ACCESS, recv_buf,
+ len),
+ NULL);
+
+ /* Set correct length for rest of the test */
+ len = 10;
+
+ /* Test fail on writing SB_MANUFACTURER_ACCESS register */
+ i2c_common_emul_set_write_fail_reg(common_data, SB_MANUFACTURER_ACCESS);
+ zassert_equal(EC_ERROR_INVAL,
+ sb_read_mfgacc(cmd, SB_ALT_MANUFACTURER_ACCESS, recv_buf,
+ len),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on reading manufacturer data (custom handler is not set) */
+ zassert_equal(EC_ERROR_INVAL,
+ sb_read_mfgacc(cmd, SB_ALT_MANUFACTURER_ACCESS, recv_buf,
+ len),
+ NULL);
+
+ /* Set arbitrary manufacturer data */
+ for (int i = 1; i < len; i++) {
+ mf_data[i] = i;
+ }
+ /* Set first byte of message as length */
+ mf_data[0] = len;
+
+ /* Setup custom handler */
+ mfacc_conf.reg = SB_ALT_MANUFACTURER_ACCESS;
+ mfacc_conf.len = len;
+ mfacc_conf.buf = mf_data;
+ i2c_common_emul_set_read_func(common_data, mfgacc_read_func,
+ &mfacc_conf);
+
+ /* Test error when mf_data doesn't start with command */
+ zassert_equal(EC_ERROR_UNKNOWN,
+ sb_read_mfgacc(cmd, SB_ALT_MANUFACTURER_ACCESS, recv_buf,
+ len),
+ NULL);
+
+ /* Set beginning of the manufacturer data */
+ mf_data[1] = cmd & 0xff;
+ mf_data[2] = (cmd >> 8) & 0xff;
+
+ /* Test successful manufacturer data read */
+ zassert_equal(EC_SUCCESS,
+ sb_read_mfgacc(cmd, SB_ALT_MANUFACTURER_ACCESS, recv_buf,
+ len),
+ NULL);
+ /* Compare received data ignoring length byte */
+ zassert_mem_equal(mf_data + 1, recv_buf, len - 1, NULL);
+
+ /* Disable custom read function */
+ i2c_common_emul_set_read_func(common_data, NULL, NULL);
+}
+
+/** Test battery fake charge level set and read */
+ZTEST_USER(smart_battery, test_battery_fake_charge)
+{
+ struct sbat_emul_bat_data *bat;
+ struct batt_params batt;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_smart_battery_get_i2c_common_data(emul);
+ int remaining_cap;
+ int fake_charge;
+ int charge;
+ int flags;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Success on command with no argument */
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "battfake"),
+ NULL);
+
+ /* Fail on command with argument which is not a number */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "battfake test"), NULL);
+
+ /* Fail on command with charge level above 100% */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "battfake 123"), NULL);
+
+ /* Fail on command with charge level below 0% */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "battfake -23"), NULL);
+
+ /* Set fake charge level */
+ fake_charge = 65;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "battfake 65"), NULL);
+
+ /* Test that fake charge level is applied */
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+ zassert_equal(fake_charge, batt.state_of_charge, "%d%% != %d%%",
+ fake_charge, batt.state_of_charge);
+ remaining_cap = bat->full_cap * fake_charge / 100;
+ zassert_equal(remaining_cap, batt.remaining_capacity, "%d != %d",
+ remaining_cap, batt.remaining_capacity);
+
+ /* Test fake remaining capacity when full capacity is not available */
+ i2c_common_emul_set_read_fail_reg(common_data, SB_FULL_CHARGE_CAPACITY);
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE |
+ BATT_FLAG_BAD_FULL_CAPACITY;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+ zassert_equal(fake_charge, batt.state_of_charge, "%d%% != %d%%",
+ fake_charge, batt.state_of_charge);
+ remaining_cap = bat->design_cap * fake_charge / 100;
+ zassert_equal(remaining_cap, batt.remaining_capacity, "%d != %d",
+ remaining_cap, batt.remaining_capacity);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Disable fake charge level */
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "battfake -1"), NULL);
+
+ /* Test that fake charge level is not applied */
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+ charge = 100 * bat->cap / bat->full_cap;
+ zassert_equal(charge, batt.state_of_charge, "%d%% != %d%%", charge,
+ batt.state_of_charge);
+ zassert_equal(bat->cap, batt.remaining_capacity, "%d != %d", bat->cap,
+ batt.remaining_capacity);
+}
+
+/** Test battery fake temperature set and read */
+ZTEST_USER(smart_battery, test_battery_fake_temperature)
+{
+ struct sbat_emul_bat_data *bat;
+ struct batt_params batt;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ int fake_temp;
+ int flags;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Success on command with no argument */
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "batttempfake"), NULL);
+
+ /* Fail on command with argument which is not a number */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "batttempfake test"),
+ NULL);
+
+ /* Fail on command with too high temperature (above 500.0 K) */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "batttempfake 5001"),
+ NULL);
+
+ /* Fail on command with too low temperature (below 0 K) */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "batttempfake -23"),
+ NULL);
+
+ /* Set fake temperature */
+ fake_temp = 2840;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "batttempfake 2840"),
+ NULL);
+
+ /* Test that fake temperature is applied */
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+ zassert_equal(fake_temp, batt.temperature, "%d != %d", fake_temp,
+ batt.temperature);
+
+ /* Disable fake temperature */
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "batttempfake -1"),
+ NULL);
+
+ /* Test that fake temperature is not applied */
+ flags = BATT_FLAG_WANT_CHARGE | BATT_FLAG_RESPONSIVE;
+ battery_get_params(&batt);
+ zassert_equal(flags, batt.flags, "0x%x != 0x%x", flags, batt.flags);
+ zassert_equal(bat->temp, batt.temperature, "%d != %d", bat->temp,
+ batt.temperature);
+}
+
+ZTEST_SUITE(smart_battery, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/stm_mems_common.c b/zephyr/test/drivers/default/src/stm_mems_common.c
new file mode 100644
index 0000000000..f7c59105b0
--- /dev/null
+++ b/zephyr/test/drivers/default/src/stm_mems_common.c
@@ -0,0 +1,338 @@
+/* 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/ztest.h>
+#include <zephyr/device.h>
+#include <zephyr/devicetree.h>
+#include <errno.h>
+
+#include "common.h"
+#include "driver/stm_mems_common.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/i2c_mock.h"
+#include "i2c/i2c.h"
+#include "test/drivers/test_state.h"
+
+#define MOCK_EMUL EMUL_DT_GET(DT_NODELABEL(i2c_mock))
+#define COMMON_DATA emul_i2c_mock_get_i2c_common_data(MOCK_EMUL)
+
+struct mock_properties {
+ /* Incremented by the mock function every time it is called */
+ int call_count;
+};
+
+static int mock_read_fn(const struct emul *emul, int reg, uint8_t *val,
+ int bytes, void *data)
+{
+ ztest_check_expected_value(reg);
+ ztest_check_expected_value(bytes);
+ if (val != NULL) {
+ /* Allow passing a mocked read byte through the output param */
+ ztest_copy_return_data(val, sizeof(*val));
+ }
+ return ztest_get_return_value();
+}
+
+static int mock_write_fn(const struct emul *emul, int reg, uint8_t val,
+ int bytes, void *data)
+{
+ struct mock_properties *props = (struct mock_properties *)data;
+
+ if (props)
+ props->call_count++;
+
+ ztest_check_expected_value(reg);
+ ztest_check_expected_value(val);
+ ztest_check_expected_value(bytes);
+ return ztest_get_return_value();
+}
+
+ZTEST(stm_mems_common, test_st_raw_read_n)
+{
+ const struct emul *emul = MOCK_EMUL;
+
+ int rv;
+
+ i2c_common_emul_set_read_func(COMMON_DATA, mock_read_fn, NULL);
+ /*
+ * Ensure the MSb (auto-increment bit) in the register address gets
+ * set, but also return an error condition
+ */
+ ztest_expect_value(mock_read_fn, reg, 0x80);
+ ztest_expect_value(mock_read_fn, bytes, 0);
+ ztest_returns_value(mock_read_fn, -EIO);
+
+ rv = st_raw_read_n(I2C_PORT_POWER, i2c_mock_get_addr(emul), 0, NULL, 2);
+ /* The shim layer translates -EIO to EC_ERROR_INVAL. */
+ zassert_equal(rv, EC_ERROR_INVAL, "rv was %d but expected %d", rv,
+ EC_ERROR_INVAL);
+}
+
+ZTEST(stm_mems_common, test_st_raw_read_n_noinc)
+{
+ const struct emul *emul = MOCK_EMUL;
+
+ int rv;
+
+ i2c_common_emul_set_read_func(COMMON_DATA, mock_read_fn, NULL);
+ /*
+ * Unlike `st_raw_read_n`, the MSb (auto-increment bit) in the register
+ * address should NOT be automatically set. Also return an error.
+ */
+ ztest_expect_value(mock_read_fn, reg, 0x00);
+ ztest_expect_value(mock_read_fn, bytes, 0);
+ ztest_returns_value(mock_read_fn, -EIO);
+
+ rv = st_raw_read_n_noinc(I2C_PORT_POWER, i2c_mock_get_addr(emul), 0,
+ NULL, 2);
+ /* The shim layer translates -EIO to EC_ERROR_INVAL. */
+ zassert_equal(rv, EC_ERROR_INVAL, "rv was %d but expected %d", rv,
+ EC_ERROR_INVAL);
+}
+
+ZTEST(stm_mems_common, test_st_write_data_with_mask)
+{
+ const struct emul *emul = MOCK_EMUL;
+
+ int rv;
+
+ const struct motion_sensor_t sensor = {
+ .port = I2C_PORT_POWER,
+ .i2c_spi_addr_flags = i2c_mock_get_addr(emul),
+ };
+
+ /* Arbitrary named test parameters */
+ uint8_t test_addr = 0xAA;
+ uint8_t initial_value = 0x55;
+ uint8_t test_mask = 0xF0;
+ uint8_t test_data = 0xFF;
+ uint8_t expected_new_value = (initial_value & ~test_mask) |
+ (test_data & test_mask);
+
+ /* Part 1: error occurs when reading initial value from sensor */
+ i2c_common_emul_set_read_func(COMMON_DATA, mock_read_fn, NULL);
+ ztest_expect_value(mock_read_fn, reg, test_addr);
+ ztest_expect_value(mock_read_fn, bytes, 0);
+ /* Value is immaterial but ztest has no way to explicitly ignore it */
+ ztest_return_data(mock_read_fn, val, &initial_value);
+ ztest_returns_value(mock_read_fn, -EIO);
+
+ rv = st_write_data_with_mask(&sensor, test_addr, test_mask, test_data);
+ /* The shim layer translates -EIO to EC_ERROR_INVAL. */
+ zassert_equal(rv, EC_ERROR_INVAL, "rv was %d but expected %d", rv,
+ EC_ERROR_INVAL);
+
+ /*
+ * Part 2: initial read succeeds, but the initial value already
+ * matches the new value, so no write happens.
+ */
+ ztest_expect_value(mock_read_fn, reg, test_addr);
+ ztest_expect_value(mock_read_fn, bytes, 0);
+ ztest_return_data(mock_read_fn, val, &expected_new_value);
+ ztest_returns_value(mock_read_fn, 0);
+
+ struct mock_properties write_fn_props = {
+ .call_count = 0,
+ };
+
+ i2c_common_emul_set_write_func(COMMON_DATA, mock_write_fn,
+ &write_fn_props);
+
+ rv = st_write_data_with_mask(&sensor, test_addr, test_mask, test_data);
+ zassert_equal(rv, EC_SUCCESS, "rv was %d but expected %d", rv,
+ EC_SUCCESS);
+ zassert_equal(write_fn_props.call_count, 0,
+ "mock_write_fn was called.");
+
+ /*
+ * Part 3: this time a write is required, but it fails. This also
+ * tests the masking logic.
+ */
+ ztest_expect_value(mock_read_fn, reg, test_addr);
+ ztest_expect_value(mock_read_fn, bytes, 0);
+ ztest_return_data(mock_read_fn, val, &initial_value);
+ ztest_returns_value(mock_read_fn, 0);
+
+ write_fn_props.call_count = 0; /* Reset call count */
+ ztest_expect_value(mock_write_fn, reg, test_addr);
+ ztest_expect_value(mock_write_fn, bytes, 1);
+ ztest_expect_value(mock_write_fn, val, expected_new_value);
+ ztest_returns_value(mock_write_fn, -EIO);
+
+ rv = st_write_data_with_mask(&sensor, test_addr, test_mask, test_data);
+ /* The shim layer translates -EIO to EC_ERROR_INVAL. */
+ zassert_equal(rv, EC_ERROR_INVAL, "rv was %d but expected %d", rv,
+ EC_ERROR_INVAL);
+ zassert_equal(write_fn_props.call_count, 1,
+ "mock_write_fn was not called.");
+}
+
+ZTEST(stm_mems_common, test_st_get_resolution)
+{
+ int expected_resolution = 123;
+ int rv;
+
+ struct stprivate_data driver_data = {
+ .resol = expected_resolution,
+ };
+
+ const struct motion_sensor_t sensor = {
+ .drv_data = &driver_data,
+ };
+
+ rv = st_get_resolution(&sensor);
+ zassert_equal(rv, expected_resolution, "rv is %d but expected %d", rv,
+ expected_resolution);
+}
+
+ZTEST(stm_mems_common, test_st_set_offset)
+{
+ int16_t expected_offset[3] = { 123, 456, 789 };
+
+ struct stprivate_data driver_data;
+ const struct motion_sensor_t sensor = {
+ .drv_data = &driver_data,
+ };
+
+ int rv = st_set_offset(&sensor, expected_offset, 0);
+
+ zassert_equal(rv, EC_SUCCESS, "rv as %d but expected %d", rv,
+ EC_SUCCESS);
+ zassert_equal(driver_data.offset[X], expected_offset[X],
+ "X offset is %d but expected %d", driver_data.offset[X],
+ expected_offset[X]);
+ zassert_equal(driver_data.offset[Y], expected_offset[Y],
+ "Y offset is %d but expected %d", driver_data.offset[Y],
+ expected_offset[Y]);
+ zassert_equal(driver_data.offset[Z], expected_offset[Z],
+ "Z offset is %d but expected %d", driver_data.offset[Z],
+ expected_offset[Z]);
+}
+
+ZTEST(stm_mems_common, test_st_get_offset)
+{
+ struct stprivate_data driver_data = {
+ .offset = { [X] = 123, [Y] = 456, [Z] = 789 },
+ };
+ const struct motion_sensor_t sensor = {
+ .drv_data = &driver_data,
+ };
+
+ int16_t temp_out = 0;
+ int16_t actual_offset[3] = { 0, 0, 0 };
+
+ int rv = st_get_offset(&sensor, actual_offset, &temp_out);
+
+ zassert_equal(rv, EC_SUCCESS, "rv as %d but expected %d", rv,
+ EC_SUCCESS);
+ zassert_equal(
+ temp_out, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP,
+ "temp is %d but should be %d (EC_MOTION_SENSE_INVALID_CALIB_TEMP)",
+ temp_out, (int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP);
+
+ zassert_equal(actual_offset[X], driver_data.offset[X],
+ "X offset is %d but expected %d", actual_offset[X],
+ driver_data.offset[X]);
+ zassert_equal(actual_offset[Y], driver_data.offset[Y],
+ "Y offset is %d but expected %d", actual_offset[Y],
+ driver_data.offset[Y]);
+ zassert_equal(actual_offset[Z], driver_data.offset[Z],
+ "Z offset is %d but expected %d", actual_offset[Z],
+ driver_data.offset[Z]);
+}
+
+ZTEST(stm_mems_common, test_st_get_data_rate)
+{
+ int expected_data_rate = 456;
+ int rv;
+
+ struct stprivate_data driver_data = {
+ .base = {
+ .odr = expected_data_rate,
+ },
+ };
+
+ const struct motion_sensor_t sensor = {
+ .drv_data = &driver_data,
+ };
+
+ rv = st_get_data_rate(&sensor);
+ zassert_equal(rv, expected_data_rate, "rv is %d but expected %d", rv,
+ expected_data_rate);
+}
+
+ZTEST(stm_mems_common, test_st_normalize)
+{
+ struct stprivate_data driver_data = {
+ .resol = 12, /* 12 bits of useful data (arbitrary) */
+ .offset = { /* Arbitrary offsets */
+ [X] = -100,
+ [Y] = 200,
+ [Z] = 100,
+ },
+ };
+ /* Fixed-point identity matrix that performs no rotation. */
+ const mat33_fp_t identity_rot_matrix = {
+ { INT_TO_FP(1), INT_TO_FP(0), INT_TO_FP(0) },
+ { INT_TO_FP(0), INT_TO_FP(1), INT_TO_FP(0) },
+ { INT_TO_FP(0), INT_TO_FP(0), INT_TO_FP(1) },
+ };
+ const struct motion_sensor_t sensor = {
+ .drv_data = &driver_data,
+ .rot_standard_ref = &identity_rot_matrix,
+ .current_range = 32, /* used to scale offsets (arbitrary) */
+ };
+
+ /* Accelerometer data is passed in with the format:
+ * (lower address) (higher address)
+ * [X LSB] [X MSB] [Y LSB] [Y MSB] [Z LSB] [Z MSB]
+ *
+ * The LSB are left-aligned and contain noise/junk data
+ * in their least-significant bit positions. When interpreted
+ * as int16 samples, the `driver_data.resol`-count most
+ * significant bits are what we actually use. For this test, we
+ * set `resol` to 12, so there will be 12 useful bits and 4 noise
+ * bits. This test (and the EC code) assume we are compiling on
+ * a little-endian machine. The samples themselvesare unsigned and
+ * biased at 2^12/2 = 2^11.
+ */
+ uint16_t input_reading[] = {
+ ((BIT(11) - 100) << 4) | 0x000a,
+ ((BIT(11) + 0) << 4) | 0x000b,
+ ((BIT(11) + 100) << 4) | 0x000c,
+ };
+
+ /* Expected outputs w/ noise bits suppressed and offsets applied.
+ * Note that the data stays left-aligned.
+ */
+ intv3_t expected_output = {
+ ((BIT(11) - 100) << 4) + driver_data.offset[X],
+ ((BIT(11) + 0) << 4) + driver_data.offset[Y],
+ ((BIT(11) + 100) << 4) + driver_data.offset[Z],
+ };
+
+ intv3_t actual_output = { 0 };
+
+ st_normalize(&sensor, (int *)&actual_output, (uint8_t *)input_reading);
+
+ zassert_within(actual_output[X], expected_output[X], 0.5f,
+ "X output is %d but expected %d", actual_output[X],
+ expected_output[X]);
+ zassert_within(actual_output[Y], expected_output[Y], 0.5f,
+ "Y output is %d but expected %d", actual_output[Y],
+ expected_output[Y]);
+ zassert_within(actual_output[Z], expected_output[Z], 0.5f,
+ "Z output is %d but expected %d", actual_output[Z],
+ expected_output[Z]);
+}
+
+static void stm_mems_common_before(void *state)
+{
+ ARG_UNUSED(state);
+ i2c_mock_reset(MOCK_EMUL);
+}
+
+ZTEST_SUITE(stm_mems_common, drivers_predicate_post_main, NULL,
+ stm_mems_common_before, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/system.c b/zephyr/test/drivers/default/src/system.c
new file mode 100644
index 0000000000..01956d8721
--- /dev/null
+++ b/zephyr/test/drivers/default/src/system.c
@@ -0,0 +1,113 @@
+/* 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 "ec_commands.h"
+#include "host_command.h"
+#include "system.h"
+#include "test/drivers/test_state.h"
+
+/* System Host Commands */
+
+ZTEST_USER(system, test_hostcmd_sysinfo)
+{
+ struct ec_response_sysinfo response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_SYSINFO, 0, response);
+
+ /* Simply issue the command and get the results */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.reset_flags, 0, "response.reset_flags = %d",
+ response.reset_flags);
+ zassert_equal(response.current_image, EC_IMAGE_RO,
+ "response.current_image = %d", response.current_image);
+ zassert_equal(response.flags, 0, "response.flags = %d", response.flags);
+}
+
+ZTEST_USER(system, test_hostcmd_board_version)
+{
+ struct ec_response_board_version response;
+ struct host_cmd_handler_args args = BUILD_HOST_COMMAND_RESPONSE(
+ EC_CMD_GET_BOARD_VERSION, 0, response);
+
+ /* Get the board version, which is default 0. */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.board_version, 0, "response.board_version = %d",
+ response.board_version);
+}
+
+/* System Function Testing */
+
+static void system_flags_before_after(void *data)
+{
+ ARG_UNUSED(data);
+ system_clear_reset_flags(-1);
+}
+
+ZTEST(system_save_flags, test_system_encode_save_flags)
+{
+ int flags_to_save = 0;
+ uint32_t saved_flags = 0;
+ int arbitrary_reset_flags = 1;
+
+ /* Save all possible flags */
+ flags_to_save = -1;
+
+ /* Clear all reset flags and set them arbitrarily */
+ system_set_reset_flags(arbitrary_reset_flags);
+
+ system_encode_save_flags(flags_to_save, &saved_flags);
+
+ /* Verify all non-mutually exclusive flags */
+ zassert_equal(1, saved_flags & system_get_reset_flags(), NULL);
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_AP_OFF, NULL);
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_STAY_IN_RO, NULL);
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_AP_WATCHDOG, NULL);
+}
+
+ZTEST(system_save_flags,
+ test_system_encode_save_flags_mutually_exclusive_reset_flags)
+{
+ int flags_to_save = 0;
+ uint32_t saved_flags = 0;
+
+ /* Verify reset hard takes precedence over hibernate/soft */
+ flags_to_save = SYSTEM_RESET_HARD | SYSTEM_RESET_HIBERNATE;
+
+ system_encode_save_flags(flags_to_save, &saved_flags);
+
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_HARD, NULL);
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_HIBERNATE, NULL);
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_SOFT, NULL);
+
+ /* Verify reset hibernate takes precedence over soft */
+ flags_to_save = SYSTEM_RESET_HIBERNATE;
+
+ system_encode_save_flags(flags_to_save, &saved_flags);
+
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_HARD, NULL);
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_HIBERNATE, NULL);
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_SOFT, NULL);
+
+ /* Verify reset soft is always saved given no other flags */
+ flags_to_save = 0;
+
+ system_encode_save_flags(flags_to_save, &saved_flags);
+
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_HARD, NULL);
+ zassert_equal(0, saved_flags & EC_RESET_FLAG_HIBERNATE, NULL);
+ zassert_not_equal(0, saved_flags & EC_RESET_FLAG_SOFT, NULL);
+}
+
+ZTEST_SUITE(system, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
+
+ZTEST_SUITE(system_save_flags, drivers_predicate_post_main, NULL,
+ system_flags_before_after, system_flags_before_after, NULL);
diff --git a/zephyr/test/drivers/default/src/tablet_mode.c b/zephyr/test/drivers/default/src/tablet_mode.c
new file mode 100644
index 0000000000..d600d26072
--- /dev/null
+++ b/zephyr/test/drivers/default/src/tablet_mode.c
@@ -0,0 +1,168 @@
+/* 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/fff.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "tablet_mode.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+static void tabletmode_before(void *state)
+{
+ ARG_UNUSED(state);
+ tablet_reset();
+}
+
+static void tabletmode_after(void *state)
+{
+ ARG_UNUSED(state);
+ tablet_reset();
+}
+
+/**
+ * @brief TestPurpose: various tablet_set_mode operations, make sure lid and
+ * base works independently.
+ */
+ZTEST_USER(tabletmode, test_tablet_set_mode)
+{
+ int ret;
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet initial mode: %d", ret);
+
+ tablet_set_mode(1, TABLET_TRIGGER_LID);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ tablet_set_mode(1, TABLET_TRIGGER_BASE);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ tablet_set_mode(0, TABLET_TRIGGER_LID);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ tablet_set_mode(0, TABLET_TRIGGER_BASE);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet mode: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: test the tablet_disable functionality.
+ */
+ZTEST_USER(tabletmode, test_tablet_disable)
+{
+ int ret;
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet initial mode: %d", ret);
+
+ tablet_disable();
+ tablet_set_mode(1, TABLET_TRIGGER_LID);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet mode: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: check that tabletmode on and off changes the mode.
+ */
+ZTEST_USER(tabletmode, test_settabletmode_on_off)
+{
+ int ret;
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet initial mode: %d", ret);
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode");
+ zassert_equal(ret, EC_SUCCESS, "unexepcted command return status: %d",
+ ret);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet mode: %d", ret);
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode on");
+ zassert_equal(ret, EC_SUCCESS, "unexepcted command return status: %d",
+ ret);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode off");
+ zassert_equal(ret, EC_SUCCESS, "unexepcted command return status: %d",
+ ret);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet mode: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: ensure that console tabletmode forces the status,
+ * inhibiting tablet_set_mode, and then unforce it with reset.
+ */
+ZTEST_USER(tabletmode, test_settabletmode_forced)
+{
+ int ret;
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet initial mode: %d", ret);
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode on");
+ zassert_equal(ret, EC_SUCCESS, "unexepcted command return status: %d",
+ ret);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ tablet_set_mode(0, TABLET_TRIGGER_LID);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 1, "unexepcted tablet mode: %d", ret);
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode reset");
+ zassert_equal(ret, EC_SUCCESS, "unexepcted command return status: %d",
+ ret);
+
+ tablet_set_mode(0, TABLET_TRIGGER_LID);
+
+ ret = tablet_get_mode();
+ zassert_equal(ret, 0, "unexepcted tablet mode: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: check the "too many arguments" case.
+ */
+ZTEST_USER(tabletmode, test_settabletmode_too_many_args)
+{
+ int ret;
+
+ ret = shell_execute_cmd(get_ec_shell(),
+ "tabletmode too many arguments");
+ zassert_equal(ret, EC_ERROR_PARAM_COUNT,
+ "unexepcted command return status: %d", ret);
+}
+
+/**
+ * @brief TestPurpose: check the "unknown argument" case.
+ */
+ZTEST_USER(tabletmode, test_settabletmode_unknown_arg)
+{
+ int ret;
+
+ ret = shell_execute_cmd(get_ec_shell(), "tabletmode X");
+ zassert_equal(ret, EC_ERROR_PARAM1,
+ "unexepcted command return status: %d", ret);
+}
+
+ZTEST_SUITE(tabletmode, drivers_predicate_post_main, NULL, tabletmode_before,
+ tabletmode_after, NULL);
diff --git a/zephyr/test/drivers/default/src/tcpci.c b/zephyr/test/drivers/default/src/tcpci.c
new file mode 100644
index 0000000000..e549e5056a
--- /dev/null
+++ b/zephyr/test/drivers/default/src/tcpci.c
@@ -0,0 +1,524 @@
+/* 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.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "test/drivers/stubs.h"
+#include "test/drivers/tcpci_test_common.h"
+
+#include "tcpm/tcpci.h"
+#include "test/drivers/test_state.h"
+
+#define TCPCI_EMUL_NODE DT_NODELABEL(tcpci_emul)
+
+/** Test TCPCI init and vbus level */
+ZTEST(tcpci, test_generic_tcpci_init)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_init(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI release */
+ZTEST(tcpci, test_generic_tcpci_release)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_release(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI get cc */
+ZTEST(tcpci, test_generic_tcpci_get_cc)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_get_cc(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI set cc */
+ZTEST(tcpci, test_generic_tcpci_set_cc)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_cc(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI set polarity */
+ZTEST(tcpci, test_generic_tcpci_set_polarity)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_polarity(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI set vconn */
+ZTEST(tcpci, test_generic_tcpci_set_vconn)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_vconn(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI set msg header */
+ZTEST(tcpci, test_generic_tcpci_set_msg_header)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_msg_header(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI rx and sop prime enable */
+ZTEST(tcpci, test_generic_tcpci_set_rx_detect)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_rx_detect(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI get raw message from TCPC revision 2.0 */
+ZTEST(tcpci, test_generic_tcpci_get_rx_message_raw_rev2)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ /* Revision 2.0 is set by default in test_rules */
+ test_tcpci_get_rx_message_raw(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI get raw message from TCPC revision 1.0 */
+ZTEST(tcpci, test_generic_tcpci_get_rx_message_raw_rev1)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ tcpc_config[USBC_PORT_C0].flags = 0;
+ tcpci_emul_set_rev(emul, TCPCI_EMUL_REV1_0_VER1_0);
+
+ test_tcpci_get_rx_message_raw(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI transmitting message from TCPC revision 2.0 */
+ZTEST(tcpci, test_generic_tcpci_transmit_rev2)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ /* Revision 2.0 is set by default in test_rules */
+ test_tcpci_transmit(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI transmitting message from TCPC revision 1.0 */
+ZTEST(tcpci, test_generic_tcpci_transmit_rev1)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ tcpc_config[USBC_PORT_C0].flags = 0;
+ tcpci_emul_set_rev(emul, TCPCI_EMUL_REV1_0_VER1_0);
+
+ test_tcpci_transmit(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI alert */
+ZTEST(tcpci, test_generic_tcpci_alert)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_alert(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI alert RX message */
+ZTEST(tcpci, test_generic_tcpci_alert_rx_message)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_alert_rx_message(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI auto discharge on disconnect */
+ZTEST(tcpci, test_generic_tcpci_auto_discharge)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_auto_discharge(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI drp toggle */
+ZTEST(tcpci, test_generic_tcpci_drp_toggle)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_drp_toggle(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI get chip info */
+ZTEST(tcpci, test_generic_tcpci_get_chip_info)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_get_chip_info(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI enter low power mode */
+ZTEST(tcpci, test_generic_tcpci_low_power_mode)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_low_power_mode(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI set bist test mode */
+ZTEST(tcpci, test_generic_tcpci_set_bist_mode)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_set_bist_mode(emul, common_data, USBC_PORT_C0);
+}
+
+/** Test TCPCI discharge vbus */
+ZTEST(tcpci, test_generic_tcpci_discharge_vbus)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ uint8_t exp_ctrl, initial_ctrl;
+
+ /* Set initial value for POWER ctrl register. Chosen arbitrary. */
+ initial_ctrl = TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS |
+ TCPC_REG_POWER_CTRL_VOLT_ALARM_DIS;
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_CTRL, initial_ctrl);
+
+ /* Test discharge enable */
+ exp_ctrl = initial_ctrl | TCPC_REG_POWER_CTRL_FORCE_DISCHARGE;
+ tcpci_tcpc_discharge_vbus(USBC_PORT_C0, 1);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+
+ /* Test discharge disable */
+ exp_ctrl = initial_ctrl & ~TCPC_REG_POWER_CTRL_FORCE_DISCHARGE;
+ tcpci_tcpc_discharge_vbus(USBC_PORT_C0, 0);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+}
+
+/** Test TCPC xfer */
+ZTEST(tcpci, test_tcpc_xfer)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ uint16_t val, exp_val;
+ uint8_t reg;
+
+ /* Set value to register (value and register chosen arbitrary) */
+ exp_val = 0x7fff;
+ reg = TCPC_REG_ALERT_MASK;
+ tcpci_emul_set_reg(emul, reg, exp_val);
+
+ /* Test reading value using tcpc_xfer() function */
+ zassert_equal(EC_SUCCESS,
+ tcpc_xfer(USBC_PORT_C0, &reg, 1, (uint8_t *)&val, 2),
+ NULL);
+ zassert_equal(exp_val, val, "0x%x != 0x%x", exp_val, val);
+}
+
+/** Test TCPCI debug accessory enable/disable */
+ZTEST(tcpci, test_generic_tcpci_debug_accessory)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ uint8_t exp_val, initial_val;
+
+ /* Set initial value for STD output register. Chosen arbitrary. */
+ initial_val = TCPC_REG_CONFIG_STD_OUTPUT_AUDIO_CONN_N |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB |
+ TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED |
+ TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N;
+ tcpci_emul_set_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, initial_val);
+
+ /* Test debug accessory connect */
+ exp_val = initial_val & ~TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N;
+ tcpci_tcpc_debug_accessory(USBC_PORT_C0, 1);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+
+ /* Test debug accessory disconnect */
+ exp_val = initial_val | TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N;
+ tcpci_tcpc_debug_accessory(USBC_PORT_C0, 0);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+}
+
+/* Setup TCPCI usb mux to behave as it is used only for usb mux */
+static void set_usb_mux_not_tcpc(void)
+{
+ usbc0_mux0.flags = USB_MUX_FLAG_NOT_TCPC;
+}
+
+/* Setup TCPCI usb mux to behave as it is used for usb mux and TCPC */
+static void set_usb_mux_tcpc(void)
+{
+ usbc0_mux0.flags = 0;
+}
+
+/** Test TCPCI mux init */
+ZTEST(tcpci, test_generic_tcpci_mux_init)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+ const struct usb_mux *tcpci_usb_mux = usb_muxes[USBC_PORT_C0].mux;
+
+ /* Set as usb mux with TCPC for first init call */
+ set_usb_mux_tcpc();
+
+ /* Make sure that TCPC is not accessed */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ zassert_equal(EC_SUCCESS, tcpci_tcpm_mux_init(tcpci_usb_mux), NULL);
+
+ /* Set as only usb mux without TCPC for rest of the test */
+ set_usb_mux_not_tcpc();
+
+ /* Test fail on power status read */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_POWER_STATUS);
+ zassert_equal(EC_ERROR_INVAL, tcpci_tcpm_mux_init(tcpci_usb_mux), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on uninitialised bit set */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_UNINIT);
+ zassert_equal(EC_ERROR_TIMEOUT, tcpci_tcpm_mux_init(tcpci_usb_mux),
+ NULL);
+
+ /* Set default power status for rest of the test */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ /* Test fail on alert mask write fail */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ALERT_MASK);
+ zassert_equal(EC_ERROR_UNKNOWN, tcpci_tcpm_mux_init(tcpci_usb_mux),
+ NULL);
+
+ /* Test fail on alert write fail */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ALERT);
+ zassert_equal(EC_ERROR_UNKNOWN, tcpci_tcpm_mux_init(tcpci_usb_mux),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set arbitrary value to alert and alert mask registers */
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, 0xffff);
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT_MASK, 0xffff);
+
+ /* Test success init */
+ zassert_equal(EC_SUCCESS, tcpci_tcpm_mux_init(tcpci_usb_mux), NULL);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, 0);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0);
+}
+
+/** Test TCPCI mux enter low power mode */
+ZTEST(tcpci, test_generic_tcpci_mux_enter_low_power)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+ const struct usb_mux *tcpci_usb_mux = usb_muxes[USBC_PORT_C0].mux;
+
+ /* Set as usb mux with TCPC for first enter_low_power call */
+ set_usb_mux_tcpc();
+
+ /* Make sure that TCPC is not accessed */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ zassert_equal(EC_SUCCESS, tcpci_tcpm_mux_enter_low_power(tcpci_usb_mux),
+ NULL);
+
+ /* Set as only usb mux without TCPC for rest of the test */
+ set_usb_mux_not_tcpc();
+
+ /* Test error on failed command set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_COMMAND);
+ zassert_equal(EC_ERROR_INVAL,
+ tcpci_tcpm_mux_enter_low_power(tcpci_usb_mux), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test correct command is issued */
+ zassert_equal(EC_SUCCESS, tcpci_tcpm_mux_enter_low_power(tcpci_usb_mux),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
+}
+
+/** Test TCPCI mux set and get */
+static void test_generic_tcpci_mux_set_get(void)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+ const struct usb_mux *tcpci_usb_mux = usb_muxes[USBC_PORT_C0].mux;
+ mux_state_t mux_state, mux_state_get;
+ uint16_t exp_val, initial_val;
+ bool ack;
+
+ mux_state = USB_PD_MUX_NONE;
+
+ /* Test fail on standard output config register read */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ TCPC_REG_CONFIG_STD_OUTPUT);
+ zassert_equal(EC_ERROR_INVAL,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ zassert_equal(EC_ERROR_INVAL,
+ tcpci_tcpm_mux_get(tcpci_usb_mux, &mux_state_get), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on standard output config register write */
+ i2c_common_emul_set_write_fail_reg(common_data,
+ TCPC_REG_CONFIG_STD_OUTPUT);
+ zassert_equal(EC_ERROR_INVAL,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set initial value for STD output register. Chosen arbitrary. */
+ initial_val = TCPC_REG_CONFIG_STD_OUTPUT_AUDIO_CONN_N |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB |
+ TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED |
+ TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N;
+ tcpci_emul_set_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, initial_val);
+
+ /* Test setting/getting no MUX connection without polarity inverted */
+ exp_val = (initial_val & ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK) |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_NONE;
+ exp_val &= ~TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED;
+ mux_state = USB_PD_MUX_NONE;
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+ zassert_false(ack, "Ack from host shouldn't be required");
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_get(tcpci_usb_mux, &mux_state_get), NULL);
+ zassert_equal(mux_state, mux_state_get, "Expected state 0x%x, got 0x%x",
+ mux_state, mux_state_get);
+
+ /* Test setting/getting MUX DP with polarity inverted */
+ exp_val = (initial_val & ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK) |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP |
+ TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED;
+ mux_state = USB_PD_MUX_DP_ENABLED | USB_PD_MUX_POLARITY_INVERTED;
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+ zassert_false(ack, "Ack from host shouldn't be required");
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_get(tcpci_usb_mux, &mux_state_get), NULL);
+ zassert_equal(mux_state, mux_state_get, "Expected state 0x%x, got 0x%x",
+ mux_state, mux_state_get);
+
+ /* Test setting/getting MUX USB without polarity inverted */
+ exp_val = (initial_val & ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK) |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB;
+ exp_val &= ~TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED;
+ mux_state = USB_PD_MUX_USB_ENABLED;
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+ zassert_false(ack, "Ack from host shouldn't be required");
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_get(tcpci_usb_mux, &mux_state_get), NULL);
+ zassert_equal(mux_state, mux_state_get, "Expected state 0x%x, got 0x%x",
+ mux_state, mux_state_get);
+
+ /* Test setting/getting MUX USB and DP with polarity inverted */
+ exp_val = (initial_val & ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK) |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP |
+ TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB |
+ TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED;
+ mux_state = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED |
+ USB_PD_MUX_POLARITY_INVERTED;
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_set(tcpci_usb_mux, mux_state, &ack), NULL);
+ check_tcpci_reg(emul, TCPC_REG_CONFIG_STD_OUTPUT, exp_val);
+ zassert_false(ack, "Ack from host shouldn't be required");
+ zassert_equal(EC_SUCCESS,
+ tcpci_tcpm_mux_get(tcpci_usb_mux, &mux_state_get), NULL);
+ zassert_equal(mux_state, mux_state_get, "Expected state 0x%x, got 0x%x",
+ mux_state, mux_state_get);
+}
+
+ZTEST(tcpci, test_generic_tcpci_mux_set_get)
+{
+ test_generic_tcpci_mux_set_get();
+}
+
+ZTEST(tcpci, test_generic_tcpci_mux_set_get__not_tcpc)
+{
+ set_usb_mux_not_tcpc();
+ test_generic_tcpci_mux_set_get();
+ set_usb_mux_tcpc();
+}
+
+ZTEST(tcpci, test_generic_tcpci_hard_reset_reinit)
+{
+ const struct emul *emul = EMUL_DT_GET(TCPCI_EMUL_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcpci_generic_get_i2c_common_data(emul);
+
+ test_tcpci_hard_reset_reinit(emul, common_data, USBC_PORT_C0);
+}
+
+static void *tcpci_setup(void)
+{
+ /* This test suite assumes that first usb mux for port C0 is TCPCI */
+ __ASSERT(usb_muxes[USBC_PORT_C0].mux->driver ==
+ &tcpci_tcpm_usb_mux_driver,
+ "Invalid config of usb_muxes in test/drivers/src/stubs.c");
+
+ return NULL;
+}
+
+static void tcpci_after(void *state)
+{
+ set_usb_mux_tcpc();
+}
+
+ZTEST_SUITE(tcpci, drivers_predicate_pre_main, tcpci_setup, NULL, tcpci_after,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/tcpci_test_common.c b/zephyr/test/drivers/default/src/tcpci_test_common.c
new file mode 100644
index 0000000000..f2c0c58bf9
--- /dev/null
+++ b/zephyr/test/drivers/default/src/tcpci_test_common.c
@@ -0,0 +1,1030 @@
+/* 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 "common.h"
+#include "emul/emul_common_i2c.h"
+#include "emul/tcpc/emul_tcpci.h"
+#include "test/drivers/tcpci_test_common.h"
+
+#include "tcpm/tcpci.h"
+
+/** Check TCPC register value */
+void check_tcpci_reg_f(const struct emul *emul, int reg, uint16_t exp_val,
+ int line)
+{
+ uint16_t reg_val;
+
+ zassert_ok(tcpci_emul_get_reg(emul, reg, &reg_val),
+ "Failed tcpci_emul_get_reg(); line: %d", line);
+ zassert_equal(exp_val, reg_val, "Expected 0x%x, got 0x%x; line: %d",
+ exp_val, reg_val, line);
+}
+
+/** Check TCPC register value with mask */
+void check_tcpci_reg_with_mask_f(const struct emul *emul, int reg,
+ uint16_t exp_val, uint16_t mask, int line)
+{
+ uint16_t reg_val;
+
+ zassert_ok(tcpci_emul_get_reg(emul, reg, &reg_val),
+ "Failed tcpci_emul_get_reg(); line: %d", line);
+ zassert_equal(exp_val & mask, reg_val & mask,
+ "Expected 0x%x, got 0x%x, mask 0x%x; line: %d", exp_val,
+ reg_val, mask, line);
+}
+
+/** Test TCPCI init and vbus level */
+void test_tcpci_init(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint16_t exp_mask;
+
+ tcpc_config[port].flags |= TCPC_FLAGS_TCPCI_REV2_0_NO_VSAFE0V;
+
+ /* Test fail on power status read */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_POWER_STATUS);
+ zassert_equal(EC_ERROR_INVAL, drv->init(port), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test fail on uninitialised bit set */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_UNINIT);
+ zassert_equal(EC_ERROR_TIMEOUT, drv->init(port), NULL);
+
+ /*
+ * Set expected alert mask. It is used in test until vSafe0V tcpc
+ * config flag is revmoved.
+ */
+ exp_mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED |
+ TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS |
+ TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS |
+ TCPC_REG_ALERT_FAULT | TCPC_REG_ALERT_POWER_STATUS;
+
+ /* Set TCPCI emulator VBUS to safe0v (disconnected) */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ /* Test init with VBUS safe0v without vSafe0V tcpc config flag */
+ zassert_equal(EC_SUCCESS, drv->init(port), NULL);
+ zassert_true(drv->check_vbus_level(port, VBUS_SAFE0V), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_PRESENT), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ TCPC_REG_POWER_STATUS_VBUS_PRES);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+
+ /* Set TCPCI emulator VBUS to present (connected, above 4V) */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_VBUS_PRES |
+ TCPC_REG_POWER_STATUS_VBUS_DET);
+
+ /* Test init with VBUS present without vSafe0V tcpc config flag */
+ zassert_equal(EC_SUCCESS, drv->init(port), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_SAFE0V), NULL);
+ zassert_true(drv->check_vbus_level(port, VBUS_PRESENT), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ TCPC_REG_POWER_STATUS_VBUS_PRES);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+
+ /* Disable vSafe0V tcpc config flag and update expected alert mask */
+ exp_mask |= TCPC_REG_ALERT_EXT_STATUS;
+ tcpc_config[port].flags = TCPC_FLAGS_TCPCI_REV2_0;
+
+ /* Test init with VBUS present with vSafe0V tcpc config flag */
+ zassert_equal(EC_SUCCESS, drv->init(port), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_SAFE0V), NULL);
+ zassert_true(drv->check_vbus_level(port, VBUS_PRESENT), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ TCPC_REG_POWER_STATUS_VBUS_PRES);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+
+ /* Set TCPCI emulator VBUS to safe0v (disconnected) */
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS,
+ TCPC_REG_POWER_STATUS_VBUS_DET);
+ tcpci_emul_set_reg(emul, TCPC_REG_EXT_STATUS,
+ TCPC_REG_EXT_STATUS_SAFE0V);
+
+ /* Test init with VBUS safe0v with vSafe0V tcpc config flag */
+ zassert_equal(EC_SUCCESS, drv->init(port), NULL);
+ zassert_true(drv->check_vbus_level(port, VBUS_SAFE0V), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_PRESENT), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ TCPC_REG_POWER_STATUS_VBUS_PRES);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+
+ /*
+ * Set TCPCI emulator VBUS to disconnected but not at vSafe0V
+ * (VBUS in 0.8V - 3.5V range)
+ */
+ tcpci_emul_set_reg(emul, TCPC_REG_EXT_STATUS, 0);
+
+ /* Test init with VBUS not safe0v with vSafe0V tcpc config flag */
+ zassert_equal(EC_SUCCESS, drv->init(port), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_SAFE0V), NULL);
+ zassert_false(drv->check_vbus_level(port, VBUS_PRESENT), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ TCPC_REG_POWER_STATUS_VBUS_PRES);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+}
+
+/** Test TCPCI release */
+void test_tcpci_release(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, 0xffff);
+
+ zassert_equal(EC_SUCCESS, drv->release(port), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK, 0);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, 0);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0);
+}
+
+/** Test TCPCI get cc */
+void test_tcpci_get_cc(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ enum tcpc_cc_voltage_status cc1, cc2;
+ uint16_t cc_status, role_ctrl;
+
+ struct {
+ /* TCPCI CC status register */
+ enum tcpc_cc_voltage_status cc[2];
+ bool connect_result;
+ /* TCPCI ROLE ctrl register */
+ enum tcpc_cc_pull role_cc[2];
+ enum tcpc_drp drp;
+ } test_param[] = {
+ /* Test DRP with open state */
+ {
+ .cc = { TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_OPEN },
+ .connect_result = false,
+ .drp = TYPEC_DRP,
+ },
+ /* Test DRP with cc1 open state, cc2 src RA */
+ {
+ .cc = { TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_RA },
+ .connect_result = false,
+ .drp = TYPEC_DRP,
+ },
+ /* Test DRP with cc1 src RA, cc2 src RD */
+ {
+ .cc = { TYPEC_CC_VOLT_RA, TYPEC_CC_VOLT_RD },
+ .connect_result = false,
+ .drp = TYPEC_DRP,
+ },
+ /* Test DRP with cc1 snk open, cc2 snk default */
+ {
+ .cc = { TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_RP_DEF },
+ .connect_result = true,
+ .drp = TYPEC_DRP,
+ },
+ /* Test DRP with cc1 snk 1.5, cc2 snk 3.0 */
+ {
+ .cc = { TYPEC_CC_VOLT_RP_1_5, TYPEC_CC_VOLT_RP_3_0 },
+ .connect_result = true,
+ .drp = TYPEC_DRP,
+ },
+ /* Test no DRP with cc1 src open, cc2 src RA */
+ {
+ .cc = { TYPEC_CC_VOLT_OPEN, TYPEC_CC_VOLT_RA },
+ .connect_result = false,
+ .drp = TYPEC_NO_DRP,
+ .role_cc = { TYPEC_CC_RP, TYPEC_CC_RP },
+ },
+ /* Test no DRP with cc1 src RD, cc2 snk default */
+ {
+ .cc = { TYPEC_CC_VOLT_RD, TYPEC_CC_VOLT_RP_DEF },
+ .connect_result = false,
+ .drp = TYPEC_NO_DRP,
+ .role_cc = { TYPEC_CC_RP, TYPEC_CC_RD },
+ },
+ /* Test no DRP with cc1 snk default, cc2 snk open */
+ {
+ .cc = { TYPEC_CC_VOLT_RP_DEF, TYPEC_CC_VOLT_OPEN },
+ .connect_result = false,
+ .drp = TYPEC_NO_DRP,
+ .role_cc = { TYPEC_CC_RD, TYPEC_CC_RD },
+ },
+ /* Test no DRP with cc1 snk 3.0, cc2 snk 1.5 */
+ {
+ .cc = { TYPEC_CC_VOLT_RP_3_0, TYPEC_CC_VOLT_RP_1_5 },
+ .connect_result = false,
+ .drp = TYPEC_NO_DRP,
+ .role_cc = { TYPEC_CC_RD, TYPEC_CC_RD },
+ },
+ };
+
+ for (int i = 0; i < ARRAY_SIZE(test_param); i++) {
+ role_ctrl = TCPC_REG_ROLE_CTRL_SET(test_param[i].drp, 0,
+ test_param[i].role_cc[0],
+ test_param[i].role_cc[1]);
+ /* If CC status is TYPEC_CC_VOLT_RP_*, then BIT(2) is ignored */
+ cc_status = TCPC_REG_CC_STATUS_SET(test_param[i].connect_result,
+ test_param[i].cc[0],
+ test_param[i].cc[1]);
+ tcpci_emul_set_reg(emul, TCPC_REG_ROLE_CTRL, role_ctrl);
+ tcpci_emul_set_reg(emul, TCPC_REG_CC_STATUS, cc_status);
+ zassert_equal(
+ EC_SUCCESS, drv->get_cc(port, &cc1, &cc2),
+ "Failed to get CC in test case %d (CC 0x%x, role 0x%x)",
+ i, cc_status, role_ctrl);
+ zassert_equal(
+ test_param[i].cc[0], cc1,
+ "0x%x != (cc1 = 0x%x) in test case %d (CC 0x%x, role 0x%x)",
+ test_param[i].cc[0], cc1, i, cc_status, role_ctrl);
+ zassert_equal(
+ test_param[i].cc[1], cc2,
+ "0x%x != (cc2 = 0x%x) in test case %d (CC 0x%x, role 0x%x)",
+ test_param[i].cc[0], cc1, i, cc_status, role_ctrl);
+ }
+}
+
+/** Test TCPCI set cc */
+void test_tcpci_set_cc(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ enum tcpc_rp_value rp;
+ enum tcpc_cc_pull cc;
+
+ /* Test setting default RP and cc open */
+ rp = TYPEC_RP_USB;
+ cc = TYPEC_CC_OPEN;
+ zassert_equal(EC_SUCCESS, drv->select_rp_value(port, rp), NULL);
+ zassert_equal(EC_SUCCESS, drv->set_cc(port, cc), NULL);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, rp, cc, cc));
+
+ /* Test error on failed role ctrl set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ROLE_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->set_cc(port, TYPEC_CC_OPEN), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting 1.5 RP and cc RD */
+ rp = TYPEC_RP_1A5;
+ cc = TYPEC_CC_RD;
+ zassert_equal(EC_SUCCESS, drv->select_rp_value(port, rp), NULL);
+ zassert_equal(EC_SUCCESS, drv->set_cc(port, cc), NULL);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, rp, cc, cc));
+
+ /* Test setting 3.0 RP and cc RP */
+ rp = TYPEC_RP_3A0;
+ cc = TYPEC_CC_RP;
+ zassert_equal(EC_SUCCESS, drv->select_rp_value(port, rp), NULL);
+ zassert_equal(EC_SUCCESS, drv->set_cc(port, cc), NULL);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, rp, cc, cc));
+
+ /*
+ * Test setting 3.0 RP and cc RA. drv->select_rp_value() is
+ * intentionally not called to check if selected rp is persistent.
+ */
+ cc = TYPEC_CC_RA;
+ zassert_equal(EC_SUCCESS, drv->set_cc(port, cc), NULL);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL,
+ TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, rp, cc, cc));
+}
+
+/** Test TCPCI set polarity */
+void test_tcpci_set_polarity(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint8_t initial_ctrl;
+ uint8_t exp_ctrl;
+
+ /* Set initial value for TCPC ctrl register. Chosen arbitrary. */
+ initial_ctrl = TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL |
+ TCPC_REG_TCPC_CTRL_BIST_TEST_MODE;
+ tcpci_emul_set_reg(emul, TCPC_REG_TCPC_CTRL, initial_ctrl);
+
+ /* Test error on failed polarity set */
+ exp_ctrl = initial_ctrl;
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TCPC_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->set_polarity(port, POLARITY_CC2),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+
+ /* Test setting polarity CC2 */
+ exp_ctrl = initial_ctrl | TCPC_REG_TCPC_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_polarity(port, POLARITY_CC2), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+
+ /* Test setting polarity CC1 */
+ exp_ctrl = initial_ctrl & ~TCPC_REG_TCPC_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_polarity(port, POLARITY_CC1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+
+ /* Test setting polarity CC2 DTS */
+ exp_ctrl = initial_ctrl | TCPC_REG_TCPC_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_polarity(port, POLARITY_CC2_DTS),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+
+ /* Test setting polarity CC1 DTS */
+ exp_ctrl = initial_ctrl & ~TCPC_REG_TCPC_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_polarity(port, POLARITY_CC1_DTS),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+}
+
+/** Test TCPCI set vconn */
+void test_tcpci_set_vconn(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint8_t initial_ctrl;
+ uint8_t exp_ctrl;
+
+ /* Set initial value for POWER ctrl register. Chosen arbitrary. */
+ initial_ctrl = TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS |
+ TCPC_REG_POWER_CTRL_FORCE_DISCHARGE;
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_CTRL, initial_ctrl);
+
+ /* Test error on failed vconn set */
+ exp_ctrl = initial_ctrl;
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_POWER_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->set_vconn(port, 1), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+
+ /* Test vconn enable */
+ exp_ctrl = initial_ctrl | TCPC_REG_POWER_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_vconn(port, 1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+
+ /* Test vconn disable */
+ exp_ctrl = initial_ctrl & ~TCPC_REG_POWER_CTRL_SET(1);
+ zassert_equal(EC_SUCCESS, drv->set_vconn(port, 0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+}
+
+/** Test TCPCI set msg header */
+void test_tcpci_set_msg_header(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+
+ /* Test error on failed header set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_MSG_HDR_INFO);
+ zassert_equal(EC_ERROR_INVAL,
+ drv->set_msg_header(port, PD_ROLE_SINK, PD_ROLE_UFP),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting sink UFP */
+ zassert_equal(EC_SUCCESS,
+ drv->set_msg_header(port, PD_ROLE_SINK, PD_ROLE_UFP),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_MSG_HDR_INFO,
+ TCPC_REG_MSG_HDR_INFO_SET(PD_ROLE_UFP, PD_ROLE_SINK));
+
+ /* Test setting sink DFP */
+ zassert_equal(EC_SUCCESS,
+ drv->set_msg_header(port, PD_ROLE_SINK, PD_ROLE_DFP),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_MSG_HDR_INFO,
+ TCPC_REG_MSG_HDR_INFO_SET(PD_ROLE_DFP, PD_ROLE_SINK));
+
+ /* Test setting source UFP */
+ zassert_equal(EC_SUCCESS,
+ drv->set_msg_header(port, PD_ROLE_SOURCE, PD_ROLE_UFP),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_MSG_HDR_INFO,
+ TCPC_REG_MSG_HDR_INFO_SET(PD_ROLE_UFP, PD_ROLE_SOURCE));
+
+ /* Test setting source DFP */
+ zassert_equal(EC_SUCCESS,
+ drv->set_msg_header(port, PD_ROLE_SOURCE, PD_ROLE_DFP),
+ NULL);
+ check_tcpci_reg(emul, TCPC_REG_MSG_HDR_INFO,
+ TCPC_REG_MSG_HDR_INFO_SET(PD_ROLE_DFP, PD_ROLE_SOURCE));
+}
+
+/** Test TCPCI rx and sop prime enable */
+void test_tcpci_set_rx_detect(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+
+ /* Test error from rx_enable on rx detect set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_RX_DETECT);
+ zassert_equal(EC_ERROR_INVAL, drv->set_rx_enable(port, 1), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test rx disable */
+ zassert_equal(EC_SUCCESS, drv->set_rx_enable(port, 0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT, 0x0);
+
+ /* Test setting sop prime with rx disable doesn't change RX_DETECT */
+ zassert_equal(EC_SUCCESS, drv->sop_prime_enable(port, 1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT, 0x0);
+
+ /* Test that enabling rx after sop prime will set RX_DETECT properly */
+ zassert_equal(EC_SUCCESS, drv->set_rx_enable(port, 1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT,
+ TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK);
+
+ /* Test error from sop_prime on rx detect set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_RX_DETECT);
+ zassert_equal(EC_ERROR_INVAL, drv->sop_prime_enable(port, 0), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test disabling sop prime with rx enabled does change RX_DETECT */
+ zassert_equal(EC_SUCCESS, drv->sop_prime_enable(port, 0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT,
+ TCPC_REG_RX_DETECT_SOP_HRST_MASK);
+
+ /* Test that enabling rx after disabling sop prime set RX_DETECT */
+ zassert_equal(EC_SUCCESS, drv->set_rx_enable(port, 0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT, 0x0);
+ zassert_equal(EC_SUCCESS, drv->set_rx_enable(port, 1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_RX_DETECT,
+ TCPC_REG_RX_DETECT_SOP_HRST_MASK);
+}
+
+/** Test TCPCI get raw message from TCPC */
+void test_tcpci_get_rx_message_raw(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ struct tcpci_emul_msg msg;
+ uint32_t payload[7];
+ uint16_t rx_mask;
+ uint8_t buf[32];
+ int exp_head;
+ int i, head;
+ int size;
+
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, 0x0);
+ tcpci_emul_set_reg(emul, TCPC_REG_DEV_CAP_2,
+ TCPC_REG_DEV_CAP_2_LONG_MSG);
+ tcpci_emul_set_reg(emul, TCPC_REG_RX_DETECT,
+ TCPC_REG_RX_DETECT_SOP | TCPC_REG_RX_DETECT_SOPP);
+
+ for (i = 0; i < 32; i++) {
+ buf[i] = i + 1;
+ }
+ msg.buf = buf;
+ msg.cnt = 31;
+ msg.sop_type = TCPCI_MSG_SOP;
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg, true),
+ "Failed to setup emulator message");
+
+ /* Test fail on reading byte count */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_RX_BUFFER);
+ zassert_equal(EC_ERROR_UNKNOWN,
+ drv->get_message_raw(port, payload, &head), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ /* Get raw message should always clean RX alerts */
+ rx_mask = TCPC_REG_ALERT_RX_BUF_OVF | TCPC_REG_ALERT_RX_STATUS;
+ check_tcpci_reg_with_mask(emul, TCPC_REG_ALERT, 0x0, rx_mask);
+
+ /* Test too short message */
+ msg.cnt = 1;
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg, true),
+ "Failed to setup emulator message");
+ zassert_equal(EC_ERROR_UNKNOWN,
+ drv->get_message_raw(port, payload, &head), NULL);
+ check_tcpci_reg_with_mask(emul, TCPC_REG_ALERT, 0x0, rx_mask);
+
+ /* Test too long message */
+ msg.cnt = 31;
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg, true),
+ "Failed to setup emulator message");
+ zassert_equal(EC_ERROR_UNKNOWN,
+ drv->get_message_raw(port, payload, &head), NULL);
+ check_tcpci_reg_with_mask(emul, TCPC_REG_ALERT, 0x0, rx_mask);
+
+ /* Test alert register and message payload on success */
+ size = 28;
+ msg.cnt = size + 2;
+ msg.sop_type = TCPCI_MSG_SOP_PRIME;
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg, true),
+ "Failed to setup emulator message");
+ zassert_equal(EC_SUCCESS, drv->get_message_raw(port, payload, &head),
+ NULL);
+ check_tcpci_reg_with_mask(emul, TCPC_REG_ALERT, 0x0, rx_mask);
+ /*
+ * Type is in bits 31-28 of header, buf[0] is in bits 7-0,
+ * buf[1] is in bits 15-8
+ */
+ exp_head = (TCPCI_MSG_SOP_PRIME << 28) | (buf[1] << 8) | buf[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf + 2, size, NULL);
+}
+
+/** Test TCPCI transmitting message from TCPC */
+void test_tcpci_transmit(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ struct tcpci_emul_msg *msg;
+ uint32_t data[6];
+ uint16_t header;
+ int i;
+
+ msg = tcpci_emul_get_tx_msg(emul);
+
+ /* Fill transmit data with pattern */
+ for (i = 0; i < 6 * sizeof(uint32_t); i++) {
+ ((uint8_t *)data)[i] = i;
+ }
+
+ /* Test transmit hard reset fail */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TRANSMIT);
+ zassert_equal(EC_ERROR_INVAL,
+ drv->transmit(port, TCPCI_MSG_TX_HARD_RESET, 0, NULL),
+ NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test transmit cabel reset */
+ zassert_equal(EC_SUCCESS,
+ drv->transmit(port, TCPCI_MSG_CABLE_RESET, 0, NULL),
+ NULL);
+ zassert_equal(TCPCI_MSG_CABLE_RESET, msg->sop_type, NULL);
+
+ /* Test transmit hard reset */
+ zassert_equal(EC_SUCCESS,
+ drv->transmit(port, TCPCI_MSG_TX_HARD_RESET, 0, NULL),
+ NULL);
+ zassert_equal(TCPCI_MSG_TX_HARD_RESET, msg->sop_type, NULL);
+
+ /* Test transmit fail on rx buffer */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TX_BUFFER);
+ zassert_equal(EC_ERROR_INVAL,
+ drv->transmit(port, TCPCI_MSG_SOP_PRIME, 0, data), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test transmit only header */
+ /* Build random header with count 0 */
+ header = PD_HEADER(PD_CTRL_PING, PD_ROLE_SOURCE, PD_ROLE_UFP, 0, 0,
+ PD_REV20, 0);
+ zassert_equal(EC_SUCCESS,
+ drv->transmit(port, TCPCI_MSG_SOP_PRIME, header, data),
+ NULL);
+ zassert_equal(TCPCI_MSG_SOP_PRIME, msg->sop_type, NULL);
+ zassert_mem_equal(msg->buf, &header, 2, NULL);
+ zassert_equal(2, msg->cnt, NULL);
+
+ /* Test transmit message */
+ /* Build random header with count 6 */
+ header = PD_HEADER(PD_CTRL_PING, PD_ROLE_SOURCE, PD_ROLE_UFP, 0, 6,
+ PD_REV20, 0);
+ zassert_equal(EC_SUCCESS,
+ drv->transmit(port, TCPCI_MSG_SOP_PRIME, header, data),
+ NULL);
+ zassert_equal(TCPCI_MSG_SOP_PRIME, msg->sop_type, NULL);
+ zassert_mem_equal(msg->buf, &header, 2, NULL);
+ zassert_mem_equal(msg->buf + 2, data, 6 * sizeof(uint32_t), NULL);
+ zassert_equal(2 + 6 * sizeof(uint32_t), msg->cnt, NULL);
+}
+
+/** Test TCPCI alert */
+void test_tcpci_alert(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+
+ /* Test alert read fail */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_ALERT);
+ drv->tcpc_alert(port);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Handle overcurrent */
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, TCPC_REG_ALERT_FAULT);
+ tcpci_emul_set_reg(emul, TCPC_REG_FAULT_STATUS,
+ TCPC_REG_FAULT_STATUS_VCONN_OVER_CURRENT);
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+ check_tcpci_reg(emul, TCPC_REG_FAULT_STATUS, 0x0);
+
+ /* Test TX complete */
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, TCPC_REG_ALERT_TX_COMPLETE);
+ drv->tcpc_alert(port);
+
+ /* Test clear alert and ext_alert */
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, TCPC_REG_ALERT_ALERT_EXT);
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT_EXT,
+ TCPC_REG_ALERT_EXT_TIMER_EXPIRED);
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+ check_tcpci_reg(emul, TCPC_REG_FAULT_STATUS, 0x0);
+
+ /* Test CC changed, CC status chosen arbitrary */
+ tcpci_emul_set_reg(emul, TCPC_REG_CC_STATUS,
+ TCPC_REG_CC_STATUS_SET(1, TYPEC_CC_VOLT_RP_1_5,
+ TYPEC_CC_VOLT_RP_3_0));
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, TCPC_REG_ALERT_CC_STATUS);
+ drv->tcpc_alert(port);
+
+ /* Test Hard reset */
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_HARD_RST);
+ drv->tcpc_alert(port);
+}
+
+/** Test TCPCI alert RX message */
+void test_tcpci_alert_rx_message(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ struct tcpci_emul_msg msg1, msg2;
+ uint8_t buf1[32], buf2[32];
+ uint32_t payload[7];
+ int exp_head;
+ int i, head;
+ int size;
+
+ tcpci_emul_set_reg(emul, TCPC_REG_DEV_CAP_2,
+ TCPC_REG_DEV_CAP_2_LONG_MSG);
+ tcpci_emul_set_reg(emul, TCPC_REG_RX_DETECT,
+ TCPC_REG_RX_DETECT_SOP | TCPC_REG_RX_DETECT_SOPP);
+
+ for (i = 0; i < 32; i++) {
+ buf1[i] = i + 1;
+ buf2[i] = i + 33;
+ }
+ size = 23;
+ msg1.buf = buf1;
+ msg1.cnt = size + 3;
+ msg1.sop_type = TCPCI_MSG_SOP;
+
+ msg2.buf = buf2;
+ msg2.cnt = size + 3;
+ msg2.sop_type = TCPCI_MSG_SOP_PRIME;
+
+ /* Test receiving one message */
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg1, true),
+ "Failed to setup emulator message");
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+
+ /* Check if msg1 is in queue */
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS, tcpm_dequeue_message(port, payload, &head),
+ NULL);
+ exp_head = (TCPCI_MSG_SOP << 28) | (buf1[1] << 8) | buf1[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf1 + 2, size, NULL);
+ zassert_false(tcpm_has_pending_message(port), NULL);
+
+ /* Test receiving two messages */
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg1, true),
+ "Failed to setup emulator message");
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg2, true),
+ "Failed to setup emulator message");
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+
+ /* Check if msg1 is in queue */
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS, tcpm_dequeue_message(port, payload, &head),
+ NULL);
+ exp_head = (TCPCI_MSG_SOP << 28) | (buf1[1] << 8) | buf1[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf1 + 2, size, NULL);
+ /* Check if msg2 is in queue */
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS, tcpm_dequeue_message(port, payload, &head),
+ NULL);
+ exp_head = (TCPCI_MSG_SOP_PRIME << 28) | (buf2[1] << 8) | buf2[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf2 + 2, size, NULL);
+ zassert_false(tcpm_has_pending_message(port), NULL);
+
+ /* Test with too long first message */
+ msg1.cnt = 32;
+ tcpci_emul_set_reg(emul, TCPC_REG_DEV_CAP_2,
+ TCPC_REG_DEV_CAP_2_LONG_MSG);
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg1, true),
+ "Failed to setup emulator message");
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg2, true),
+ "Failed to setup emulator message");
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+
+ /* Check if msg2 is in queue */
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS, tcpm_dequeue_message(port, payload, &head),
+ NULL);
+ exp_head = (TCPCI_MSG_SOP_PRIME << 28) | (buf2[1] << 8) | buf2[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf2 + 2, size, NULL);
+ zassert_false(tcpm_has_pending_message(port), NULL);
+
+ /* Test constant read message failure */
+ zassert_equal(TCPCI_EMUL_TX_SUCCESS,
+ tcpci_emul_add_rx_msg(emul, &msg1, true),
+ "Failed to setup emulator message");
+ /* Create loop with one message with wrong size */
+ msg1.next = &msg1;
+ drv->tcpc_alert(port);
+ /* Nothing should be in queue */
+ zassert_false(tcpm_has_pending_message(port), NULL);
+
+ /* Test constant correct messages stream */
+ msg1.cnt = size + 3;
+ drv->tcpc_alert(port);
+ msg1.next = NULL;
+
+ /* msg1 should be at least twice in queue */
+ exp_head = (TCPCI_MSG_SOP << 28) | (buf1[1] << 8) | buf1[0];
+ for (i = 0; i < 2; i++) {
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS,
+ tcpm_dequeue_message(port, payload, &head), NULL);
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf1 + 2, size, NULL);
+ }
+ tcpm_clear_pending_messages(port);
+ zassert_false(tcpm_has_pending_message(port), NULL);
+
+ /* Read message that is left in TCPC buffer */
+ drv->tcpc_alert(port);
+ check_tcpci_reg(emul, TCPC_REG_ALERT, 0x0);
+
+ /* Check if msg1 is in queue */
+ zassert_true(tcpm_has_pending_message(port), NULL);
+ zassert_equal(EC_SUCCESS, tcpm_dequeue_message(port, payload, &head),
+ NULL);
+ exp_head = (TCPCI_MSG_SOP << 28) | (buf1[1] << 8) | buf1[0];
+ zassert_equal(exp_head, head,
+ "Received header 0x%08lx, expected 0x%08lx", head,
+ exp_head);
+ zassert_mem_equal(payload, buf1 + 2, size, NULL);
+ zassert_false(tcpm_has_pending_message(port), NULL);
+}
+
+/** Test TCPCI auto discharge on disconnect */
+void test_tcpci_auto_discharge(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint8_t initial_ctrl;
+ uint8_t exp_ctrl;
+
+ /* Set initial value for POWER ctrl register. Chosen arbitrary. */
+ initial_ctrl = TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS |
+ TCPC_REG_POWER_CTRL_FORCE_DISCHARGE;
+ tcpci_emul_set_reg(emul, TCPC_REG_POWER_CTRL, initial_ctrl);
+
+ /* Test discharge enable */
+ exp_ctrl = initial_ctrl | TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT;
+ drv->tcpc_enable_auto_discharge_disconnect(port, 1);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+
+ /* Test discharge disable */
+ exp_ctrl = initial_ctrl &
+ ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT;
+ drv->tcpc_enable_auto_discharge_disconnect(port, 0);
+ check_tcpci_reg(emul, TCPC_REG_POWER_CTRL, exp_ctrl);
+}
+
+/** Test TCPCI drp toggle */
+void test_tcpci_drp_toggle(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint8_t exp_tcpc_ctrl, exp_role_ctrl, initial_tcpc_ctrl;
+
+ /* Test error on failed role CTRL set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ROLE_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->drp_toggle(port), NULL);
+
+ /* Test error on failed TCPC CTRL set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TCPC_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->drp_toggle(port), NULL);
+
+ /* Test error on failed command set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_COMMAND);
+ zassert_equal(EC_ERROR_INVAL, drv->drp_toggle(port), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set initial value for TCPC ctrl register. Chosen arbitrary. */
+ initial_tcpc_ctrl = TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL |
+ TCPC_REG_TCPC_CTRL_BIST_TEST_MODE;
+ tcpci_emul_set_reg(emul, TCPC_REG_TCPC_CTRL, initial_tcpc_ctrl);
+
+ /*
+ * Test correct registers values for rev 2.0. Role control CC lines
+ * have to be set to RP with DRP enabled and smallest RP value.
+ */
+ exp_tcpc_ctrl = initial_tcpc_ctrl |
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT;
+ exp_role_ctrl = TCPC_REG_ROLE_CTRL_SET(TYPEC_DRP, TYPEC_RP_USB,
+ TYPEC_CC_RP, TYPEC_CC_RP);
+ zassert_equal(EC_SUCCESS, drv->drp_toggle(port), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_tcpc_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL, exp_role_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_LOOK4CONNECTION);
+
+ /* Set TCPCI to revision 1 */
+ tcpc_config[port].flags = 0;
+ tcpci_emul_set_rev(emul, TCPCI_EMUL_REV1_0_VER1_0);
+
+ /* Set initial value for TCPC ctrl register. Chosen arbitrary. */
+ initial_tcpc_ctrl = TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL |
+ TCPC_REG_TCPC_CTRL_BIST_TEST_MODE;
+ tcpci_emul_set_reg(emul, TCPC_REG_TCPC_CTRL, initial_tcpc_ctrl);
+
+ /*
+ * Test correct registers values for rev 1.0. Role control CC lines
+ * have to be set to RD with DRP enabled and smallest RP value.
+ * Only CC lines setting is different from rev 2.0
+ */
+ exp_tcpc_ctrl = initial_tcpc_ctrl |
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT;
+ exp_role_ctrl = TCPC_REG_ROLE_CTRL_SET(TYPEC_DRP, TYPEC_RP_USB,
+ TYPEC_CC_RD, TYPEC_CC_RD);
+ zassert_equal(EC_SUCCESS, drv->drp_toggle(port), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_tcpc_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_ROLE_CTRL, exp_role_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_COMMAND,
+ TCPC_REG_COMMAND_LOOK4CONNECTION);
+}
+
+/** Test TCPCI get chip info */
+void test_tcpci_get_chip_info(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ struct ec_response_pd_chip_info_v1 info;
+ uint16_t vendor, product, bcd;
+
+ /* Test error on failed vendor id get */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_VENDOR_ID);
+ zassert_equal(EC_ERROR_INVAL, drv->get_chip_info(port, 1, &info), NULL);
+
+ /* Test error on failed product id get */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_PRODUCT_ID);
+ zassert_equal(EC_ERROR_INVAL, drv->get_chip_info(port, 1, &info), NULL);
+
+ /* Test error on failed BCD get */
+ i2c_common_emul_set_read_fail_reg(common_data, TCPC_REG_VENDOR_ID);
+ zassert_equal(EC_ERROR_INVAL, drv->get_chip_info(port, 1, &info), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test reading chip info. Values chosen arbitrary. */
+ vendor = 0x1234;
+ product = 0x5678;
+ bcd = 0x9876;
+ tcpci_emul_set_reg(emul, TCPC_REG_VENDOR_ID, vendor);
+ tcpci_emul_set_reg(emul, TCPC_REG_PRODUCT_ID, product);
+ tcpci_emul_set_reg(emul, TCPC_REG_BCD_DEV, bcd);
+ zassert_equal(EC_SUCCESS, drv->get_chip_info(port, 1, &info), NULL);
+ zassert_equal(vendor, info.vendor_id, NULL);
+ zassert_equal(product, info.product_id, NULL);
+ zassert_equal(bcd, info.device_id, NULL);
+
+ /* Test reading cached chip info */
+ info.vendor_id = 0;
+ info.product_id = 0;
+ info.device_id = 0;
+ /* Make sure, that TCPC is not accessed */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ zassert_equal(EC_SUCCESS, drv->get_chip_info(port, 0, &info), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ zassert_equal(vendor, info.vendor_id, NULL);
+ zassert_equal(product, info.product_id, NULL);
+ zassert_equal(bcd, info.device_id, NULL);
+}
+
+/** Test TCPCI enter low power mode */
+void test_tcpci_low_power_mode(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+
+ /* Test error on failed command set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_COMMAND);
+ zassert_equal(EC_ERROR_INVAL, drv->enter_low_power_mode(port), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test correct command is issued */
+ zassert_equal(EC_SUCCESS, drv->enter_low_power_mode(port), NULL);
+ check_tcpci_reg(emul, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
+}
+
+/** Test TCPCI set bist test mode */
+void test_tcpci_set_bist_mode(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint16_t exp_mask, initial_mask;
+ uint8_t exp_ctrl, initial_ctrl;
+
+ /* Test error on TCPC CTRL set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_TCPC_CTRL);
+ zassert_equal(EC_ERROR_INVAL, drv->set_bist_test_mode(port, 1), NULL);
+
+ /* Test error on alert mask set */
+ i2c_common_emul_set_write_fail_reg(common_data, TCPC_REG_ALERT_MASK);
+ zassert_equal(EC_ERROR_INVAL, drv->set_bist_test_mode(port, 1), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Set initial value for alert mask register. Chosen arbitrary. */
+ initial_mask = TCPC_REG_ALERT_MASK_ALL;
+ tcpci_emul_set_reg(emul, TCPC_REG_ALERT_MASK, initial_mask);
+
+ /* Set initial value for TCPC ctrl register. Chosen arbitrary. */
+ initial_ctrl = TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL |
+ TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT;
+ tcpci_emul_set_reg(emul, TCPC_REG_TCPC_CTRL, initial_ctrl);
+
+ /* Test enabling bist test mode */
+ exp_mask = initial_mask & ~TCPC_REG_ALERT_RX_STATUS;
+ exp_ctrl = initial_ctrl | TCPC_REG_TCPC_CTRL_BIST_TEST_MODE;
+ zassert_equal(EC_SUCCESS, drv->set_bist_test_mode(port, 1), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+
+ /* Test disabling bist test mode */
+ exp_mask = initial_mask | TCPC_REG_ALERT_RX_STATUS;
+ exp_ctrl = initial_ctrl & ~TCPC_REG_TCPC_CTRL_BIST_TEST_MODE;
+ zassert_equal(EC_SUCCESS, drv->set_bist_test_mode(port, 0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_TCPC_CTRL, exp_ctrl);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, exp_mask);
+}
+
+void test_tcpci_hard_reset_reinit(const struct emul *emul,
+ struct i2c_common_emul_data *common_data,
+ enum usbc_port port)
+{
+ const struct tcpm_drv *drv = tcpc_config[port].drv;
+ uint16_t power_status_mask;
+ uint16_t alert_mask;
+
+ zassume_equal(EC_SUCCESS, drv->init(port), NULL);
+ tcpci_emul_get_reg(emul, TCPC_REG_POWER_STATUS_MASK,
+ &power_status_mask);
+ tcpci_emul_get_reg(emul, TCPC_REG_ALERT_MASK, &alert_mask);
+ zassert_ok(tcpci_hard_reset_reinit(USBC_PORT_C0), NULL);
+ check_tcpci_reg(emul, TCPC_REG_POWER_STATUS_MASK, power_status_mask);
+ check_tcpci_reg(emul, TCPC_REG_ALERT_MASK, alert_mask);
+}
diff --git a/zephyr/test/drivers/default/src/tcs3400.c b/zephyr/test/drivers/default/src/tcs3400.c
new file mode 100644
index 0000000000..860b069532
--- /dev/null
+++ b/zephyr/test/drivers/default/src/tcs3400.c
@@ -0,0 +1,641 @@
+/* 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 "common.h"
+#include "i2c.h"
+#include "emul/emul_tcs3400.h"
+#include "emul/emul_common_i2c.h"
+
+#include "motion_sense.h"
+#include "motion_sense_fifo.h"
+#include "driver/als_tcs3400.h"
+#include "test/drivers/test_state.h"
+
+#define TCS_NODE DT_NODELABEL(tcs_emul)
+#define TCS_CLR_SENSOR_ID SENSOR_ID(DT_NODELABEL(tcs3400_clear))
+#define TCS_RGB_SENSOR_ID SENSOR_ID(DT_NODELABEL(tcs3400_rgb))
+#define TCS_INT_EVENT \
+ TASK_EVENT_MOTION_SENSOR_INTERRUPT(SENSOR_ID(DT_ALIAS(tcs3400_int)))
+
+/** How accurate comparision of rgb sensors should be */
+#define V_EPS 8
+
+/** Test initialization of light sensor driver and device */
+ZTEST_USER(tcs3400, test_tcs_init)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcs3400_get_i2c_common_data(emul);
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* RGB sensor initialization is always successful */
+ zassert_equal(EC_SUCCESS, ms_rgb->drv->init(ms_rgb), NULL);
+
+ /* Fail init on communication errors */
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_FAIL_ALL_REG);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->init(ms), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Fail on bad ID */
+ tcs_emul_set_reg(emul, TCS_I2C_ID, 0);
+ zassert_equal(EC_ERROR_ACCESS_DENIED, ms->drv->init(ms), NULL);
+ /* Restore ID */
+ tcs_emul_set_reg(emul, TCS_I2C_ID,
+ DT_STRING_TOKEN(DT_NODELABEL(tcs_emul), device_id));
+
+ /* Test successful init. ATIME and AGAIN should be changed on init */
+ zassert_equal(EC_SUCCESS, ms->drv->init(ms), NULL);
+ zassert_equal(TCS_DEFAULT_ATIME, tcs_emul_get_reg(emul, TCS_I2C_ATIME),
+ NULL);
+ zassert_equal(TCS_DEFAULT_AGAIN,
+ tcs_emul_get_reg(emul, TCS_I2C_CONTROL), NULL);
+}
+
+/** Test if read function leaves device in correct mode to accuire data */
+ZTEST_USER(tcs3400, test_tcs_read)
+{
+ struct motion_sensor_t *ms;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcs3400_get_i2c_common_data(emul);
+ uint8_t enable;
+ intv3_t v;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+
+ /* Test error on writing registers */
+ i2c_common_emul_set_write_fail_reg(common_data, TCS_I2C_ATIME);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, v), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data, TCS_I2C_CONTROL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, v), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data, TCS_I2C_ENABLE);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->read(ms, v), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test starting read with calibration */
+ tcs_emul_set_reg(emul, TCS_I2C_ATIME, 0);
+ tcs_emul_set_reg(emul, TCS_I2C_CONTROL, 0);
+ tcs_emul_set_reg(emul, TCS_I2C_ENABLE, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL);
+ zassert_equal(TCS_CALIBRATION_ATIME,
+ tcs_emul_get_reg(emul, TCS_I2C_ATIME), NULL);
+ zassert_equal(TCS_CALIBRATION_AGAIN,
+ tcs_emul_get_reg(emul, TCS_I2C_CONTROL), NULL);
+ enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE);
+ zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL);
+
+ /* Test starting read without calibration */
+ tcs_emul_set_reg(emul, TCS_I2C_ATIME, 0);
+ tcs_emul_set_reg(emul, TCS_I2C_CONTROL, 0);
+ tcs_emul_set_reg(emul, TCS_I2C_ENABLE, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL);
+ enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE);
+ zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL);
+}
+
+/** Check if FIFO for RGB and clear sensor is empty */
+static void check_fifo_empty_f(struct motion_sensor_t *ms,
+ struct motion_sensor_t *ms_rgb, int line)
+{
+ struct ec_response_motion_sensor_data vector;
+ uint16_t size;
+
+ /* Read all data committed to FIFO */
+ while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) {
+ /* Ignore timestamp frames */
+ if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) {
+ continue;
+ }
+
+ if (ms - motion_sensors == vector.sensor_num) {
+ zassert_unreachable(
+ "Unexpected frame for clear sensor @line: %d",
+ line);
+ }
+
+ if (ms_rgb - motion_sensors == vector.sensor_num) {
+ zassert_unreachable(
+ "Unexpected frame for rgb sensor @line: %d",
+ line);
+ }
+ }
+}
+#define check_fifo_empty(ms, ms_rgb) check_fifo_empty_f(ms, ms_rgb, __LINE__)
+
+/**
+ * Test different conditions where irq handler fail or commit no data
+ * to fifo
+ */
+ZTEST_USER(tcs3400, test_tcs_irq_handler_fail)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcs3400_get_i2c_common_data(emul);
+ uint32_t event;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* Fail on wrong event */
+ event = 0x1234 & ~TCS_INT_EVENT;
+ zassert_equal(EC_ERROR_NOT_HANDLED, ms->drv->irq_handler(ms, &event),
+ NULL);
+ check_fifo_empty(ms, ms_rgb);
+
+ event = TCS_INT_EVENT;
+ /* Test error on reading status */
+ i2c_common_emul_set_read_fail_reg(common_data, TCS_I2C_STATUS);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ check_fifo_empty(ms, ms_rgb);
+
+ /* Test fail on changing device power state */
+ i2c_common_emul_set_write_fail_reg(common_data, TCS_I2C_ENABLE);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->irq_handler(ms, &event), NULL);
+ i2c_common_emul_set_write_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+ check_fifo_empty(ms, ms_rgb);
+
+ /* Test that no data is committed when status is 0 */
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS, 0);
+ zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL);
+ check_fifo_empty(ms, ms_rgb);
+}
+
+/**
+ * Check if last data committed to FIFO for RGB and clear sensor equals to
+ * expected value.
+ */
+static void check_fifo_f(struct motion_sensor_t *ms,
+ struct motion_sensor_t *ms_rgb, int *exp_v, int eps,
+ int line)
+{
+ struct ec_response_motion_sensor_data vector;
+ uint16_t size;
+ int ret_v[4] = { -1, -1, -1, -1 };
+ int i;
+
+ /* Read all data committed to FIFO */
+ while (motion_sense_fifo_read(sizeof(vector), 1, &vector, &size)) {
+ /* Ignore timestamp frames */
+ if (vector.flags == MOTIONSENSE_SENSOR_FLAG_TIMESTAMP) {
+ continue;
+ }
+
+ /* Get clear frame */
+ if (ms - motion_sensors == vector.sensor_num) {
+ ret_v[0] = vector.udata[0];
+ }
+
+ /* Get rgb frame */
+ if (ms_rgb - motion_sensors == vector.sensor_num) {
+ ret_v[1] = vector.udata[0];
+ ret_v[2] = vector.udata[1];
+ ret_v[3] = vector.udata[2];
+ }
+ }
+
+ if (ret_v[0] == -1) {
+ zassert_unreachable("No frame for clear sensor, line %d", line);
+ }
+
+ if (ret_v[1] == -1) {
+ zassert_unreachable("No frame for rgb sensor, line %d", line);
+ }
+
+ /* Compare with last committed data */
+ for (i = 0; i < 4; i++) {
+ zassert_within(
+ exp_v[i], ret_v[i], eps,
+ "Expected [%d; %d; %d; %d], got [%d; %d; %d; %d]; line: %d",
+ exp_v[0], exp_v[1], exp_v[2], exp_v[3], ret_v[0],
+ ret_v[1], ret_v[2], ret_v[3], line);
+ }
+}
+#define check_fifo(ms, ms_rgb, exp_v, eps) \
+ check_fifo_f(ms, ms_rgb, exp_v, eps, __LINE__)
+
+/** Test calibration mode reading of light sensor values */
+ZTEST_USER(tcs3400, test_tcs_read_calibration)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ uint32_t event = TCS_INT_EVENT;
+ int emul_v[4];
+ int exp_v[4];
+ intv3_t v;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* Need to be set to collect all data in FIFO */
+ ms->oversampling_ratio = 1;
+ ms_rgb->oversampling_ratio = 1;
+ /* Enable calibration mode */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 1), NULL);
+ /* Setup AGAIN and ATIME for calibration */
+ zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL);
+
+ /* Test data that are in calibration range */
+ exp_v[0] = 12;
+ exp_v[1] = 123;
+ exp_v[2] = 1234;
+ exp_v[3] = 12345;
+ /*
+ * Emulator value is with gain 64, while expected value is
+ * with gain 16
+ */
+ emul_v[0] = exp_v[0] * 64 / 16;
+ emul_v[1] = exp_v[1] * 64 / 16;
+ emul_v[2] = exp_v[2] * 64 / 16;
+ emul_v[3] = exp_v[3] * 64 / 16;
+ tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]);
+ tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]);
+ tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]);
+ tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]);
+ /* Set status to show valid data */
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS, TCS_I2C_STATUS_RGBC_VALID);
+
+ zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL);
+ /* In calibration mode check for exact match */
+ check_fifo(ms, ms_rgb, exp_v, 1);
+
+ /* Test data that are outside of calibration range */
+ exp_v[0] = 0;
+ exp_v[1] = UINT16_MAX;
+ exp_v[2] = UINT16_MAX;
+ exp_v[3] = 213;
+ /*
+ * Emulator value is with gain 64, while expected value is
+ * with gain 16
+ */
+ emul_v[0] = 0;
+ emul_v[1] = exp_v[1] * 64 / 16;
+ emul_v[2] = (UINT16_MAX + 23) * 64 / 16;
+ emul_v[3] = exp_v[3] * 64 / 16;
+ tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]);
+ tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]);
+ tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]);
+ tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]);
+ /* Set status to show valid data */
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS, TCS_I2C_STATUS_RGBC_VALID);
+
+ zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event), NULL);
+ /* In calibration mode check for exact match */
+ check_fifo(ms, ms_rgb, exp_v, 1);
+}
+
+/**
+ * Set emulator internal value using expected output value returned by
+ * the driver. First element of expected vector is IR value used in
+ * calculations. Based on that clear light value is calculated.
+ * First element of expected vector is updated by this function.
+ */
+static void set_emul_val_from_exp(int *exp_v, uint16_t *scale,
+ const struct emul *emul)
+{
+ int emul_v[4];
+ int ir;
+
+ /* We use exp_v[0] as IR value */
+ ir = exp_v[0];
+ /* Driver will return lux value as calculated blue light value */
+ exp_v[0] = exp_v[2];
+
+ /*
+ * Driver takes care of different ATIME and AGAIN value, so expected
+ * value is always normalized to ATIME 256 and AGAIN 16. Convert it
+ * to internal emulator value (ATIME 256, AGAIN 64) and add expected IR
+ * value. Clear light is the sum of rgb light and IR component.
+ */
+ emul_v[1] = (exp_v[1] + ir) * 64 / 16;
+ emul_v[2] = (exp_v[2] + ir) * 64 / 16;
+ emul_v[3] = (exp_v[3] + ir) * 64 / 16;
+ emul_v[0] = (exp_v[1] + exp_v[2] + exp_v[3] + ir) * 64 / 16;
+
+ /* Apply scale, driver should divide by this value */
+ emul_v[0] = SENSOR_APPLY_SCALE(emul_v[0], scale[0]);
+ emul_v[1] = SENSOR_APPLY_SCALE(emul_v[1], scale[1]);
+ emul_v[2] = SENSOR_APPLY_SCALE(emul_v[2], scale[2]);
+ emul_v[3] = SENSOR_APPLY_SCALE(emul_v[3], scale[3]);
+
+ /* Set emulator values */
+ tcs_emul_set_val(emul, TCS_EMUL_C, emul_v[0]);
+ tcs_emul_set_val(emul, TCS_EMUL_R, emul_v[1]);
+ tcs_emul_set_val(emul, TCS_EMUL_G, emul_v[2]);
+ tcs_emul_set_val(emul, TCS_EMUL_B, emul_v[3]);
+}
+
+/** Test normal mode reading of light sensor values */
+ZTEST_USER(tcs3400, test_tcs_read_xyz)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ uint32_t event = TCS_INT_EVENT;
+ /* Expected data to test: IR, R, G, B */
+ int exp_v[][4] = {
+ { 200, 1110, 870, 850 }, { 300, 1110, 10000, 8500 },
+ { 600, 50000, 40000, 30000 }, { 1000, 3000, 40000, 2000 },
+ { 1000, 65000, 65000, 65000 }, { 100, 214, 541, 516 },
+ { 143, 2141, 5414, 5163 }, { 100, 50000, 40000, 30000 },
+ { 1430, 2141, 5414, 5163 }, { 10000, 50000, 40000, 30000 },
+ { 10000, 214, 541, 516 }, { 15000, 50000, 40000, 30000 },
+ };
+ uint16_t scale[4] = { MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE };
+ int i, test;
+ intv3_t v;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* Need to be set to collect all data in FIFO */
+ ms->oversampling_ratio = 1;
+ ms_rgb->oversampling_ratio = 1;
+ /* Disable calibration mode */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ /* Setup AGAIN and ATIME for normal mode */
+ zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL);
+
+ /* Test different data in supported range */
+ for (test = 0; test < ARRAY_SIZE(exp_v); test++) {
+ set_emul_val_from_exp(exp_v[test], scale, emul);
+
+ /* Run few times to allow driver change gain */
+ for (i = 0; i < 5; i++) {
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS,
+ TCS_I2C_STATUS_RGBC_VALID);
+ zassert_equal(EC_SUCCESS,
+ ms->drv->irq_handler(ms, &event), NULL);
+ }
+ check_fifo(ms, ms_rgb, exp_v[test], V_EPS);
+ }
+
+ /* Test data that are outside of supported range */
+ exp_v[0][0] = 3000;
+ exp_v[0][1] = UINT16_MAX;
+ exp_v[0][2] = UINT16_MAX * 32;
+ exp_v[0][3] = 200;
+ set_emul_val_from_exp(exp_v[0], scale, emul);
+
+ /* Run few times to allow driver change gain */
+ for (i = 0; i < 10; i++) {
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS,
+ TCS_I2C_STATUS_RGBC_VALID);
+ zassert_equal(EC_SUCCESS, ms->drv->irq_handler(ms, &event),
+ NULL);
+ }
+ /*
+ * If saturation value is exceeded on any rgb sensor, than data
+ * shouldn't be committed to FIFO.
+ */
+ check_fifo_empty(ms, ms_rgb);
+}
+
+/**
+ * Test getting and setting scale of light sensor. Checks if collected values
+ * are scaled properly.
+ */
+ZTEST_USER(tcs3400, test_tcs_scale)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ uint32_t event = TCS_INT_EVENT;
+ /* Expected data to test: IR, R, G, B */
+ int exp_v[][4] = {
+ { 200, 1110, 870, 850 }, { 300, 1110, 10000, 8500 },
+ { 600, 5000, 4000, 3000 }, { 100, 3000, 4000, 2000 },
+ { 100, 1000, 1000, 1000 },
+ };
+ /* Scale for each test */
+ uint16_t exp_scale[][4] = {
+ { MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE },
+ { MOTION_SENSE_DEFAULT_SCALE + 300,
+ MOTION_SENSE_DEFAULT_SCALE + 300,
+ MOTION_SENSE_DEFAULT_SCALE + 300,
+ MOTION_SENSE_DEFAULT_SCALE + 300 },
+ { MOTION_SENSE_DEFAULT_SCALE - 300,
+ MOTION_SENSE_DEFAULT_SCALE - 300,
+ MOTION_SENSE_DEFAULT_SCALE - 300,
+ MOTION_SENSE_DEFAULT_SCALE - 300 },
+ { MOTION_SENSE_DEFAULT_SCALE + 345,
+ MOTION_SENSE_DEFAULT_SCALE - 5423,
+ MOTION_SENSE_DEFAULT_SCALE - 30,
+ MOTION_SENSE_DEFAULT_SCALE + 400 },
+ { MOTION_SENSE_DEFAULT_SCALE - 345,
+ MOTION_SENSE_DEFAULT_SCALE + 5423,
+ MOTION_SENSE_DEFAULT_SCALE + 30,
+ MOTION_SENSE_DEFAULT_SCALE - 400 },
+ { MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE,
+ MOTION_SENSE_DEFAULT_SCALE, MOTION_SENSE_DEFAULT_SCALE }
+ };
+ uint16_t scale[3];
+ int16_t temp;
+ int i, test;
+ intv3_t v;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* Need to be set to collect all data in FIFO */
+ ms->oversampling_ratio = 1;
+ ms_rgb->oversampling_ratio = 1;
+ /* Disable calibration mode */
+ zassert_equal(EC_SUCCESS, ms->drv->perform_calib(ms, 0), NULL);
+ /* Setup AGAIN and ATIME for normal mode */
+ zassert_equal(EC_RES_IN_PROGRESS, ms->drv->read(ms, v), NULL);
+
+ /* Test different data in supported range */
+ for (test = 0; test < ARRAY_SIZE(exp_v); test++) {
+ /* Set and test clear sensor scale */
+ zassert_equal(EC_SUCCESS,
+ ms->drv->set_scale(ms, exp_scale[test], 0),
+ "test %d", test);
+ zassert_equal(EC_SUCCESS, ms->drv->get_scale(ms, scale, &temp),
+ "test %d", test);
+ zassert_equal((int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, temp,
+ "test %d, %d", test, temp);
+ zassert_equal(exp_scale[test][0], scale[0], "test %d", test);
+
+ /* Set and test RGB sensor scale */
+ zassert_equal(EC_SUCCESS,
+ ms_rgb->drv->set_scale(ms_rgb,
+ &(exp_scale[test][1]), 0),
+ "test %d", test);
+ zassert_equal(EC_SUCCESS,
+ ms_rgb->drv->get_scale(ms_rgb, scale, &temp),
+ "test %d", test);
+ zassert_equal((int16_t)EC_MOTION_SENSE_INVALID_CALIB_TEMP, temp,
+ "test %d", test);
+ zassert_equal(exp_scale[test][1], scale[0], "test %d", test);
+ zassert_equal(exp_scale[test][2], scale[1], "test %d", test);
+ zassert_equal(exp_scale[test][3], scale[2], "test %d", test);
+
+ set_emul_val_from_exp(exp_v[test], exp_scale[test], emul);
+
+ /* Run few times to allow driver change gain */
+ for (i = 0; i < 5; i++) {
+ tcs_emul_set_reg(emul, TCS_I2C_STATUS,
+ TCS_I2C_STATUS_RGBC_VALID);
+ zassert_equal(EC_SUCCESS,
+ ms->drv->irq_handler(ms, &event), NULL);
+ }
+ check_fifo(ms, ms_rgb, exp_v[test], V_EPS);
+ }
+
+ /* Test fail if scale equals 0 */
+ scale[0] = 0;
+ scale[1] = MOTION_SENSE_DEFAULT_SCALE;
+ scale[2] = MOTION_SENSE_DEFAULT_SCALE;
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_scale(ms, scale, 0), NULL);
+
+ zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0),
+ NULL);
+ scale[0] = MOTION_SENSE_DEFAULT_SCALE;
+ scale[1] = 0;
+ scale[2] = MOTION_SENSE_DEFAULT_SCALE;
+ zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0),
+ NULL);
+ scale[0] = MOTION_SENSE_DEFAULT_SCALE;
+ scale[1] = MOTION_SENSE_DEFAULT_SCALE;
+ scale[2] = 0;
+ zassert_equal(EC_ERROR_INVAL, ms_rgb->drv->set_scale(ms_rgb, scale, 0),
+ NULL);
+}
+
+/** Test setting and getting data rate of light sensor */
+ZTEST_USER(tcs3400, test_tcs_data_rate)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+ const struct emul *emul = EMUL_DT_GET(TCS_NODE);
+ struct i2c_common_emul_data *common_data =
+ emul_tcs3400_get_i2c_common_data(emul);
+ uint8_t enable;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ /* RGB sensor doesn't set rate, but return rate of clear sesnor */
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* Test fail on reading device power state */
+ i2c_common_emul_set_read_fail_reg(common_data, TCS_I2C_ENABLE);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 0, 0), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 0, 1), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 100, 0), NULL);
+ zassert_equal(EC_ERROR_INVAL, ms->drv->set_data_rate(ms, 100, 1), NULL);
+ i2c_common_emul_set_read_fail_reg(common_data,
+ I2C_COMMON_EMUL_NO_FAIL_REG);
+
+ /* Test setting 0 rate disables device */
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 0), NULL);
+ zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL);
+ zassert_equal(0, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(0, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 0, 1), NULL);
+ zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL);
+ zassert_equal(0, tcs_emul_get_reg(emul, TCS_I2C_ENABLE), NULL);
+ zassert_equal(0, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(0, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+
+ /* Test setting non-zero rate enables device */
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 100, 0), NULL);
+ enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE);
+ zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL);
+ zassert_equal(100, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_data_rate(ms, 100, 1), NULL);
+ enable = tcs_emul_get_reg(emul, TCS_I2C_ENABLE);
+ zassert_true(enable & TCS_I2C_ENABLE_POWER_ON, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_ADC_ENABLE, NULL);
+ zassert_true(enable & TCS_I2C_ENABLE_INT_ENABLE, NULL);
+ zassert_equal(100, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+
+ /* Test RGB sensor doesn't change data rate */
+ zassert_equal(EC_SUCCESS, ms_rgb->drv->set_data_rate(ms_rgb, 300, 0),
+ NULL);
+ zassert_equal(100, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+
+ zassert_equal(EC_SUCCESS, ms_rgb->drv->set_data_rate(ms_rgb, 300, 1),
+ NULL);
+ zassert_equal(100, ms->drv->get_data_rate(ms), NULL);
+ zassert_equal(100, ms_rgb->drv->get_data_rate(ms_rgb), NULL);
+}
+
+/** Test set range function of clear and RGB sensors */
+ZTEST_USER(tcs3400, test_tcs_set_range)
+{
+ struct motion_sensor_t *ms, *ms_rgb;
+
+ ms = &motion_sensors[TCS_CLR_SENSOR_ID];
+ ms_rgb = &motion_sensors[TCS_RGB_SENSOR_ID];
+
+ /* RGB sensor doesn't set anything */
+ zassert_equal(EC_SUCCESS, ms_rgb->drv->set_range(ms_rgb, 1, 0), NULL);
+
+ /* Clear sensor doesn't change anything on device to set range */
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 0x12300, 1), NULL);
+ zassert_equal(0x12300, ms->current_range, NULL);
+
+ zassert_equal(EC_SUCCESS, ms->drv->set_range(ms, 0x10000, 0), NULL);
+ zassert_equal(0x10000, ms->current_range, NULL);
+}
+
+struct tcs3400_test_fixture {
+ struct als_drv_data_t drv_data;
+ struct tcs3400_rgb_drv_data_t rgb_drv_data;
+};
+
+static void tcs3400_before(void *state)
+{
+ struct tcs3400_test_fixture *f = state;
+
+ f->drv_data = *TCS3400_DRV_DATA(&motion_sensors[TCS_CLR_SENSOR_ID]);
+ f->rgb_drv_data =
+ *TCS3400_RGB_DRV_DATA(&motion_sensors[TCS_RGB_SENSOR_ID]);
+}
+
+static void tcs3400_after(void *state)
+{
+ struct tcs3400_test_fixture *f = state;
+
+ *TCS3400_DRV_DATA(&motion_sensors[TCS_CLR_SENSOR_ID]) = f->drv_data;
+ *TCS3400_RGB_DRV_DATA(&motion_sensors[TCS_RGB_SENSOR_ID]) =
+ f->rgb_drv_data;
+}
+
+static void *tcs3400_setup(void)
+{
+ static struct tcs3400_test_fixture tcs3400_fixture = { 0 };
+
+ return &tcs3400_fixture;
+}
+
+ZTEST_SUITE(tcs3400, drivers_predicate_post_main, tcs3400_setup, tcs3400_before,
+ tcs3400_after, NULL);
diff --git a/zephyr/test/drivers/default/src/temp_sensor.c b/zephyr/test/drivers/default/src/temp_sensor.c
new file mode 100644
index 0000000000..5caecc556c
--- /dev/null
+++ b/zephyr/test/drivers/default/src/temp_sensor.c
@@ -0,0 +1,200 @@
+/* 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/adc.h>
+#include <zephyr/drivers/adc/adc_emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+
+#include <math.h>
+
+#include "common.h"
+#include "temp_sensor.h"
+#include "temp_sensor/temp_sensor.h"
+#include "test/drivers/test_state.h"
+
+#define GPIO_PG_EC_DSW_PWROK_PATH DT_PATH(named_gpios, pg_ec_dsw_pwrok)
+#define GPIO_PG_EC_DSW_PWROK_PORT DT_GPIO_PIN(GPIO_PG_EC_DSW_PWROK_PATH, gpios)
+
+#define GPIO_EC_PG_PIN_TEMP_PATH DT_PATH(named_gpios, ec_pg_pin_temp)
+#define GPIO_EC_PG_PIN_TEMP_PORT DT_GPIO_PIN(GPIO_EC_PG_PIN_TEMP_PATH, gpios)
+
+#define ADC_DEVICE_NODE DT_NODELABEL(adc0)
+#define ADC_CHANNELS_NUM DT_PROP(DT_NODELABEL(adc0), nchannels)
+
+/** Test error code when invalid sensor is passed to temp_sensor_read() */
+ZTEST_USER(temp_sensor, test_temp_sensor_wrong_id)
+{
+ int temp;
+
+ zassert_equal(EC_ERROR_INVAL,
+ temp_sensor_read(TEMP_SENSOR_COUNT, &temp), NULL);
+}
+
+/** Test error code when temp_sensor_read() is called with powered off ADC */
+ZTEST_USER(temp_sensor, test_temp_sensor_adc_error)
+{
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_PG_EC_DSW_PWROK_PATH, gpios));
+ int temp;
+
+ zassert_not_null(gpio_dev, "Cannot get GPIO device");
+
+ /*
+ * pg_ec_dsw_pwrok = 0 means ADC is not powered.
+ * adc_read will return error
+ */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_PG_EC_DSW_PWROK_PORT, 0),
+ NULL);
+
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(
+ TEMP_SENSOR_ID(DT_NODELABEL(named_temp_charger)),
+ &temp),
+ NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(
+ TEMP_SENSOR_ID(DT_NODELABEL(named_temp_ddr_soc)),
+ &temp),
+ NULL);
+ zassert_equal(
+ EC_ERROR_NOT_POWERED,
+ temp_sensor_read(TEMP_SENSOR_ID(DT_NODELABEL(named_temp_fan)),
+ &temp),
+ NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(TEMP_SENSOR_ID(DT_NODELABEL(
+ named_temp_pp3300_regulator)),
+ &temp),
+ NULL);
+
+ /* power ADC */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_PG_EC_DSW_PWROK_PORT, 1),
+ NULL);
+}
+
+/** Test error code when temp_sensor_read() is called power-good-pin low */
+ZTEST_USER(temp_sensor, test_temp_sensor_pg_pin)
+{
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_EC_PG_PIN_TEMP_PATH, gpios));
+ int temp;
+
+ zassert_not_null(gpio_dev, "Cannot get GPIO device");
+
+ /* ec_pg_pin_temp = 0 means temperature sensors are not powered. */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_EC_PG_PIN_TEMP_PORT, 0),
+ NULL);
+
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(
+ TEMP_SENSOR_ID(DT_NODELABEL(named_temp_charger)),
+ &temp),
+ NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(
+ TEMP_SENSOR_ID(DT_NODELABEL(named_temp_ddr_soc)),
+ &temp),
+ NULL);
+ zassert_equal(
+ EC_ERROR_NOT_POWERED,
+ temp_sensor_read(TEMP_SENSOR_ID(DT_NODELABEL(named_temp_fan)),
+ &temp),
+ NULL);
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ temp_sensor_read(TEMP_SENSOR_ID(DT_NODELABEL(
+ named_temp_pp3300_regulator)),
+ &temp),
+ NULL);
+
+ /* power ADC */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_EC_PG_PIN_TEMP_PORT, 1),
+ NULL);
+}
+
+/** Simple ADC emulator custom function which always return error */
+static int adc_error_func(const struct device *dev, unsigned int channel,
+ void *param, uint32_t *result)
+{
+ return -EINVAL;
+}
+
+/**
+ * Set valid response only for ADC channel connected with tested sensor.
+ * Check if temp_sensor_read() from tested sensor returns EC_SUCCESS and
+ * valid temperature. Set invalid response on ADC channel for next test.
+ */
+static void check_valid_temperature(const struct device *adc_dev, int sensor)
+{
+ int temp;
+
+ /* ADC channel of tested sensor return valid value */
+ zassert_ok(adc_emul_const_value_set(adc_dev, temp_sensors[sensor].idx,
+ 1000),
+ "adc_emul_const_value_set() failed (sensor %d)", sensor);
+ zassert_equal(EC_SUCCESS, temp_sensor_read(sensor, &temp), NULL);
+ zassert_within(
+ temp, 273 + 50, 51,
+ "Expected temperature in 0*C-100*C, got %d*C (sensor %d)",
+ temp - 273, sensor);
+ /* Return error on ADC channel of tested sensor */
+ zassert_ok(adc_emul_value_func_set(adc_dev, temp_sensors[sensor].idx,
+ adc_error_func, NULL),
+ "adc_emul_value_func_set() failed (sensor %d)", sensor);
+}
+
+/** Test if temp_sensor_read() returns temperature on success */
+ZTEST_USER(temp_sensor, test_temp_sensor_read)
+{
+ const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
+ int chan;
+
+ zassert_not_null(adc_dev, "Cannot get ADC device");
+
+ /* Return error on all ADC channels */
+ for (chan = 0; chan < ADC_CHANNELS_NUM; chan++) {
+ zassert_ok(adc_emul_value_func_set(adc_dev, chan,
+ adc_error_func, NULL),
+ "channel %d adc_emul_value_func_set() failed", chan);
+ }
+
+ check_valid_temperature(
+ adc_dev, TEMP_SENSOR_ID(DT_NODELABEL(named_temp_charger)));
+ check_valid_temperature(
+ adc_dev, TEMP_SENSOR_ID(DT_NODELABEL(named_temp_ddr_soc)));
+ check_valid_temperature(adc_dev,
+ TEMP_SENSOR_ID(DT_NODELABEL(named_temp_fan)));
+ check_valid_temperature(adc_dev, TEMP_SENSOR_ID(DT_NODELABEL(
+ named_temp_pp3300_regulator)));
+
+ /* Return correct value on all ADC channels */
+ for (chan = 0; chan < ADC_CHANNELS_NUM; chan++) {
+ zassert_ok(adc_emul_const_value_set(adc_dev, chan, 1000),
+ "channel %d adc_emul_const_value_set() failed",
+ chan);
+ }
+}
+
+static void *temp_sensor_setup(void)
+{
+ const struct device *dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_PG_EC_DSW_PWROK_PATH, gpios));
+ const struct device *dev_pin =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_EC_PG_PIN_TEMP_PATH, gpios));
+
+ zassert_not_null(dev, NULL);
+ /* Before tests make sure that power pins are set. */
+ zassert_ok(gpio_emul_input_set(dev, GPIO_PG_EC_DSW_PWROK_PORT, 1),
+ NULL);
+ zassert_ok(gpio_emul_input_set(dev_pin, GPIO_EC_PG_PIN_TEMP_PORT, 1),
+ NULL);
+
+ return NULL;
+}
+
+ZTEST_SUITE(temp_sensor, drivers_predicate_post_main, temp_sensor_setup, NULL,
+ NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/thermistor.c b/zephyr/test/drivers/default/src/thermistor.c
new file mode 100644
index 0000000000..417b482d99
--- /dev/null
+++ b/zephyr/test/drivers/default/src/thermistor.c
@@ -0,0 +1,327 @@
+/* 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/adc.h>
+#include <zephyr/drivers/adc/adc_emul.h>
+#include <zephyr/drivers/gpio.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <temp_sensor.h>
+
+#include "common.h"
+#include "../driver/temp_sensor/thermistor.h"
+#include "temp_sensor/temp_sensor.h"
+#include "test/drivers/test_state.h"
+
+#define GPIO_PG_EC_DSW_PWROK_PATH DT_PATH(named_gpios, pg_ec_dsw_pwrok)
+#define GPIO_PG_EC_DSW_PWROK_PORT DT_GPIO_PIN(GPIO_PG_EC_DSW_PWROK_PATH, gpios)
+
+#define GPIO_EC_PG_PIN_TEMP_PATH DT_PATH(named_gpios, ec_pg_pin_temp)
+#define GPIO_EC_PG_PIN_TEMP_PORT DT_GPIO_PIN(GPIO_EC_PG_PIN_TEMP_PATH, gpios)
+
+#define ADC_DEVICE_NODE DT_NODELABEL(adc0)
+
+/* TODO replace counting macros with DT macro when
+ * https://github.com/zephyrproject-rtos/zephyr/issues/38715 lands
+ */
+#define _ACCUMULATOR(x) 1 +
+#define NAMED_TEMP_SENSORS_SIZE \
+ DT_FOREACH_CHILD(TEMP_SENSORS_NODEID, _ACCUMULATOR) 0
+
+#define TEMP_SENSORS_ENABLED_SIZE FOREACH_TEMP_SENSOR(_ACCUMULATOR) 0
+
+/* Conversion of temperature doesn't need to be 100% accurate */
+#define TEMP_EPS 2
+
+#define A_VALID_VOLTAGE 1000
+/**
+ * Test if get temp function return expected error when ADC is not powered
+ * (indicated as GPIO pin set to low) and return success after powering on ADC.
+ */
+ZTEST_USER(thermistor, test_thermistor_power_pin)
+{
+ int temp;
+ int sensor_idx;
+
+ const struct device *gpio_dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_PG_EC_DSW_PWROK_PATH, gpios));
+ const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
+
+ zassert_not_null(gpio_dev, "Cannot get GPIO device");
+ zassert_not_null(adc_dev, "Cannot get ADC device");
+
+ /* Make sure that ADC return a valid value */
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ const struct temp_sensor_t *sensor = &temp_sensors[sensor_idx];
+
+ zassert_ok(adc_emul_const_value_set(adc_dev, sensor->idx,
+ A_VALID_VOLTAGE),
+ "adc_emul_value_func_set() failed on %s",
+ sensor->name);
+ }
+
+ /* pg_ec_dsw_pwrok = 0 means ADC is not powered. */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_PG_EC_DSW_PWROK_PORT, 0),
+ NULL);
+
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ const struct temp_sensor_t *sensor = &temp_sensors[sensor_idx];
+
+ zassert_equal(EC_ERROR_NOT_POWERED,
+ sensor->zephyr_info->read(sensor, &temp),
+ "%s failed", sensor->name);
+ }
+
+ /* pg_ec_dsw_pwrok = 1 means ADC is powered. */
+ zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_PG_EC_DSW_PWROK_PORT, 1),
+ NULL);
+
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ const struct temp_sensor_t *sensor = &temp_sensors[sensor_idx];
+
+ zassert_equal(EC_SUCCESS,
+ sensor->zephyr_info->read(sensor, &temp),
+ "%s failed", sensor->name);
+ }
+}
+
+/* Simple ADC emulator custom function which always return error */
+static int adc_error_func(const struct device *dev, unsigned int channel,
+ void *param, uint32_t *result)
+{
+ return -EINVAL;
+}
+
+/** Test if get temp function return expected error on ADC malfunction */
+ZTEST_USER(thermistor, test_thermistor_adc_read_error)
+{
+ int temp;
+ int sensor_idx;
+
+ const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
+
+ zassert_not_null(adc_dev, "Cannot get ADC device");
+
+ /* Return error on all ADC channels */
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ const struct temp_sensor_t *sensor = &temp_sensors[sensor_idx];
+
+ zassert_ok(adc_emul_value_func_set(adc_dev, sensor->idx,
+ adc_error_func, NULL),
+ "adc_emul_value_func_set() failed on %s",
+ sensor->name);
+ }
+
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ const struct temp_sensor_t *sensor = &temp_sensors[sensor_idx];
+
+ zassert_equal(EC_ERROR_UNKNOWN,
+ sensor->zephyr_info->read(sensor, &temp),
+ "%s failed", sensor->name);
+ }
+}
+
+/** Get resistance of thermistor for given temperature */
+static int resistance_47kohm_B4050(int t)
+{
+ /* Thermistor manufacturer resistance lookup table*/
+ int r_table[] = {
+ 155700, 147900, 140600, 133700, 127200, /* 0*C - 4*C */
+ 121000, 115100, 109600, 104300, 99310, /* 5*C - 9*C */
+ 94600, 90130, 85890, 81870, 78070, /* 10*C - 14*C */
+ 74450, 71020, 67770, 64680, 61750, /* 15*C - 19*C */
+ 58970, 56320, 53810, 51430, 49160, /* 20*C - 24*C */
+ 47000, 44950, 42990, 41130, 39360, /* 25*C - 29*C */
+ 37680, 36070, 34540, 33080, 31690, /* 30*C - 34*C */
+ 30360, 29100, 27900, 26750, 25650, /* 35*C - 39*C */
+ 24610, 23610, 22660, 21750, 20880, /* 40*C - 44*C */
+ 20050, 19260, 18500, 17780, 17090, /* 45*C - 49*C */
+ 16430, 15800, 15200, 14620, 14070, /* 50*C - 54*C */
+ 13540, 13030, 12550, 12090, 11640, /* 55*C - 59*C */
+ 11210, 10800, 10410, 10040, 9676, /* 60*C - 64*C */
+ 9331, 8999, 8680, 8374, 8081, /* 65*C - 69*C */
+ 7799, 7528, 7268, 7018, 6777, /* 70*C - 74*C */
+ 6546, 6324, 6111, 5906, 5708, /* 75*C - 79*C */
+ 5518, 5335, 5160, 4990, 4827, /* 80*C - 84*C */
+ 4671, 4519, 4374, 4233, 4098, /* 85*C - 89*C */
+ 3968, 3842, 3721, 3605, 3492, /* 90*C - 94*C */
+ 3384, 3279, 3179, 3082, 2988, /* 95*C - 99*C */
+ 2898 /* 100*C */
+ };
+
+ t -= 273;
+ if (t < 0)
+ return r_table[0] + 10000;
+
+ if (t >= ARRAY_SIZE(r_table))
+ return r_table[ARRAY_SIZE(r_table) - 1] - 100;
+
+ return r_table[t];
+}
+
+/**
+ * Calculate output voltage in voltage divider circuit using formula
+ * Vout = Vs * r2 / (r1 + r2)
+ */
+static int volt_divider(int vs, int r1, int r2)
+{
+ return vs * r2 / (r1 + r2);
+}
+
+struct thermistor_state {
+ const int v;
+ const int r;
+ int temp_expected;
+};
+
+/** ADC emulator function which calculate output voltage for given thermistor */
+static int adc_temperature_func(const struct device *dev, unsigned int channel,
+ void *param, uint32_t *result)
+{
+ struct thermistor_state *s = (struct thermistor_state *)param;
+
+ *result = volt_divider(s->v, s->r,
+ resistance_47kohm_B4050(s->temp_expected));
+
+ return 0;
+}
+
+/** Test conversion from ADC raw value to temperature */
+static void do_thermistor_test(const struct temp_sensor_t *temp_sensor,
+ int reference_mv, int reference_ohms)
+{
+ int temp_expected;
+ int temp;
+
+ const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
+ struct thermistor_state state = {
+ .v = reference_mv,
+ .r = reference_ohms,
+ };
+
+ zassert_not_null(adc_dev, "Cannot get ADC device");
+
+ /* Setup ADC channel */
+ zassert_ok(adc_emul_value_func_set(adc_dev, temp_sensor->idx,
+ adc_temperature_func, &state),
+ "adc_emul_value_func_set() failed on %s", temp_sensor->name);
+
+ /* Makes sure that reference voltage is correct for given thermistor */
+ zassert_ok(adc_emul_ref_voltage_set(adc_dev, ADC_REF_INTERNAL, state.v),
+ "adc_emul_ref_voltage_set() failed %s on ",
+ temp_sensor->name);
+
+ /* Test whole supported range from 0*C to 100*C (273*K to 373*K) */
+ for (temp_expected = 273; temp_expected <= 373; temp_expected++) {
+ state.temp_expected = temp_expected;
+ zassert_equal(EC_SUCCESS,
+ temp_sensor->zephyr_info->read(temp_sensor,
+ &temp),
+ "failed on %s", temp_sensor->name);
+ zassert_within(temp_expected, temp, TEMP_EPS,
+ "Expected %d*K, got %d*K on %s", temp_expected,
+ temp, temp_sensor->name);
+ }
+
+ /* Temperatures below 0*C should be reported as 0*C */
+ state.temp_expected = -15 + 273;
+ zassert_equal(EC_SUCCESS,
+ temp_sensor->zephyr_info->read(temp_sensor, &temp),
+ "failed on %s", temp_sensor->name);
+ zassert_equal(273, temp, "Expected %d*K, got %d*K on %s", 273, temp,
+ temp_sensor->name);
+
+ /* Temperatures above 100*C should be reported as 100*C */
+ state.temp_expected = 115 + 273;
+ zassert_equal(EC_SUCCESS,
+ temp_sensor->zephyr_info->read(temp_sensor, &temp),
+ "failed on %s", temp_sensor->name);
+ zassert_equal(373, temp, "Expected %d*K, got %d*K on %s", 373, temp,
+ temp_sensor->name);
+}
+
+#define GET_THERMISTOR_REF_MV(node_id) \
+ [TEMP_SENSOR_ID_BY_DEV(node_id)] = DT_PROP( \
+ DT_PHANDLE(node_id, thermistor), steinhart_reference_mv),
+
+#define GET_THERMISTOR_REF_RES(node_id) \
+ [TEMP_SENSOR_ID_BY_DEV(node_id)] = DT_PROP( \
+ DT_PHANDLE(node_id, thermistor), steinhart_reference_res),
+
+ZTEST_USER(thermistor, test_thermistors_adc_temperature_conversion)
+{
+ int sensor_idx;
+
+ const static int reference_mv_arr[] = { DT_FOREACH_STATUS_OKAY(
+ THERMISTOR_COMPAT, GET_THERMISTOR_REF_MV) };
+ const static int reference_res_arr[] = { DT_FOREACH_STATUS_OKAY(
+ THERMISTOR_COMPAT, GET_THERMISTOR_REF_RES) };
+
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE; sensor_idx++)
+ do_thermistor_test(&temp_sensors[sensor_idx],
+ reference_mv_arr[sensor_idx],
+ reference_res_arr[sensor_idx]);
+}
+
+ZTEST_USER(thermistor, test_device_nodes_enabled)
+{
+ zassert_equal(NAMED_TEMP_SENSORS_SIZE, TEMP_SENSORS_ENABLED_SIZE,
+ "Temperature sensors in device tree and "
+ "those enabled for test differ");
+
+ /* Thermistor nodes being enabled are already tested by compilation. */
+}
+
+static void *thermistor_setup(void)
+{
+ const struct device *dev =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_PG_EC_DSW_PWROK_PATH, gpios));
+ const struct device *dev_pin =
+ DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_EC_PG_PIN_TEMP_PATH, gpios));
+
+ zassert_not_null(dev, NULL);
+ /* Before tests make sure that power pins are set. */
+ zassert_ok(gpio_emul_input_set(dev, GPIO_PG_EC_DSW_PWROK_PORT, 1),
+ NULL);
+ zassert_ok(gpio_emul_input_set(dev_pin, GPIO_EC_PG_PIN_TEMP_PORT, 1),
+ NULL);
+
+ return NULL;
+}
+
+static void thermistor_cleanup(void *state)
+{
+ int sensor_idx;
+ const struct device *adc_dev = DEVICE_DT_GET(ADC_DEVICE_NODE);
+
+ const static int reference_mv_arr[] = { DT_FOREACH_STATUS_OKAY(
+ THERMISTOR_COMPAT, GET_THERMISTOR_REF_MV) };
+ const static int reference_res_arr[] = { DT_FOREACH_STATUS_OKAY(
+ THERMISTOR_COMPAT, GET_THERMISTOR_REF_RES) };
+
+ if (adc_dev == NULL)
+ TC_ERROR("Cannot get ADC device");
+
+ for (sensor_idx = 0; sensor_idx < NAMED_TEMP_SENSORS_SIZE;
+ sensor_idx++) {
+ /* Setup ADC to return 27*C (300K) which is reasonable value */
+ adc_emul_const_value_set(
+ adc_dev, temp_sensors[sensor_idx].idx,
+ volt_divider(reference_mv_arr[sensor_idx],
+ reference_res_arr[sensor_idx],
+ resistance_47kohm_B4050(300)));
+ adc_emul_ref_voltage_set(adc_dev, ADC_REF_INTERNAL,
+ reference_mv_arr[sensor_idx]);
+ }
+}
+
+ZTEST_SUITE(thermistor, drivers_predicate_post_main, thermistor_setup, NULL,
+ NULL, thermistor_cleanup);
diff --git a/zephyr/test/drivers/default/src/uart_hostcmd.c b/zephyr/test/drivers/default/src/uart_hostcmd.c
new file mode 100644
index 0000000000..879e734837
--- /dev/null
+++ b/zephyr/test/drivers/default/src/uart_hostcmd.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/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "console.h"
+#include "host_command.h"
+#include "uart.h"
+#include "test/drivers/test_state.h"
+
+/** Messages used in test */
+static const char msg1[] = "test";
+static const char msg2[] = "uart_hostcmd";
+static const char msg3[] = "message3";
+
+/** Length of message excluding NULL char at the end */
+#define MSG_LEN(msg) (sizeof(msg) - 1)
+
+/**
+ * Write message 1 before first snapshot. Read everything from buffer. Create
+ * second snapshot. Write message 2 after it.
+ */
+static void setup_snapshots_and_messages(void *unused)
+{
+ char response[1024];
+ struct host_cmd_handler_args read_args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_CONSOLE_READ, 0, response);
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_CONSOLE_SNAPSHOT, 0);
+
+ /* Set first snapshot before first message */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ cputs(CC_COMMAND, msg1);
+
+ /* Read everything from buffer */
+ do {
+ /* Clear response size before executing command */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args),
+ NULL);
+ } while (read_args.response_size != 0);
+
+ /* Set second snapshot after first message */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ cputs(CC_COMMAND, msg2);
+}
+
+/**
+ * Test if read next variant of console read host command is working. ver
+ * argument allows to change version of command. In case of version 1, parameter
+ * with sub command is provided.
+ */
+static void test_uart_hc_read_next(int ver)
+{
+ /* Should be able to read whole buffer in one command */
+ char response[CONFIG_PLATFORM_EC_HOSTCMD_CONSOLE_BUF_SIZE + 1];
+ struct ec_params_console_read_v1 params;
+ struct host_cmd_handler_args read_args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_CONSOLE_READ, ver, response);
+ struct host_cmd_handler_args snap_args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_CONSOLE_SNAPSHOT, 0);
+ char *msg1_start;
+ char *msg2_start;
+ char *msg3_start;
+
+ /* Set up host command parameters */
+ if (ver == 1) {
+ read_args.params = &params;
+ read_args.params_size = sizeof(params);
+ params.subcmd = CONSOLE_READ_NEXT;
+ }
+
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+
+ /*
+ * Whole buffer until snapshot should be in response, check if it ends
+ * with message 1 which should start at the end of response excluding
+ * NULL char.
+ */
+ msg1_start = response + read_args.response_size - 1 - MSG_LEN(msg1);
+ zassert_mem_equal(msg1, msg1_start, MSG_LEN(msg1),
+ "expected \"%s\", got \"%.*s\"", msg1, MSG_LEN(msg1),
+ msg1_start);
+
+ /* Set new snapshot which should include message 2 */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&snap_args), NULL);
+
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+
+ /*
+ * Whole buffer should be in response, check if it ends with both
+ * messages. Message 2 should start at the end of response excluding
+ * NULL char.
+ */
+ msg2_start = response + read_args.response_size - 1 - MSG_LEN(msg2);
+ msg1_start = msg2_start - MSG_LEN(msg1);
+ zassert_mem_equal(msg2, msg2_start, MSG_LEN(msg2),
+ "expected \"%s\", got \"%.*s\"", msg2, MSG_LEN(msg2),
+ msg2_start);
+ zassert_mem_equal(msg1, msg1_start, MSG_LEN(msg1),
+ "expected \"%s\", got \"%.*s\"", msg1, MSG_LEN(msg1),
+ msg1_start);
+
+ /* Append third message */
+ cputs(CC_COMMAND, msg3);
+
+ /* Check read next without new snapshot, no data should be read */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal(0, read_args.response_size,
+ "expected message length 0, got %d",
+ read_args.response_size);
+
+ /* Set new snapshot which should include message 3 */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&snap_args), NULL);
+
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+
+ msg3_start = response + read_args.response_size - 1 - MSG_LEN(msg3);
+ msg2_start = msg3_start - MSG_LEN(msg2);
+ msg1_start = msg2_start - MSG_LEN(msg1);
+ zassert_mem_equal(msg3, msg3_start, MSG_LEN(msg3),
+ "expected \"%s\", got \"%.*s\"", msg3, MSG_LEN(msg3),
+ msg3_start);
+ zassert_mem_equal(msg2, msg2_start, MSG_LEN(msg2),
+ "expected \"%s\", got \"%.*s\"", msg2, MSG_LEN(msg2),
+ msg2_start);
+ zassert_mem_equal(msg1, msg1_start, MSG_LEN(msg1),
+ "expected \"%s\", got \"%.*s\"", msg1, MSG_LEN(msg1),
+ msg1_start);
+}
+
+ZTEST_USER(uart_hostcmd, test_uart_hc_read_next_v0)
+{
+ test_uart_hc_read_next(0);
+}
+
+ZTEST_USER(uart_hostcmd, test_uart_hc_read_next_v1)
+{
+ test_uart_hc_read_next(1);
+}
+
+/** Test if read recent variant of console read host command is working */
+ZTEST_USER(uart_hostcmd, test_uart_hc_read_recent_v1)
+{
+ /* Should be able to read whole buffer in one command */
+ char response[CONFIG_PLATFORM_EC_HOSTCMD_CONSOLE_BUF_SIZE + 1];
+ struct ec_params_console_read_v1 params;
+ struct host_cmd_handler_args read_args =
+ BUILD_HOST_COMMAND(EC_CMD_CONSOLE_READ, 1, response, params);
+ struct host_cmd_handler_args snap_args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_CONSOLE_SNAPSHOT, 0);
+
+ params.subcmd = CONSOLE_READ_RECENT;
+
+ /* Only message 1 which is between two last snapshots should be read */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+ /* Account additional NULL char at the end */
+ zassert_equal(MSG_LEN(msg1) + 1, read_args.response_size,
+ "expected message length %d, got %d", MSG_LEN(msg1) + 1,
+ read_args.response_size);
+ zassert_mem_equal(msg1, response, MSG_LEN(msg1),
+ "expected \"%s\", got \"%.*s\"", msg1, MSG_LEN(msg1),
+ response);
+
+ /* Set new snapshot after second message */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&snap_args), NULL);
+
+ /* Only message between two last snapshots should be read */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+ /* Account additional NULL char at the end */
+ zassert_equal(MSG_LEN(msg2) + 1, read_args.response_size,
+ "expected message length %d, got %d", MSG_LEN(msg2) + 1,
+ read_args.response_size);
+ zassert_mem_equal(msg2, response, MSG_LEN(msg2),
+ "expected \"%s\", got \"%.*s\"", msg2, MSG_LEN(msg2),
+ response);
+
+ /* Append third message */
+ cputs(CC_COMMAND, msg3);
+
+ /* Check that message is not read without setting snapshot */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal(0, read_args.response_size,
+ "expected message length 0, got %d",
+ read_args.response_size);
+
+ /* Set new snapshot */
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&snap_args), NULL);
+
+ /* This time only third message should be read */
+ read_args.response_size = 0;
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&read_args), NULL);
+ zassert_equal('\0', response[read_args.response_size],
+ "Last byte of response is not '\\0' (got 0x%x)",
+ response[read_args.response_size]);
+ /* Account additional NULL char at the end */
+ zassert_equal(MSG_LEN(msg3) + 1, read_args.response_size,
+ "expected message length %d, got %d", MSG_LEN(msg3) + 1,
+ read_args.response_size);
+ zassert_mem_equal(msg3, response, MSG_LEN(msg3),
+ "expected \"%s\", got \"%.*s\"", msg3, MSG_LEN(msg3),
+ response);
+}
+
+ZTEST_SUITE(uart_hostcmd, drivers_predicate_post_main, NULL,
+ setup_snapshots_and_messages, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/usb_mux.c b/zephyr/test/drivers/default/src/usb_mux.c
new file mode 100644
index 0000000000..45b81d6ea5
--- /dev/null
+++ b/zephyr/test/drivers/default/src/usb_mux.c
@@ -0,0 +1,912 @@
+/* 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.h>
+#include <zephyr/drivers/gpio/gpio_emul.h>
+#include <zephyr/shell/shell.h>
+#include <zephyr/shell/shell_uart.h>
+
+#include "common.h"
+#include "ec_commands.h"
+#include "ec_tasks.h"
+#include <zephyr/fff.h>
+#include "hooks.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "test/drivers/stubs.h"
+#include "task.h"
+#include "tcpm/ps8xxx_public.h"
+#include "tcpm/tcpci.h"
+#include "usb_prl_sm.h"
+#include "usb_tc_sm.h"
+
+#include "usb_mux.h"
+#include "test/drivers/test_state.h"
+#include "test/drivers/utils.h"
+
+/** Copy of original usb_muxes[USB_PORT_C1] */
+struct usb_mux_chain usb_mux_c1;
+
+/** Number of usb mux proxies in chain */
+#define NUM_OF_PROXY 3
+
+/** Pointers to original usb muxes chain of port c1 */
+const struct usb_mux *org_mux[NUM_OF_PROXY];
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VALUE_FUNC(int, proxy_init, const struct usb_mux *);
+static int proxy_init_custom(const struct usb_mux *me)
+{
+ int i = me->i2c_addr_flags;
+ int ec = EC_SUCCESS;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL && org_mux[i]->driver->init != NULL) {
+ ec = org_mux[i]->driver->init(org_mux[i]);
+ }
+
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(proxy_init);
+ }
+
+ /* Discard this call if made from different thread */
+ proxy_init_fake.call_count--;
+
+ return ec;
+}
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VALUE_FUNC(int, proxy_set, const struct usb_mux *, mux_state_t, bool *);
+static int proxy_set_custom(const struct usb_mux *me, mux_state_t mux_state,
+ bool *ack_required)
+{
+ int i = me->i2c_addr_flags;
+ int ec = EC_SUCCESS;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL && org_mux[i]->driver->set != NULL) {
+ ec = org_mux[i]->driver->set(org_mux[i], mux_state,
+ ack_required);
+ /* Disable waiting for ACK in tests */
+ *ack_required = false;
+ }
+
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(proxy_set);
+ }
+
+ /* Discard this call if made from different thread */
+ proxy_set_fake.call_count--;
+
+ return ec;
+}
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VALUE_FUNC(int, proxy_get, const struct usb_mux *, mux_state_t *);
+/** Sequence of mux_state values returned by proxy_get function */
+static mux_state_t proxy_get_mux_state_seq[NUM_OF_PROXY];
+/** Index of next mux_state to return from proxy_get_function */
+static int proxy_get_mux_state_seq_idx;
+/** Set all mux_state in sequence to the same state value */
+static void set_proxy_get_mux_state_seq(mux_state_t state)
+{
+ proxy_get_mux_state_seq_idx = 0;
+ for (int i = 0; i < NUM_OF_PROXY; i++) {
+ proxy_get_mux_state_seq[i] = state;
+ }
+}
+
+static int proxy_get_custom(const struct usb_mux *me, mux_state_t *mux_state)
+{
+ int i = me->i2c_addr_flags;
+ int ec = EC_SUCCESS;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL && org_mux[i]->driver->get != NULL) {
+ ec = org_mux[i]->driver->get(org_mux[i], mux_state);
+ }
+
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ zassert_true(proxy_get_mux_state_seq_idx < NUM_OF_PROXY,
+ "%s called too many times without resetting "
+ "mux_state_seq",
+ __func__);
+ *mux_state =
+ proxy_get_mux_state_seq[proxy_get_mux_state_seq_idx];
+ proxy_get_mux_state_seq_idx++;
+ RETURN_FAKE_RESULT(proxy_get);
+ }
+
+ /* Discard this call if made from different thread */
+ proxy_get_fake.call_count--;
+
+ return ec;
+}
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VALUE_FUNC(int, proxy_enter_low_power_mode, const struct usb_mux *);
+static int proxy_enter_low_power_mode_custom(const struct usb_mux *me)
+{
+ int i = me->i2c_addr_flags;
+ int ec = EC_SUCCESS;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL &&
+ org_mux[i]->driver->enter_low_power_mode != NULL) {
+ ec = org_mux[i]->driver->enter_low_power_mode(org_mux[i]);
+ }
+
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(proxy_enter_low_power_mode);
+ }
+
+ /* Discard this call if made from different thread */
+ proxy_enter_low_power_mode_fake.call_count--;
+
+ return ec;
+}
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VALUE_FUNC(int, proxy_chipset_reset, const struct usb_mux *);
+static int proxy_chipset_reset_custom(const struct usb_mux *me)
+{
+ int i = me->i2c_addr_flags;
+ int ec = EC_SUCCESS;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL && org_mux[i]->driver->chipset_reset != NULL) {
+ ec = org_mux[i]->driver->chipset_reset(org_mux[i]);
+ }
+
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(proxy_chipset_reset);
+ }
+
+ /* Discard this call if made from different thread */
+ proxy_chipset_reset_fake.call_count--;
+
+ return ec;
+}
+
+/** Proxy function for fw update capability */
+static bool proxy_fw_update_cap(void)
+{
+ return true;
+}
+
+/** Proxy function which check calls from usb_mux framework to driver */
+FAKE_VOID_FUNC(proxy_hpd_update, const struct usb_mux *, mux_state_t, bool *);
+static void proxy_hpd_update_custom(const struct usb_mux *me,
+ mux_state_t mux_state, bool *ack_required)
+{
+ int i = me->i2c_addr_flags;
+
+ zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux");
+
+ if (org_mux[i] != NULL && org_mux[i]->hpd_update != NULL) {
+ org_mux[i]->hpd_update(org_mux[i], mux_state, ack_required);
+ /* Disable waiting for ACK in tests */
+ *ack_required = false;
+ }
+
+ if (task_get_current() != TASK_ID_TEST_RUNNER) {
+ /* Discard this call if made from different thread */
+ proxy_hpd_update_fake.call_count--;
+ }
+}
+
+/** Usb mux driver with proxy functions */
+const struct usb_mux_driver proxy_usb_mux = {
+ .init = &proxy_init,
+ .set = &proxy_set,
+ .get = &proxy_get,
+ .enter_low_power_mode = &proxy_enter_low_power_mode,
+ .chipset_reset = &proxy_chipset_reset,
+ .is_retimer_fw_update_capable = &proxy_fw_update_cap,
+};
+
+/** Mock function used in init test */
+FAKE_VALUE_FUNC(int, mock_board_init, const struct usb_mux *);
+static int mock_board_init_custom(const struct usb_mux *me)
+{
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(mock_board_init);
+ }
+
+ /* Discard this call if made from different thread */
+ mock_board_init_fake.call_count--;
+
+ return EC_SUCCESS;
+}
+
+/** Mock function used in set test */
+FAKE_VALUE_FUNC(int, mock_board_set, const struct usb_mux *, mux_state_t);
+static int mock_board_set_custom(const struct usb_mux *me,
+ mux_state_t mux_state)
+{
+ if (task_get_current() == TASK_ID_TEST_RUNNER) {
+ RETURN_FAKE_RESULT(mock_board_set);
+ }
+
+ /* Discard this call if made from different thread */
+ mock_board_set_fake.call_count--;
+
+ return EC_SUCCESS;
+}
+
+/**
+ * Reset state of all fake functions, setup custom fake functions and set
+ * default return value to EC_SUCCESS (all functions which has return value)
+ */
+static void reset_proxy_fakes(void)
+{
+ RESET_FAKE(proxy_init);
+ RESET_FAKE(proxy_set);
+ RESET_FAKE(proxy_get);
+ RESET_FAKE(proxy_enter_low_power_mode);
+ RESET_FAKE(proxy_chipset_reset);
+ RESET_FAKE(proxy_hpd_update);
+ RESET_FAKE(mock_board_init);
+ RESET_FAKE(mock_board_set);
+
+ /* Setup proxy functions */
+ proxy_init_fake.custom_fake = proxy_init_custom;
+ proxy_set_fake.custom_fake = proxy_set_custom;
+ proxy_get_fake.custom_fake = proxy_get_custom;
+ proxy_enter_low_power_mode_fake.custom_fake =
+ proxy_enter_low_power_mode_custom;
+ proxy_chipset_reset_fake.custom_fake = proxy_chipset_reset_custom;
+ proxy_hpd_update_fake.custom_fake = proxy_hpd_update_custom;
+ mock_board_init_fake.custom_fake = mock_board_init_custom;
+ mock_board_set_fake.custom_fake = mock_board_set_custom;
+
+ /* Set default return value */
+ proxy_init_fake.return_val = EC_SUCCESS;
+ proxy_set_fake.return_val = EC_SUCCESS;
+ proxy_get_fake.return_val = EC_SUCCESS;
+ proxy_enter_low_power_mode_fake.return_val = EC_SUCCESS;
+ proxy_chipset_reset_fake.return_val = EC_SUCCESS;
+ mock_board_init_fake.return_val = EC_SUCCESS;
+ mock_board_set_fake.return_val = EC_SUCCESS;
+}
+
+/** Chain of 3 proxy usb muxes */
+struct usb_mux proxy_mux_2 = {
+ .usb_port = USBC_PORT_C1,
+ .driver = &proxy_usb_mux,
+ .i2c_addr_flags = 2,
+ .hpd_update = &proxy_hpd_update,
+};
+
+struct usb_mux_chain proxy_chain_2 = {
+ .mux = &proxy_mux_2,
+};
+
+struct usb_mux proxy_mux_1 = {
+ .usb_port = USBC_PORT_C1,
+ .driver = &proxy_usb_mux,
+ .i2c_addr_flags = 1,
+ .hpd_update = &proxy_hpd_update,
+};
+
+struct usb_mux_chain proxy_chain_1 = {
+ .mux = &proxy_mux_1,
+ .next = &proxy_chain_2,
+};
+
+struct usb_mux proxy_mux_0 = {
+ .usb_port = USBC_PORT_C1,
+ .driver = &proxy_usb_mux,
+ .i2c_addr_flags = 0,
+ .hpd_update = &proxy_hpd_update,
+};
+
+struct usb_mux_chain proxy_chain_0 = {
+ .mux = &proxy_mux_0,
+ .next = &proxy_chain_1,
+};
+
+/** Setup first 3 usb muxes of port 1 with proxy */
+static void setup_usb_mux_proxy_chain(void)
+{
+ const struct usb_mux_chain *t;
+ int i;
+
+ memcpy(&usb_mux_c1, &usb_muxes[USBC_PORT_C1],
+ sizeof(struct usb_mux_chain));
+ memcpy(&usb_muxes[USBC_PORT_C1], &proxy_chain_0,
+ sizeof(struct usb_mux_chain));
+
+ /*
+ * Setup org_mux array to point real driver which should be called by
+ * each proxy
+ */
+ t = &usb_mux_c1;
+ for (i = 0; i < NUM_OF_PROXY; i++) {
+ if (t != NULL) {
+ org_mux[i] = t->mux;
+ t = t->next;
+ } else {
+ org_mux[i] = NULL;
+ }
+ }
+
+ if (t != NULL) {
+ proxy_chain_2.next = t;
+ } else {
+ proxy_chain_2.next = NULL;
+ }
+}
+
+/** Restore original usb_mux chain without proxy */
+static void restore_usb_mux_chain(void)
+{
+ memcpy(&usb_muxes[USBC_PORT_C1], &usb_mux_c1,
+ sizeof(struct usb_mux_chain));
+
+ /* Reset flags to default */
+ proxy_mux_0.flags = 0;
+ proxy_mux_1.flags = 0;
+ proxy_mux_2.flags = 0;
+}
+
+/**
+ * Check if given proxy function was called num times and if first argument was
+ * pointer to the right proxy chain element. First argument is
+ * const struct usb_mux * for all struct usb_mux_driver callbacks.
+ */
+#define CHECK_PROXY_FAKE_CALL_CNT(proxy, num) \
+ do { \
+ zassert_equal(num, proxy##_fake.call_count, "%d != %d", num, \
+ proxy##_fake.call_count); \
+ if (num >= 1) { \
+ zassert_equal(usb_muxes[USBC_PORT_C1].mux, \
+ proxy##_fake.arg0_history[0], NULL); \
+ } \
+ if (num >= 2) { \
+ zassert_equal(proxy_chain_1.mux, \
+ proxy##_fake.arg0_history[1], NULL); \
+ } \
+ if (num >= 3) { \
+ zassert_equal(proxy_chain_2.mux, \
+ proxy##_fake.arg0_history[2], NULL); \
+ } \
+ } while (0)
+
+/**
+ * Do the same thing as CHECK_PROXY_FAKE_CALL_CNT and check if second argument
+ * was the same as given state. hpd_update and set callback have mux_state_t
+ * as second argument.
+ */
+#define CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy, num, state) \
+ do { \
+ CHECK_PROXY_FAKE_CALL_CNT(proxy, num); \
+ if (num >= 1) { \
+ zassert_equal(state, proxy##_fake.arg1_history[0], \
+ "0x%x != 0x%x", state, \
+ proxy##_fake.arg1_history[0]); \
+ } \
+ if (num >= 2) { \
+ zassert_equal(state, proxy##_fake.arg1_history[1], \
+ "0x%x != 0x%x", state, \
+ proxy##_fake.arg1_history[1]); \
+ } \
+ if (num >= 3) { \
+ zassert_equal(state, proxy##_fake.arg1_history[2], \
+ "0x%x != 0x%x", state, \
+ proxy##_fake.arg1_history[2]); \
+ } \
+ } while (0)
+
+/** Test usb_mux init */
+ZTEST(usb_uninit_mux, test_usb_mux_init)
+{
+ int fail_on_2nd_ret[] = { EC_SUCCESS, EC_ERROR_NOT_POWERED };
+
+ /* Set AP to normal state to init BB retimer */
+ test_set_chipset_to_s0();
+
+ /* Test successful initialisation */
+ usb_mux_init(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+
+ /*
+ * Test failed initialisation. Muxes that are in chain after
+ * the one which fails shouldn't be called
+ */
+ reset_proxy_fakes();
+ SET_RETURN_SEQ(proxy_init, fail_on_2nd_ret, 2);
+ usb_mux_init(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 2);
+
+ /* Test board init callback */
+ proxy_mux_1.board_init = &mock_board_init;
+ reset_proxy_fakes();
+ usb_mux_init(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ /* Check if board_init was called for proxy 1 */
+ zassert_equal(1, mock_board_init_fake.call_count, NULL);
+ zassert_equal(proxy_chain_1.mux, mock_board_init_fake.arg0_history[0],
+ NULL);
+
+ proxy_mux_1.board_init = NULL;
+}
+
+/** Test usb_mux setting mux mode */
+ZTEST(usb_uninit_mux, test_usb_mux_set)
+{
+ int fail_on_2nd_ret[] = { EC_SUCCESS, EC_ERROR_UNKNOWN };
+ mux_state_t exp_mode;
+
+ /* Set flag for usb mux 1 to disable polarity setting */
+ proxy_mux_1.flags = USB_MUX_FLAG_SET_WITHOUT_FLIP;
+
+ /* Test setting mux mode without polarity inversion */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ /* All muxes should have the same mode */
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test setting mux mode with polarity inversion */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_TBT_COMPAT_ENABLED;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 1 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_set, NUM_OF_PROXY);
+ /* usb mux 1 shouldn't be set with polarity mode, because of flag */
+ zassert_equal(exp_mode | USB_PD_MUX_POLARITY_INVERTED,
+ proxy_set_fake.arg1_history[0], NULL);
+ zassert_equal(exp_mode, proxy_set_fake.arg1_history[1], NULL);
+ zassert_equal(exp_mode | USB_PD_MUX_POLARITY_INVERTED,
+ proxy_set_fake.arg1_history[2], NULL);
+
+ /* Test board set callback */
+ reset_proxy_fakes();
+ proxy_mux_1.board_set = &mock_board_set;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+ /* Check if board_set was called for proxy 1 */
+ zassert_equal(1, mock_board_set_fake.call_count, NULL);
+ zassert_equal(proxy_chain_1.mux, mock_board_set_fake.arg0_history[0],
+ NULL);
+ zassert_equal(exp_mode, mock_board_set_fake.arg1_history[0], NULL);
+
+ /* Test set function with error in usb_mux */
+ reset_proxy_fakes();
+ SET_RETURN_SEQ(proxy_set, fail_on_2nd_ret, 2);
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, 2, exp_mode);
+ /* board_set shouldn't be called after fail */
+ zassert_equal(0, mock_board_set_fake.call_count, NULL);
+
+ proxy_mux_1.board_set = NULL;
+}
+
+/** Test usb_mux reset in g3 when required flag is set */
+ZTEST(usb_uninit_mux, test_usb_mux_reset_in_g3)
+{
+ mux_state_t exp_mode = USB_PD_MUX_USB_ENABLED;
+
+ /* Test that init is called */
+ reset_proxy_fakes();
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Usb muxes of port 1 should stay initialised */
+ proxy_mux_0.flags = 0;
+ hook_notify(HOOK_CHIPSET_HARD_OFF);
+
+ /* Test that init is not called */
+ reset_proxy_fakes();
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+}
+
+/** Test usb_mux getting mux mode */
+ZTEST(usb_uninit_mux, test_usb_mux_get)
+{
+ int fail_on_2nd_ret[] = { EC_SUCCESS, EC_ERROR_UNKNOWN };
+ mux_state_t exp_mode, mode;
+
+ /* Test getting mux mode */
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ set_proxy_get_mux_state_seq(exp_mode);
+ mode = usb_mux_get(USBC_PORT_C1);
+ zassert_equal(exp_mode, mode, "mode is 0x%x (!= 0x%x)", mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+
+ /* Test getting mux mode with inverted polarisation in one mux */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_TBT_COMPAT_ENABLED;
+ set_proxy_get_mux_state_seq(exp_mode);
+ /* Set polarisation in usb mux 1 state */
+ proxy_get_mux_state_seq[1] |= USB_PD_MUX_POLARITY_INVERTED;
+ exp_mode |= USB_PD_MUX_POLARITY_INVERTED;
+ mode = usb_mux_get(USBC_PORT_C1);
+ zassert_equal(exp_mode, mode, "mode is 0x%x (!= 0x%x)", mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+
+ /* Test get function with error in usb_mux */
+ reset_proxy_fakes();
+ SET_RETURN_SEQ(proxy_get, fail_on_2nd_ret, 2);
+ set_proxy_get_mux_state_seq(USB_PD_MUX_TBT_COMPAT_ENABLED);
+ exp_mode = USB_PD_MUX_NONE;
+ mode = usb_mux_get(USBC_PORT_C1);
+ zassert_equal(exp_mode, mode, "mode is 0x%x (!= 0x%x)", mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, 2);
+}
+
+/** Test usb_mux entering and exiting low power mode */
+ZTEST(usb_init_mux, test_usb_mux_low_power_mode)
+{
+ int fail_on_2nd_ret[] = { EC_SUCCESS, EC_ERROR_NOT_POWERED };
+ mux_state_t exp_mode, mode;
+
+ /* Test enter to low power mode */
+ exp_mode = USB_PD_MUX_NONE;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_DISCONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_enter_low_power_mode, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test that nothing is changed when already in low power mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_NONE;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_DISCONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_enter_low_power_mode, 0);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_set, 0);
+
+ /* Test that get return USB_PD_MUX_NONE in low power mode */
+ exp_mode = USB_PD_MUX_NONE;
+ mode = usb_mux_get(USBC_PORT_C1);
+ zassert_equal(exp_mode, mode, "mode is 0x%x (!= 0x%x)", mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, 0);
+
+ /* Test exiting from low power mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test exiting from lpm, when init end with EC_ERROR_NOT_POWERED */
+ reset_proxy_fakes();
+ SET_RETURN_SEQ(proxy_init, fail_on_2nd_ret, 2);
+ usb_mux_init(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 2);
+
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test enter to low power mode with polarity */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_NONE;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_DISCONNECT,
+ 1 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_enter_low_power_mode, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test that nothing is changed on lpm exit error */
+ reset_proxy_fakes();
+ SET_RETURN_SEQ(proxy_init, fail_on_2nd_ret, 2);
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ usb_mux_set(USBC_PORT_C1, exp_mode, USB_SWITCH_CONNECT,
+ 0 /* = polarity */);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 2);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_set, 0);
+}
+
+/** Test usb_mux flip */
+ZTEST(usb_uninit_mux, test_usb_mux_flip)
+{
+ mux_state_t exp_mode;
+
+ /* Set flag for usb mux 1 to disable polarity setting */
+ proxy_mux_1.flags = USB_MUX_FLAG_SET_WITHOUT_FLIP;
+
+ /* Test flip port without polarity inverted */
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ set_proxy_get_mux_state_seq(exp_mode);
+ usb_mux_flip(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_set, NUM_OF_PROXY);
+ /* usb mux 1 shouldn't be set with polarity mode, because of flag */
+ zassert_equal(exp_mode | USB_PD_MUX_POLARITY_INVERTED,
+ proxy_set_fake.arg1_history[0], NULL);
+ zassert_equal(exp_mode, proxy_set_fake.arg1_history[1], NULL);
+ zassert_equal(exp_mode | USB_PD_MUX_POLARITY_INVERTED,
+ proxy_set_fake.arg1_history[2], NULL);
+
+ /* Test flip port with polarity inverted */
+ reset_proxy_fakes();
+ exp_mode |= USB_PD_MUX_POLARITY_INVERTED;
+ set_proxy_get_mux_state_seq(exp_mode);
+ /* Clear polarity bit from usb mux 1 */
+ proxy_get_mux_state_seq[1] &= ~USB_PD_MUX_POLARITY_INVERTED;
+ exp_mode &= ~USB_PD_MUX_POLARITY_INVERTED;
+ usb_mux_flip(USBC_PORT_C1);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+}
+
+ZTEST(usb_uninit_mux, test_usb_mux_hpd_update)
+{
+ mux_state_t exp_mode, mode, virt_mode;
+
+ /* Get current state of virtual usb mux and set mock */
+ usbc1_virtual_usb_mux.driver->get(&usbc1_virtual_usb_mux, &virt_mode);
+
+ /* Test no hpd level and no irq */
+ exp_mode = virt_mode;
+ usb_mux_hpd_update(USBC_PORT_C1, exp_mode);
+ /* Check if virtual usb mux mode is updated correctly */
+ usbc1_virtual_usb_mux.driver->get(&usbc1_virtual_usb_mux, &mode);
+ zassert_equal(exp_mode, mode, "virtual mux mode is 0x%x (!= 0x%x)",
+ mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY,
+ exp_mode);
+
+ /* Test hpd level and irq */
+ reset_proxy_fakes();
+ exp_mode = virt_mode | USB_PD_MUX_HPD_LVL | USB_PD_MUX_HPD_IRQ;
+ usb_mux_hpd_update(USBC_PORT_C1, exp_mode);
+ /* Check if virtual usb mux mode is updated correctly */
+ usbc1_virtual_usb_mux.driver->get(&usbc1_virtual_usb_mux, &mode);
+ zassert_equal(exp_mode, mode, "virtual mux mode is 0x%x (!= 0x%x)",
+ mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY,
+ exp_mode);
+
+ /* Test no hpd level and irq */
+ reset_proxy_fakes();
+ exp_mode = virt_mode | USB_PD_MUX_HPD_IRQ;
+ usb_mux_hpd_update(USBC_PORT_C1, exp_mode);
+ /* Check if virtual usb mux mode is updated correctly */
+ usbc1_virtual_usb_mux.driver->get(&usbc1_virtual_usb_mux, &mode);
+ zassert_equal(exp_mode, mode, "virtual mux mode is 0x%x (!= 0x%x)",
+ mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY,
+ exp_mode);
+
+ /* Test hpd level and no irq */
+ reset_proxy_fakes();
+ exp_mode = virt_mode | USB_PD_MUX_HPD_LVL;
+ usb_mux_hpd_update(USBC_PORT_C1, exp_mode);
+ /* Check if virtual usb mux mode is updated correctly */
+ usbc1_virtual_usb_mux.driver->get(&usbc1_virtual_usb_mux, &mode);
+ zassert_equal(exp_mode, mode, "virtual mux mode is 0x%x (!= 0x%x)",
+ mode, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, 0);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY,
+ exp_mode);
+
+ /* Test ps8xxx hpd update */
+ proxy_mux_0.usb_port = 1;
+ proxy_mux_0.driver = &tcpci_tcpm_usb_mux_driver;
+ proxy_mux_0.hpd_update = &ps8xxx_tcpc_update_hpd_status;
+
+ reset_proxy_fakes();
+ exp_mode = virt_mode | USB_PD_MUX_HPD_LVL | USB_PD_MUX_HPD_IRQ;
+ usb_mux_hpd_update(USBC_PORT_C1, exp_mode);
+ /* Check if PS8xxx mux mode is updated correctly */
+ tcpci_tcpm_usb_mux_driver.get(usb_muxes[USBC_PORT_C1].mux, &mode);
+
+ /* Restore proxy chain 0 */
+ proxy_mux_0.usb_port = USBC_PORT_C1;
+ proxy_mux_0.driver = &proxy_usb_mux;
+ proxy_mux_0.hpd_update = &proxy_hpd_update;
+
+ zassert_equal(0, mode, "mux mode is 0x%x (!= 0x%x)", mode, 0);
+}
+
+ZTEST(usb_init_mux, test_usb_mux_fw_update_port_info)
+{
+ int port_info;
+
+ port_info = usb_mux_retimer_fw_update_port_info();
+ zassert_true(port_info & BIT(USBC_PORT_C1),
+ "fw update for port C1 should be set");
+}
+
+ZTEST(usb_init_mux, test_usb_mux_chipset_reset)
+{
+ /* After this hook chipset reset functions should be called */
+ hook_notify(HOOK_CHIPSET_RESET);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_chipset_reset, NUM_OF_PROXY);
+}
+
+/* Test host command get mux info */
+ZTEST(usb_init_mux, test_usb_mux_hc_mux_info)
+{
+ struct ec_response_usb_pd_mux_info response;
+ struct ec_params_usb_pd_mux_info params;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_USB_PD_MUX_INFO, 0, response, params);
+ mux_state_t exp_mode;
+
+ /* Test invalid port parameter */
+ params.port = 5;
+ zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL);
+
+ /* Set correct port for rest of the test */
+ params.port = USBC_PORT_C1;
+
+ /* Test error on getting mux mode */
+ set_proxy_get_mux_state_seq(USB_PD_MUX_USB_ENABLED);
+ proxy_get_fake.return_val = EC_ERROR_UNKNOWN;
+ zassert_equal(EC_RES_ERROR, host_command_process(&args), NULL);
+
+ /* Test getting mux mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED;
+ set_proxy_get_mux_state_seq(exp_mode);
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(exp_mode, response.flags, "mode is 0x%x (!= 0x%x)",
+ response.flags, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+
+ /* Test clearing HPD IRQ */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_HPD_LVL |
+ USB_PD_MUX_HPD_IRQ;
+ set_proxy_get_mux_state_seq(exp_mode);
+ zassert_equal(EC_RES_SUCCESS, host_command_process(&args), NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(exp_mode, response.flags, "mode is 0x%x (!= 0x%x)",
+ response.flags, exp_mode);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY,
+ USB_PD_MUX_HPD_LVL);
+}
+
+/** Test typec console command */
+ZTEST(usb_init_mux, test_usb_mux_typec_command)
+{
+ mux_state_t polarity;
+ mux_state_t exp_mode;
+
+ /* Test error on command with no argument */
+ zassert_equal(EC_ERROR_PARAM_COUNT,
+ shell_execute_cmd(get_ec_shell(), "typec"), NULL);
+
+ /*
+ * Test success on passing "debug" as first argument. This will enable
+ * debug prints, but it is not possible to test that in unit test
+ * without accessing cprints output.
+ */
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "typec debug"), NULL);
+
+ /* Test error on port argument that is not a number */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "typec test1"), NULL);
+
+ /* Test error on invalid port number */
+ zassert_equal(EC_ERROR_PARAM1,
+ shell_execute_cmd(get_ec_shell(), "typec 5"), NULL);
+
+ /*
+ * Test success on correct port number. Command should print mux state
+ * on console, but it is not possible to check that in unit test.
+ */
+ set_proxy_get_mux_state_seq(USB_PD_MUX_TBT_COMPAT_ENABLED);
+ zassert_equal(EC_SUCCESS, shell_execute_cmd(get_ec_shell(), "typec 1"),
+ NULL);
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_get, NUM_OF_PROXY);
+
+ /* Test setting none mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_NONE;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "typec 1 none"), NULL);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+ /* Mux will enter low power mode */
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_enter_low_power_mode, NUM_OF_PROXY);
+
+ /* Polarity is set based on PD */
+ polarity = polarity_rm_dts(pd_get_polarity(USBC_PORT_C1)) ?
+ USB_PD_MUX_POLARITY_INVERTED :
+ 0;
+
+ /* Test setting USB mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED | polarity;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "typec 1 usb"), NULL);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+ /* Mux will exit low power mode */
+ CHECK_PROXY_FAKE_CALL_CNT(proxy_init, NUM_OF_PROXY);
+
+ /* Test setting DP mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_DP_ENABLED | polarity;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "typec 1 dp"), NULL);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+
+ /* Test setting dock mode */
+ reset_proxy_fakes();
+ exp_mode = USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED | polarity;
+ zassert_equal(EC_SUCCESS,
+ shell_execute_cmd(get_ec_shell(), "typec 1 dock"), NULL);
+ CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_set, NUM_OF_PROXY, exp_mode);
+}
+
+/** Setup proxy chain and uninit usb muxes */
+void usb_uninit_mux_before(void *state)
+{
+ ARG_UNUSED(state);
+ setup_usb_mux_proxy_chain();
+ set_test_runner_tid();
+
+ /* Makes sure that usb muxes of port 1 are not init */
+ proxy_mux_0.flags = USB_MUX_FLAG_RESETS_IN_G3;
+ hook_notify(HOOK_CHIPSET_HARD_OFF);
+ reset_proxy_fakes();
+}
+
+void usb_uninit_mux_after(void *state)
+{
+ ARG_UNUSED(state);
+ restore_usb_mux_chain();
+}
+
+/** Setup proxy chain and init usb muxes */
+void usb_init_mux_before(void *state)
+{
+ ARG_UNUSED(state);
+ setup_usb_mux_proxy_chain();
+ set_test_runner_tid();
+
+ /* Makes sure that usb muxes of port 1 are init */
+ usb_mux_init(USBC_PORT_C1);
+ reset_proxy_fakes();
+}
+
+void usb_init_mux_after(void *state)
+{
+ ARG_UNUSED(state);
+ restore_usb_mux_chain();
+}
+
+ZTEST_SUITE(usb_uninit_mux, drivers_predicate_post_main, NULL,
+ usb_uninit_mux_before, usb_uninit_mux_after, NULL);
+
+ZTEST_SUITE(usb_init_mux, drivers_predicate_post_main, NULL,
+ usb_init_mux_before, usb_init_mux_after, NULL);
diff --git a/zephyr/test/drivers/default/src/usb_pd_host_cmd.c b/zephyr/test/drivers/default/src/usb_pd_host_cmd.c
new file mode 100644
index 0000000000..c8851fbeb1
--- /dev/null
+++ b/zephyr/test/drivers/default/src/usb_pd_host_cmd.c
@@ -0,0 +1,26 @@
+/* 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 "ec_commands.h"
+#include "host_command.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_USER(usb_pd_host_cmd, test_host_command_hc_pd_ports)
+{
+ struct ec_response_usb_pd_ports response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_USB_PD_PORTS, 0, response);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.num_ports, CONFIG_USB_PD_PORT_MAX_COUNT, NULL);
+}
+
+ZTEST_SUITE(usb_pd_host_cmd, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/vboot_hash.c b/zephyr/test/drivers/default/src/vboot_hash.c
new file mode 100644
index 0000000000..546fc8135f
--- /dev/null
+++ b/zephyr/test/drivers/default/src/vboot_hash.c
@@ -0,0 +1,103 @@
+/* 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 <sha256.h>
+
+#include "ec_commands.h"
+#include "host_command.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_USER(vboot_hash, test_hostcmd_abort)
+{
+ struct ec_response_vboot_hash response;
+ struct ec_params_vboot_hash start_params = {
+ .cmd = EC_VBOOT_HASH_START,
+ .hash_type = EC_VBOOT_HASH_TYPE_SHA256,
+ .offset = EC_VBOOT_HASH_OFFSET_RO,
+ .size = 0,
+ };
+ struct host_cmd_handler_args start_args = BUILD_HOST_COMMAND(
+ EC_CMD_VBOOT_HASH, 0, response, start_params);
+ struct ec_params_vboot_hash abort_params = {
+ .cmd = EC_VBOOT_HASH_ABORT,
+ };
+ struct host_cmd_handler_args abort_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_VBOOT_HASH, 0, abort_params);
+ struct ec_params_vboot_hash get_params = {
+ .cmd = EC_VBOOT_HASH_GET,
+ };
+ struct host_cmd_handler_args get_args =
+ BUILD_HOST_COMMAND(EC_CMD_VBOOT_HASH, 0, response, get_params);
+
+ /* Start hashing. The command doesn't wait to finish. */
+ zassert_ok(host_command_process(&start_args), NULL);
+ zassert_ok(start_args.result, NULL);
+ zassert_equal(start_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, EC_VBOOT_HASH_STATUS_BUSY,
+ "response.status = %d", response.status);
+
+ /* Abort it immediately */
+ zassert_ok(host_command_process(&abort_args), NULL);
+ zassert_ok(abort_args.result, NULL);
+
+ /* Give it a bit time. The abort is being processed in the background */
+ k_msleep(20);
+
+ /* Get the hash result. Should be NONE. */
+ zassert_ok(host_command_process(&get_args), NULL);
+ zassert_ok(get_args.result, NULL);
+ zassert_equal(get_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, EC_VBOOT_HASH_STATUS_NONE,
+ "response.status = %d", response.status);
+}
+
+ZTEST_USER(vboot_hash, test_hostcmd_recalc)
+{
+ struct ec_response_vboot_hash response;
+ struct ec_params_vboot_hash recalc_params = {
+ .cmd = EC_VBOOT_HASH_RECALC,
+ .hash_type = EC_VBOOT_HASH_TYPE_SHA256,
+ .offset = EC_VBOOT_HASH_OFFSET_RO,
+ .size = 0,
+ };
+ struct host_cmd_handler_args recalc_args = BUILD_HOST_COMMAND(
+ EC_CMD_VBOOT_HASH, 0, response, recalc_params);
+
+ /* Recalculate the hash. The command waits to finish. */
+ zassert_ok(host_command_process(&recalc_args), NULL);
+ zassert_ok(recalc_args.result, NULL);
+ zassert_equal(recalc_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, EC_VBOOT_HASH_STATUS_DONE,
+ "response.status = %d", response.status);
+ zassert_equal(response.digest_size, SHA256_DIGEST_SIZE,
+ "response.digest_size = %d", response.digest_size);
+}
+
+ZTEST_USER(vboot_hash, test_hostcmd_hash_arbitrary_size)
+{
+ struct ec_response_vboot_hash response;
+ struct ec_params_vboot_hash recalc_params = {
+ .cmd = EC_VBOOT_HASH_RECALC,
+ .hash_type = EC_VBOOT_HASH_TYPE_SHA256,
+ .offset = 0,
+ /* arbitrary size */
+ .size = 0x12345,
+ };
+ struct host_cmd_handler_args recalc_args = BUILD_HOST_COMMAND(
+ EC_CMD_VBOOT_HASH, 0, response, recalc_params);
+
+ /* Recalculate the hash. The command waits to finish. */
+ zassert_ok(host_command_process(&recalc_args), NULL);
+ zassert_ok(recalc_args.result, NULL);
+ zassert_equal(recalc_args.response_size, sizeof(response), NULL);
+ zassert_equal(response.status, EC_VBOOT_HASH_STATUS_DONE,
+ "response.status = %d", response.status);
+ zassert_equal(response.digest_size, SHA256_DIGEST_SIZE,
+ "response.digest_size = %d", response.digest_size);
+}
+
+ZTEST_SUITE(vboot_hash, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
diff --git a/zephyr/test/drivers/default/src/virtual_battery.c b/zephyr/test/drivers/default/src/virtual_battery.c
new file mode 100644
index 0000000000..0e69c641a5
--- /dev/null
+++ b/zephyr/test/drivers/default/src/virtual_battery.c
@@ -0,0 +1,259 @@
+/* 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 "battery.h"
+#include "battery_smart.h"
+#include "ec_commands.h"
+#include "emul/emul_smart_battery.h"
+#include "host_command.h"
+#include "test/drivers/test_state.h"
+
+/* The param buffer has at most 2 msg's (write + read) and 1 byte write len. */
+static uint8_t param_buf[sizeof(struct ec_params_i2c_passthru) +
+ sizeof(struct ec_params_i2c_passthru_msg) * 2 + 1];
+
+/* The response buffer has at most 32 bytes returned result. */
+static uint8_t response_buf[sizeof(struct ec_response_i2c_passthru) + 32];
+
+static void i2c_passthru_xfer(uint8_t port, uint8_t addr, uint8_t *write_buf,
+ int write_len, uint8_t **read_buf, int read_len)
+{
+ struct ec_params_i2c_passthru *params =
+ (struct ec_params_i2c_passthru *)&param_buf;
+ struct ec_response_i2c_passthru *response =
+ (struct ec_response_i2c_passthru *)&response_buf;
+ struct ec_params_i2c_passthru_msg *msg = params->msg;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_SIMPLE(EC_CMD_I2C_PASSTHRU, 0);
+ uint8_t *pdata;
+ int size;
+
+ params->port = port;
+ params->num_msgs = (read_len != 0) + (write_len != 0);
+
+ size = sizeof(*params) + params->num_msgs * sizeof(*msg);
+ pdata = (uint8_t *)params + size;
+
+ if (write_len) {
+ msg->addr_flags = addr;
+ msg->len = write_len;
+ memcpy(pdata, write_buf, write_len);
+ msg++;
+ }
+
+ if (read_len) {
+ msg->addr_flags = addr | EC_I2C_FLAG_READ;
+ msg->len = read_len;
+ }
+
+ args.params = params;
+ args.params_size = size + write_len;
+ args.response = response;
+ args.response_max = sizeof(*response) + read_len;
+
+ /* Execute the I2C passthru host command */
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_ok(response->i2c_status, NULL);
+ zassert_equal(args.response_size, sizeof(*response) + read_len, NULL);
+
+ /* Return the data portion */
+ if (read_len)
+ *read_buf = response->data;
+}
+
+static inline void virtual_battery_xfer(uint8_t *write_buf, int write_len,
+ uint8_t **read_buf, int read_len)
+{
+ i2c_passthru_xfer(I2C_PORT_VIRTUAL_BATTERY, VIRTUAL_BATTERY_ADDR_FLAGS,
+ write_buf, write_len, read_buf, read_len);
+}
+
+static uint16_t virtual_battery_read16(uint8_t command)
+{
+ uint8_t write_buf[1] = { command };
+ uint8_t *read_buf;
+
+ virtual_battery_xfer(write_buf, 1, &read_buf, 2);
+
+ /* Little endian */
+ return ((int)read_buf[1] << 8) | read_buf[0];
+}
+
+static void virtual_battery_write16(uint8_t command, uint16_t data)
+{
+ uint8_t write_buf[3] = { command };
+
+ *((uint16_t *)&write_buf[1]) = data;
+
+ virtual_battery_xfer(write_buf, 3, NULL, 0);
+}
+
+static int virtual_battery_read_str(uint8_t command, char **read_buf,
+ int read_len)
+{
+ uint8_t write_buf[1] = { command };
+ int len;
+
+ virtual_battery_xfer(write_buf, 1, (uint8_t **)read_buf, read_len);
+
+ /* Battery v2 embeds the strlen in the first byte so shift 1 byte. */
+ len = **read_buf;
+ (*read_buf)++;
+
+ return len;
+}
+
+static void virtual_battery_read_data(uint8_t command, char **read_buf,
+ int read_len)
+{
+ uint8_t write_buf[1] = { command };
+
+ virtual_battery_xfer(write_buf, 1, (uint8_t **)read_buf, read_len);
+}
+
+#define BATTERY_NODE DT_NODELABEL(battery)
+
+ZTEST_USER(virtual_battery, test_read_regs)
+{
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ struct sbat_emul_bat_data *bat = sbat_emul_get_bat_data(emul);
+ int16_t int16;
+ uint16_t word;
+ int expected;
+ char *str;
+ int len;
+
+ /*
+ * Iterate all the registers, which issues the I2C passthru host
+ * command to query the emulated smart battery. Most of the values
+ * are the same as the emulated battery, but with some exceptions.
+ */
+ word = virtual_battery_read16(SB_BATTERY_MODE);
+ zassert_equal(bat->mode, word, "%d != %d", bat->mode, word);
+
+ word = virtual_battery_read16(SB_SERIAL_NUMBER);
+ zassert_equal(bat->sn, word, "%d != %d", bat->sn, word);
+
+ word = virtual_battery_read16(SB_VOLTAGE);
+ zassert_equal(bat->volt, word, "%d != %d", bat->volt, word);
+
+ /* The expected value is calculated */
+ expected = 100 * bat->cap / bat->full_cap;
+ word = virtual_battery_read16(SB_RELATIVE_STATE_OF_CHARGE);
+
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ word = virtual_battery_read16(SB_TEMPERATURE);
+ zassert_equal(bat->temp, word, "%d != %d", bat->temp, word);
+
+ int16 = virtual_battery_read16(SB_CURRENT);
+ zassert_equal(bat->cur, int16, "%d != %d", bat->cur, int16);
+
+ int16 = virtual_battery_read16(SB_AVERAGE_CURRENT);
+ zassert_equal(bat->avg_cur, int16, "%d != %d", bat->avg_cur, int16);
+
+ /* The virtual battery modifies the return value to make kernel happy */
+ expected = BATTERY_LEVEL_SHUTDOWN;
+ word = virtual_battery_read16(SB_MAX_ERROR);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ word = virtual_battery_read16(SB_FULL_CHARGE_CAPACITY);
+ zassert_equal(bat->full_cap, word, "%d != %d", bat->full_cap, word);
+
+ word = virtual_battery_read16(SB_CYCLE_COUNT);
+ zassert_equal(bat->cycle_count, word, "%d != %d", bat->cycle_count,
+ word);
+
+ word = virtual_battery_read16(SB_DESIGN_CAPACITY);
+ zassert_equal(bat->design_cap, word, "%d != %d", bat->design_cap, word);
+
+ word = virtual_battery_read16(SB_REMAINING_CAPACITY);
+ zassert_equal(bat->cap, word, "%d != %d", bat->cap, word);
+
+ len = virtual_battery_read_str(SB_MANUFACTURER_NAME, &str,
+ SB_MAX_STR_SIZE);
+ zassert_equal(bat->mf_name_len, len, "%d != %d", bat->mf_name_len, len);
+ zassert_mem_equal(str, bat->mf_name, bat->mf_name_len, "%s != %s", str,
+ bat->mf_name);
+
+ len = virtual_battery_read_str(SB_DEVICE_NAME, &str, SB_MAX_STR_SIZE);
+ zassert_equal(bat->dev_name_len, len, "%d != %d", bat->dev_name_len,
+ len);
+ zassert_mem_equal(str, bat->dev_name, bat->dev_name_len, "%s != %s",
+ str, bat->dev_name);
+
+ len = virtual_battery_read_str(SB_DEVICE_CHEMISTRY, &str,
+ SB_MAX_STR_SIZE);
+ zassert_equal(bat->dev_chem_len, len, "%d != %d", bat->dev_chem_len,
+ len);
+ zassert_mem_equal(str, bat->dev_chem, bat->dev_chem_len, "%s != %s",
+ str, bat->dev_chem);
+
+ /* Use the API to query the expected value */
+ battery_time_to_full(&expected);
+ word = virtual_battery_read16(SB_AVERAGE_TIME_TO_FULL);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ battery_time_to_empty(&expected);
+ word = virtual_battery_read16(SB_AVERAGE_TIME_TO_EMPTY);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ battery_run_time_to_empty(&expected);
+ word = virtual_battery_read16(SB_RUN_TIME_TO_EMPTY);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ word = virtual_battery_read16(SB_CHARGING_CURRENT);
+ zassert_equal(bat->desired_charg_cur, word, "%d != %d",
+ bat->desired_charg_cur, word);
+
+ word = virtual_battery_read16(SB_CHARGING_VOLTAGE);
+ zassert_equal(bat->desired_charg_volt, word, "%d != %d",
+ bat->desired_charg_volt, word);
+
+ word = virtual_battery_read16(SB_MANUFACTURE_DATE);
+ zassert_equal(bat->mf_date, word, "%d != %d", bat->mf_date, word);
+
+ /* Hard-coded return value: v1.1 without PEC */
+ expected = 0x0011;
+ word = virtual_battery_read16(SB_SPECIFICATION_INFO);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ zassume_ok(battery_status(&expected));
+ word = virtual_battery_read16(SB_BATTERY_STATUS);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ zassume_ok(battery_design_voltage(&expected));
+ word = virtual_battery_read16(SB_DESIGN_VOLTAGE);
+ zassert_equal(expected, word, "%d != %d", expected, word);
+
+ virtual_battery_read_data(SB_MANUFACTURER_DATA, &str, bat->mf_data_len);
+ zassert_mem_equal(str, bat->mf_data, bat->mf_data_len, "%s != %s", str,
+ bat->mf_data);
+
+ /* At present, this command is used nowhere in our codebase. */
+ virtual_battery_read_data(SB_MANUFACTURE_INFO, &str, bat->mf_info_len);
+ zassert_mem_equal(str, bat->mf_info, bat->mf_info_len, "%s != %s", str,
+ bat->mf_info);
+}
+
+ZTEST_USER(virtual_battery, test_write_mfgacc)
+{
+ struct sbat_emul_bat_data *bat;
+ const struct emul *emul = EMUL_DT_GET(BATTERY_NODE);
+ uint16_t cmd = PARAM_OPERATION_STATUS;
+
+ bat = sbat_emul_get_bat_data(emul);
+
+ /* Write the command to the SB_MANUFACTURER_ACCESS and check */
+ virtual_battery_write16(SB_MANUFACTURER_ACCESS, cmd);
+ zassert_equal(bat->mf_access, cmd, "%d != %d", bat->mf_access, cmd);
+}
+
+ZTEST_SUITE(virtual_battery, drivers_predicate_post_main, NULL, NULL, NULL,
+ NULL);
diff --git a/zephyr/test/drivers/default/src/vstore.c b/zephyr/test/drivers/default/src/vstore.c
new file mode 100644
index 0000000000..b4264aaeb3
--- /dev/null
+++ b/zephyr/test/drivers/default/src/vstore.c
@@ -0,0 +1,230 @@
+/* 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 <setjmp.h>
+
+#include <console.h>
+#include <zephyr/fff.h>
+#include <zephyr/shell/shell_dummy.h>
+#include <zephyr/ztest.h>
+
+#include "ec_commands.h"
+#include "host_command.h"
+#include "system.h"
+#include "system_fake.h"
+#include "vstore.h"
+#include "test/drivers/test_state.h"
+
+ZTEST_SUITE(vstore, drivers_predicate_post_main, NULL, NULL, NULL, NULL);
+
+ZTEST_USER(vstore, test_vstore_info)
+{
+ struct ec_response_vstore_info response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_RESPONSE(EC_CMD_VSTORE_INFO, 0, response);
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_equal(response.slot_count, CONFIG_VSTORE_SLOT_COUNT,
+ "response.slot_count = %d", response.slot_count);
+ zassert_equal(response.slot_locked, 0, "response.slot_locked = %#x",
+ response.slot_locked);
+}
+
+ZTEST_USER(vstore, test_vstore_read)
+{
+ struct ec_params_vstore_read params = {
+ .slot = 0,
+ };
+ struct ec_response_vstore_read response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_VSTORE_READ, 0, response, params);
+ uint8_t expect[EC_VSTORE_SLOT_SIZE] = {}; /* data should start as 0 */
+
+ zassert_ok(host_command_process(&args), NULL);
+ zassert_ok(args.result, NULL);
+ zassert_equal(args.response_size, sizeof(response), NULL);
+ zassert_mem_equal(expect, response.data, EC_VSTORE_SLOT_SIZE,
+ "response.data did not match");
+}
+
+ZTEST_USER(vstore, test_vstore_read_bad_slot)
+{
+ struct ec_params_vstore_read params = {
+ .slot = CONFIG_VSTORE_SLOT_COUNT,
+ };
+ struct ec_response_vstore_read response;
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND(EC_CMD_VSTORE_READ, 0, response, params);
+
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM,
+ "Failed to fail on invalid slot %d", params.slot);
+}
+
+ZTEST_USER(vstore, test_vstore_write_bad_slot)
+{
+ struct ec_params_vstore_write params = {
+ .slot = CONFIG_VSTORE_SLOT_COUNT,
+ .data = {},
+ };
+ struct host_cmd_handler_args args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_VSTORE_WRITE, 0, params);
+
+ zassert_equal(host_command_process(&args), EC_RES_INVALID_PARAM,
+ "Failed to fail on invalid slot %d", params.slot);
+}
+
+static void do_vstore_write_read(unsigned int slot)
+{
+ struct ec_params_vstore_write write_params = {
+ .slot = slot,
+ /* .data is set up below */
+ };
+ struct host_cmd_handler_args write_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_VSTORE_WRITE, 0, write_params);
+ struct ec_params_vstore_read read_params = {
+ .slot = slot,
+ };
+ struct ec_response_vstore_read read_response;
+ struct host_cmd_handler_args read_args = BUILD_HOST_COMMAND(
+ EC_CMD_VSTORE_READ, 0, read_response, read_params);
+ struct ec_response_vstore_info info_response;
+ struct host_cmd_handler_args info_args = BUILD_HOST_COMMAND_RESPONSE(
+ EC_CMD_VSTORE_INFO, 0, info_response);
+ int i;
+
+ for (i = 0; i < EC_VSTORE_SLOT_SIZE; i++)
+ write_params.data[i] = i + 1;
+
+ /* Write to a slot */
+ zassert_ok(host_command_process(&write_args), NULL);
+ zassert_ok(write_args.result, NULL);
+
+ /* Check that it is now locked */
+ zassert_ok(host_command_process(&info_args), NULL);
+ zassert_ok(info_args.result, NULL);
+ zassert_equal(info_args.response_size, sizeof(info_response), NULL);
+ zassert_equal(info_response.slot_count, CONFIG_VSTORE_SLOT_COUNT,
+ "response.slot_count = %d", info_response.slot_count);
+ zassert_equal(info_response.slot_locked, 1 << slot,
+ "response.slot_locked = %#x", info_response.slot_locked);
+
+ /* Read to check data */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_ok(read_args.result, NULL);
+ zassert_equal(read_args.response_size, sizeof(read_response), NULL);
+ zassert_mem_equal(write_params.data, read_response.data,
+ EC_VSTORE_SLOT_SIZE, "response.data did not match");
+
+ /* Try to write to it again */
+ zassert_equal(host_command_process(&write_args), EC_RES_ACCESS_DENIED,
+ "Failed to fail on writing locked slot %d",
+ write_params.slot);
+
+ /* Check that it is still locked after that attempt */
+ zassert_ok(host_command_process(&info_args), NULL);
+ zassert_ok(info_args.result, NULL);
+ zassert_equal(info_args.response_size, sizeof(info_response), NULL);
+ zassert_equal(info_response.slot_count, CONFIG_VSTORE_SLOT_COUNT,
+ "response.slot_count = %d", info_response.slot_count);
+ zassert_equal(info_response.slot_locked, 1 << slot,
+ "response.slot_locked = %#x", info_response.slot_locked);
+
+ /* Read to check the data didn't change */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_ok(read_args.result, NULL);
+ zassert_equal(read_args.response_size, sizeof(read_response), NULL);
+ zassert_mem_equal(write_params.data, read_response.data,
+ EC_VSTORE_SLOT_SIZE, "response.data did not match");
+
+ /* Clear locks and try the write again, this time with zero bytes */
+ vstore_clear_lock();
+ memset(write_params.data, '\0', EC_VSTORE_SLOT_SIZE);
+ zassert_ok(host_command_process(&write_args), NULL);
+ zassert_ok(write_args.result, NULL);
+
+ /* Check that it is now locked */
+ zassert_ok(host_command_process(&info_args), NULL);
+ zassert_ok(info_args.result, NULL);
+ zassert_equal(info_args.response_size, sizeof(info_response), NULL);
+ zassert_equal(info_response.slot_count, CONFIG_VSTORE_SLOT_COUNT,
+ "response.slot_count = %d", info_response.slot_count);
+ zassert_equal(info_response.slot_locked, 1 << slot,
+ "response.slot_locked = %#x", info_response.slot_locked);
+
+ /* Read to check the data changed */
+ zassert_ok(host_command_process(&read_args), NULL);
+ zassert_ok(read_args.result, NULL);
+ zassert_equal(read_args.response_size, sizeof(read_response), NULL);
+ zassert_mem_equal(write_params.data, read_response.data,
+ EC_VSTORE_SLOT_SIZE, "response.data did not match");
+
+ /* Clear locks to put things into a normal state */
+ vstore_clear_lock();
+}
+
+ZTEST_USER(vstore, test_vstore_write_read)
+{
+ /* Try on two different slots */
+ zassert_true(CONFIG_VSTORE_SLOT_COUNT >= 2,
+ "Please set CONFIG_VSTORE_SLOT_COUNT to >= 2");
+ do_vstore_write_read(0);
+ do_vstore_write_read(1);
+}
+
+ZTEST_USER(vstore, test_vstore_state)
+{
+ struct ec_params_vstore_write write_params = {
+ .slot = 0,
+ /* .data is set up below */
+ };
+ struct host_cmd_handler_args write_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_VSTORE_WRITE, 0, write_params);
+
+ struct ec_params_reboot_ec reboot_params = {
+ .cmd = EC_REBOOT_JUMP_RW,
+ };
+ struct host_cmd_handler_args reboot_args =
+ BUILD_HOST_COMMAND_PARAMS(EC_CMD_REBOOT_EC, 0, reboot_params);
+ struct ec_response_vstore_info info_response;
+ struct host_cmd_handler_args info_args = BUILD_HOST_COMMAND_RESPONSE(
+ EC_CMD_VSTORE_INFO, 0, info_response);
+ jmp_buf env;
+ int i;
+
+ shell_backend_dummy_clear_output(get_ec_shell());
+ system_common_pre_init();
+
+ for (i = 0; i < EC_VSTORE_SLOT_SIZE; i++)
+ write_params.data[i] = i + 1;
+
+ /* Write to a slot */
+ zassert_ok(host_command_process(&write_args), NULL);
+ zassert_ok(write_args.result, NULL);
+
+ /* Set up so we get back to this test on a reboot */
+ if (!setjmp(env)) {
+ system_fake_setenv(&env);
+
+ /* Reboot to RW */
+ zassert_ok(host_command_process(&reboot_args), NULL);
+
+ /* Does not return unless something went wrong */
+ zassert_unreachable("Failed to reboot");
+ }
+
+ /* the reboot should end up here: check the slot is still locked */
+ zassert_ok(host_command_process(&info_args), NULL);
+ zassert_ok(info_args.result, NULL);
+ zassert_equal(info_args.response_size, sizeof(info_response), NULL);
+ zassert_equal(info_response.slot_count, CONFIG_VSTORE_SLOT_COUNT,
+ "response.slot_count = %d", info_response.slot_count);
+ zassert_equal(info_response.slot_locked, 1 << 0,
+ "response.slot_locked = %#x", info_response.slot_locked);
+
+ /* Clear locks to put things into a normal state */
+ vstore_clear_lock();
+}
diff --git a/zephyr/test/drivers/default/src/watchdog.c b/zephyr/test/drivers/default/src/watchdog.c
new file mode 100644
index 0000000000..958aa3eaaa
--- /dev/null
+++ b/zephyr/test/drivers/default/src/watchdog.c
@@ -0,0 +1,142 @@
+/* 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.
+ */
+
+/**
+ * @file
+ * @brief Unit Tests for watchdog.
+ */
+
+#include <zephyr/device.h>
+#include <zephyr/drivers/watchdog.h>
+
+#include <zephyr/logging/log.h>
+#include <zephyr/kernel.h>
+#include <zephyr/ztest.h>
+
+#include "common.h"
+#include "ec_tasks.h"
+#include <zephyr/fff.h>
+#include "hooks.h"
+#include "test/drivers/stubs.h"
+#include "watchdog.h"
+#include "test/drivers/test_state.h"
+
+#define wdt DEVICE_DT_GET(DT_CHOSEN(cros_ec_watchdog))
+
+/**
+ * @brief Default watchdog timeout plus some time for it to expire.
+ */
+#define DEFAULT_WDT_EXPIRY_MS \
+ (CONFIG_AUX_TIMER_PERIOD_MS + (CONFIG_AUX_TIMER_PERIOD_MS / 2))
+
+/**
+ * @brief Boolean to indicate watchdog alert triggered
+ */
+bool wdt_warning_triggered;
+
+/**
+ * @brief timer to used to validate watchdog expiries.
+ */
+K_TIMER_DEFINE(ktimer, NULL, NULL);
+
+/**
+ * @brief Watchdog test setup handler.
+ */
+static void watchdog_before(void *state)
+{
+ ARG_UNUSED(state);
+ set_test_runner_tid();
+ wdt_warning_triggered = false;
+
+ /* When shuffling need watchdog initialized and running
+ * for other tests.
+ */
+ (void)watchdog_init();
+ (void)wdt_setup(wdt, 0);
+}
+
+/**
+ * @brief Watchdog test teardown handler.
+ */
+static void watchdog_after(void *state)
+{
+ ARG_UNUSED(state);
+ wdt_warning_triggered = false;
+}
+
+/**
+ * @brief TestPurpose: Verify watchdog initialization.
+ *
+ * @details
+ * Validate watchdog initialization.
+ *
+ * Expected Results
+ * - Successful on first init.
+ * - Failure on second init.
+ */
+ZTEST(watchdog, test_watchdog_init)
+{
+ int retval = EC_SUCCESS;
+
+ /* Test already initialized (initialized in watchdog_before) */
+ retval = watchdog_init();
+ zassert_equal(-ENOMEM, retval, "Expected -ENOMEM, returned %d.",
+ retval);
+}
+
+/**
+ * @brief TestPurpose: Verify watchdog reload.
+ *
+ * @details
+ * Validate watchdog is fed.
+ *
+ * Expected Results
+ * - watchdog warning handler function is never triggered
+ */
+ZTEST(watchdog, test_watchdog_reload)
+{
+ int i;
+ int safe_wait_ms = DEFAULT_WDT_EXPIRY_MS / 2;
+
+ zassert_false(wdt_warning_triggered, "Watchdog timer expired early.");
+ for (i = 0; i < 10; i++) {
+ k_timer_start(&ktimer, K_MSEC(safe_wait_ms), K_NO_WAIT);
+ k_busy_wait(safe_wait_ms * 1000);
+ k_timer_stop(&ktimer);
+ watchdog_reload();
+ zassert_false(wdt_warning_triggered,
+ "Watchdog timer expired unexpectedly on loop=%d",
+ i);
+ }
+}
+
+/**
+ * @brief TestPurpose: Verify watchdog timer expires.
+ *
+ * @details
+ * Validate watchdog timer expiry occurs after busy wait
+ *
+ * Expected Results
+ * - Validate watchdog warning handler function is triggered.
+ */
+ZTEST(watchdog, test_wdt_warning_handler)
+{
+ /* Feed the dog so timer is reset */
+ watchdog_reload();
+
+ zassert_false(wdt_warning_triggered, "Watchdog timer expired early.");
+
+ k_timer_start(&ktimer, K_MSEC(DEFAULT_WDT_EXPIRY_MS), K_NO_WAIT);
+ k_busy_wait(DEFAULT_WDT_EXPIRY_MS * 1000);
+ k_timer_stop(&ktimer);
+
+ zassert_true(wdt_warning_triggered, "Watchdog timer did not expire.");
+}
+
+/**
+ * @brief Test Suite: Verifies watchdog functionality.
+ */
+ZTEST_SUITE(watchdog, drivers_predicate_post_main, NULL, watchdog_before,
+ watchdog_after, NULL);