diff options
Diffstat (limited to 'zephyr/test/drivers/src')
-rw-r--r-- | zephyr/test/drivers/src/bb_retimer.c | 16 | ||||
-rw-r--r-- | zephyr/test/drivers/src/bmi160.c | 2 | ||||
-rw-r--r-- | zephyr/test/drivers/src/bmi260.c | 2 | ||||
-rw-r--r-- | zephyr/test/drivers/src/cros_cbi.c | 24 | ||||
-rw-r--r-- | zephyr/test/drivers/src/espi.c | 3 | ||||
-rw-r--r-- | zephyr/test/drivers/src/integration_usb.c | 187 | ||||
-rw-r--r-- | zephyr/test/drivers/src/isl923x.c | 463 | ||||
-rw-r--r-- | zephyr/test/drivers/src/lis2dw12.c | 363 | ||||
-rw-r--r-- | zephyr/test/drivers/src/main.c | 4 | ||||
-rw-r--r-- | zephyr/test/drivers/src/power_common.c | 677 | ||||
-rw-r--r-- | zephyr/test/drivers/src/ppc.c | 328 | ||||
-rw-r--r-- | zephyr/test/drivers/src/ppc_sn5s330.c | 326 | ||||
-rw-r--r-- | zephyr/test/drivers/src/ps8xxx.c | 13 | ||||
-rw-r--r-- | zephyr/test/drivers/src/stubs.c | 144 | ||||
-rw-r--r-- | zephyr/test/drivers/src/tcpci.c | 7 | ||||
-rw-r--r-- | zephyr/test/drivers/src/tcpci_test_common.c | 11 | ||||
-rw-r--r-- | zephyr/test/drivers/src/usb_mux.c | 623 |
17 files changed, 2832 insertions, 361 deletions
diff --git a/zephyr/test/drivers/src/bb_retimer.c b/zephyr/test/drivers/src/bb_retimer.c index 39af8da2c3..02a712aacb 100644 --- a/zephyr/test/drivers/src/bb_retimer.c +++ b/zephyr/test/drivers/src/bb_retimer.c @@ -441,13 +441,7 @@ static void test_bb_init(void) emul = bb_emul_get(BB_RETIMER_ORD); /* Set AP to normal state and wait for chipset task */ - set_mock_power_state(POWER_S0); - /* - * TODO(b/201420132) - setting power state requires to wake up - * TASK_ID_CHIPSET Sleep is required to run chipset task before - * continuing with test - */ - k_msleep(1); + power_set_state(POWER_S0); /* Setup emulator fail on read */ i2c_common_emul_set_read_fail_reg(emul, BB_RETIMER_REG_VENDOR_ID); @@ -508,13 +502,7 @@ static void test_bb_init(void) NULL); /* Set AP to off state and wait for chipset task */ - set_mock_power_state(POWER_G3); - /* - * TODO(b/201420132) - setting power state requires to wake up - * TASK_ID_CHIPSET Sleep is required to run chipset task before - * continuing with test - */ - k_msleep(1); + power_set_state(POWER_G3); /* With AP off, init should fail and pins should be unset */ zassert_equal(EC_ERROR_NOT_POWERED, diff --git a/zephyr/test/drivers/src/bmi160.c b/zephyr/test/drivers/src/bmi160.c index 080ec2ab96..736077b523 100644 --- a/zephyr/test/drivers/src/bmi160.c +++ b/zephyr/test/drivers/src/bmi160.c @@ -1997,7 +1997,7 @@ static void test_bmi_interrupt_handler(void) * interrupt, and ensure the flag is set. */ - uint32_t *mask; + atomic_t *mask; mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE); zassert_true(mask != NULL, diff --git a/zephyr/test/drivers/src/bmi260.c b/zephyr/test/drivers/src/bmi260.c index fb00288367..fb33a4e888 100644 --- a/zephyr/test/drivers/src/bmi260.c +++ b/zephyr/test/drivers/src/bmi260.c @@ -1913,7 +1913,7 @@ void test_interrupt_handler(void) * interrupt, and ensure the flag is set. */ - uint32_t *mask; + atomic_t *mask; mask = task_get_event_bitmap(TASK_ID_MOTIONSENSE); zassert_true(mask != NULL, diff --git a/zephyr/test/drivers/src/cros_cbi.c b/zephyr/test/drivers/src/cros_cbi.c index ee3666f3f0..5209bb2b7f 100644 --- a/zephyr/test/drivers/src/cros_cbi.c +++ b/zephyr/test/drivers/src/cros_cbi.c @@ -39,10 +39,32 @@ static void test_fail_check_match(void) "Expected cbi ssfc to never match CBI_SSFC_VALUE_COUNT"); } +static void test_fw_config(void) +{ + const struct device *dev = device_get_binding(CROS_CBI_LABEL); + uint32_t value; + int ret; + + zassert_not_null(dev, NULL); + + ret = cros_cbi_get_fw_config(dev, 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_A, + "Expected field value to match FW_FIELD_1_A"); + + ret = cros_cbi_get_fw_config(dev, 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"); +} + void test_suite_cros_cbi(void) { ztest_test_suite(cros_cbi, ztest_unit_test(test_check_match), - ztest_unit_test(test_fail_check_match)); + ztest_unit_test(test_fail_check_match), + ztest_unit_test(test_fw_config)); ztest_run_test_suite(cros_cbi); } diff --git a/zephyr/test/drivers/src/espi.c b/zephyr/test/drivers/src/espi.c index c852f1b771..81cbac30da 100644 --- a/zephyr/test/drivers/src/espi.c +++ b/zephyr/test/drivers/src/espi.c @@ -13,7 +13,8 @@ static void test_host_command_get_protocol_info(void) { struct ec_response_get_protocol_info response; struct host_cmd_handler_args args = - BUILD_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, 0, response); + BUILD_HOST_COMMAND_RESPONSE(EC_CMD_GET_PROTOCOL_INFO, 0, + response); zassert_ok(host_command_process(&args), NULL); zassert_ok(args.result, NULL); diff --git a/zephyr/test/drivers/src/integration_usb.c b/zephyr/test/drivers/src/integration_usb.c new file mode 100644 index 0000000000..c61a706002 --- /dev/null +++ b/zephyr/test/drivers/src/integration_usb.c @@ -0,0 +1,187 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <zephyr.h> +#include <ztest.h> +#include <drivers/gpio/gpio_emul.h> + +#include "battery_smart.h" +#include "ec_commands.h" +#include "ec_tasks.h" +#include "emul/emul_smart_battery.h" +#include "emul/tcpc/emul_tcpci.h" +#include "emul/tcpc/emul_tcpci_partner_src.h" +#include "host_command.h" +#include "tcpm/tcpci.h" + +#define TCPCI_EMUL_LABEL DT_NODELABEL(tcpci_emul) +#define BATTERY_ORD DT_DEP_ORD(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) + +static void init_tcpm(void) +{ + const struct emul *tcpci_emul = + emul_get_binding(DT_LABEL(TCPCI_EMUL_LABEL)); + struct i2c_emul *i2c_emul; + struct sbat_emul_bat_data *bat; + const struct device *gpio_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_AC_OK_PATH, gpios)); + + set_test_runner_tid(); + zassert_ok(tcpci_tcpm_init(0), 0); + pd_set_suspend(0, 0); + /* Reset to disconnected state. */ + zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul), NULL); + + /* Battery defaults to charging, so reset to not charging. */ + i2c_emul = sbat_emul_get_ptr(BATTERY_ORD); + bat = sbat_emul_get_bat_data(i2c_emul); + bat->cur = -5; + + zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_AC_OK_PIN, 0), NULL); +} + +static void remove_emulated_devices(void) +{ + const struct emul *tcpci_emul = + emul_get_binding(DT_LABEL(TCPCI_EMUL_LABEL)); + /* TODO: This function should trigger gpios to signal there is nothing + * attached to the port. + */ + zassert_ok(tcpci_emul_disconnect_partner(tcpci_emul), NULL); +} + +static void test_attach_compliant_charger(void) +{ + const struct emul *tcpci_emul = + emul_get_binding(DT_LABEL(TCPCI_EMUL_LABEL)); + struct i2c_emul *i2c_emul; + uint16_t battery_status; + struct tcpci_src_emul_data my_charger; + const struct device *gpio_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_AC_OK_PATH, gpios)); + + /* Verify battery not charging. */ + i2c_emul = sbat_emul_get_ptr(BATTERY_ORD); + zassert_ok(sbat_emul_get_word_val(i2c_emul, SB_BATTERY_STATUS, + &battery_status), + NULL); + zassert_not_equal(battery_status & STATUS_DISCHARGING, 0, + "Battery is not discharging: %d", battery_status); + + /* TODO? Send host command to verify PD_ROLE_DISCONNECTED. */ + + /* Attach emulated charger. */ + zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_AC_OK_PIN, 1), NULL); + tcpci_src_emul_init(&my_charger); + zassert_ok(tcpci_src_emul_connect_to_tcpci(&my_charger, tcpci_emul), + NULL); + + /* Wait for current ramp. */ + k_sleep(K_SECONDS(10)); + + /* Verify battery charging. */ + zassert_ok(sbat_emul_get_word_val(i2c_emul, SB_BATTERY_STATUS, + &battery_status), + NULL); + zassert_equal(battery_status & STATUS_DISCHARGING, 0, + "Battery is discharging: %d", battery_status); + /* TODO: Also check voltage, current, etc. */ +} + +static void test_attach_pd_charger(void) +{ + const struct emul *tcpci_emul = + emul_get_binding(DT_LABEL(TCPCI_EMUL_LABEL)); + struct i2c_emul *i2c_emul; + uint16_t battery_status; + struct tcpci_src_emul_data my_charger; + const struct device *gpio_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_AC_OK_PATH, gpios)); + struct ec_params_charge_state charge_params; + struct ec_response_charge_state charge_response; + struct host_cmd_handler_args args = BUILD_HOST_COMMAND( + EC_CMD_CHARGE_STATE, 0, charge_response, charge_params); + + /* + * TODO(b/209907297): Implement the steps of the test beyond USB default + * charging. + */ + + /* 1. Configure source PDOs of partner (probably fixed source 5V 3A + * and fixed source 20V 3A). Currently, the partner emulator only + * supports the default USB power PDO. + */ + + /* Attach emulated charger. This will send Source Capabilities. */ + zassert_ok(gpio_emul_input_set(gpio_dev, GPIO_AC_OK_PIN, 1), NULL); + tcpci_src_emul_init(&my_charger); + zassert_ok(tcpci_src_emul_connect_to_tcpci(&my_charger, tcpci_emul), + NULL); + + /* Wait for current ramp. */ + k_sleep(K_SECONDS(10)); + + /* Verify battery charging. */ + i2c_emul = sbat_emul_get_ptr(BATTERY_ORD); + zassert_ok(sbat_emul_get_word_val(i2c_emul, SB_BATTERY_STATUS, + &battery_status), + NULL); + zassert_equal(battery_status & STATUS_DISCHARGING, 0, + "Battery is discharging: %d", battery_status); + + /* + * 2. Check charging current and voltage (should be 5V, default USB + * current); make sure that reports from battery and PD host commands + * match; check that host command reports no active PDO. + */ + /* + * TODO(b/209907297): Also check the corresponding PD state and + * encapsulate this for use in other tests. + */ + charge_params.chgnum = 0; + charge_params.cmd = CHARGE_STATE_CMD_GET_STATE; + zassert_ok(host_command_process(&args), "Failed to get charge state"); + zassert_true(charge_response.get_state.ac, "USB default but AC absent"); + zassert_equal(charge_response.get_state.chg_voltage, 5000, + "USB default volage %dmV", + charge_response.get_state.chg_voltage); + zassert_true(charge_response.get_state.chg_current > 0, + "USB default current %dmA", + charge_response.get_state.chg_current); + + /* + * 3. Wait for SenderResponseTimeout. Expect TCPM to send Request. + * We could verify that the Request references the expected PDO, but + * the voltage/current/PDO checks at the end of the test should all be + * wrong if the requested PDO was wrong here. + */ + + /* + * 4. Send Accept and PS_RDY from partner with appropriate delay between + * them. Emulate supplying VBUS at the requested voltage/current before + * PS_RDY. + */ + + /* + * 5. Check the charging voltage and current. Cross-check the PD state, + * the battery/charger state, and the active PDO as reported by the PD + * state. + */ +} + +void test_suite_integration_usb(void) +{ + ztest_test_suite(integration_usb, + ztest_user_unit_test_setup_teardown( + test_attach_compliant_charger, init_tcpm, + remove_emulated_devices), + ztest_user_unit_test_setup_teardown( + test_attach_pd_charger, init_tcpm, + remove_emulated_devices)); + ztest_run_test_suite(integration_usb); +} diff --git a/zephyr/test/drivers/src/isl923x.c b/zephyr/test/drivers/src/isl923x.c index e1b1dbc020..27ce29984a 100644 --- a/zephyr/test/drivers/src/isl923x.c +++ b/zephyr/test/drivers/src/isl923x.c @@ -5,6 +5,7 @@ #include <ztest.h> #include <drivers/emul.h> +#include <fff.h> #include "battery.h" #include "battery_smart.h" @@ -14,6 +15,7 @@ #include "emul/emul_common_i2c.h" #include "emul/emul_isl923x.h" #include "system.h" +#include "test_mocks.h" BUILD_ASSERT(CONFIG_CHARGER_SENSE_RESISTOR == 10 || CONFIG_CHARGER_SENSE_RESISTOR == 5); @@ -673,24 +675,451 @@ static void test_init(void) system_jumped_late_mock.ret_val = false; } +static void test_isl923x_is_acok(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_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(i2c_emul, 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(i2c_emul, + 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"); +} + +static void test_isl923x_enable_asgate(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_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(i2c_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(i2c_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, struct i2c_emul *, int, uint8_t *, + int, void *); +FAKE_VALUE_FUNC(int, hibernate_mock_write_fn, struct i2c_emul *, int, uint8_t, + int, void *); + +/** + * @brief Setup function for the hibernate tests. + */ +static void hibernate_test_setup(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + /* 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(i2c_emul, hibernate_mock_read_fn, NULL); + i2c_common_emul_set_write_func(i2c_emul, hibernate_mock_write_fn, NULL); + + /* Don't fail on any register access */ + i2c_common_emul_set_read_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); + i2c_common_emul_set_write_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); +} + +/** + * @brief Teardown function for the hibernate tests. + */ +static void hibernate_test_teardown(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + /* Clear the mock read/write functions */ + i2c_common_emul_set_read_func(i2c_emul, NULL, NULL); + i2c_common_emul_set_write_func(i2c_emul, NULL, NULL); + + /* Don't fail on any register access */ + i2c_common_emul_set_read_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); + i2c_common_emul_set_write_fail_reg(i2c_emul, + I2C_COMMON_EMUL_NO_FAIL_REG); +} + +static void test_isl923x_hibernate__happy_path(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + uint16_t actual; + + raa489000_hibernate(CHARGER_NUM, false); + + /* Check ISL923X_REG_CONTROL0 */ + actual = isl923x_emul_peek_reg(i2c_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(i2c_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(i2c_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(i2c_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); + } +} + +static void test_isl923x_hibernate__invalid_charger_number(void) +{ + /* 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"); +} + +static void test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL0(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + i2c_common_emul_set_read_fail_reg(i2c_emul, 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); +} + +static void test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL1(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + i2c_common_emul_set_read_fail_reg(i2c_emul, 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); +} + +static void test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL3(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + i2c_common_emul_set_read_fail_reg(i2c_emul, 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); +} + +static void test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL4(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + + i2c_common_emul_set_read_fail_reg(i2c_emul, 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); +} + +static void test_isl923x_hibernate__adc_disable(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + uint16_t expected; + + raa489000_hibernate(CHARGER_NUM, true); + + /* Check ISL9238_REG_CONTROL3 (disable_adc = true) */ + expected = isl923x_emul_peek_reg(i2c_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); +} + +static void test_isl9238c_hibernate(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + uint16_t control1_expected, control2_expected, control3_expected; + int rv; + + /* Part 1: Happy path */ + control1_expected = + (isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL1) & + ~ISL923X_C1_ENABLE_PSYS) | + ISL923X_C1_DISABLE_MON; + control2_expected = + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2) | + ISL923X_C2_COMPARATOR; + control3_expected = + isl923x_emul_peek_reg(i2c_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(i2c_emul, ISL923X_REG_CONTROL1), + control1_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL1), + control1_expected); + zassert_equal(isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2), + control2_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2), + control2_expected); + zassert_equal(isl923x_emul_peek_reg(i2c_emul, ISL9238_REG_CONTROL3), + control3_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_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(i2c_emul, 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); + } +} + +static void test_isl9238c_resume(void) +{ + const struct emul *isl923x_emul = ISL923X_EMUL; + struct i2c_emul *i2c_emul = isl923x_emul_get_i2c_emul(isl923x_emul); + uint16_t control1_expected, control2_expected, control3_expected; + int rv; + + /* Part 1: Happy path */ + control1_expected = + (isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL1) & + ~ISL923X_C1_DISABLE_MON) | ISL923X_C1_ENABLE_PSYS + ; + control2_expected = + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2) & + ~ISL923X_C2_COMPARATOR; + control3_expected = + isl923x_emul_peek_reg(i2c_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(i2c_emul, ISL923X_REG_CONTROL1), + control1_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL1), + control1_expected); + zassert_equal(isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2), + control2_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_emul, ISL923X_REG_CONTROL2), + control2_expected); + zassert_equal(isl923x_emul_peek_reg(i2c_emul, ISL9238_REG_CONTROL3), + control3_expected, + "Unexpected register value 0x%02x. Should be 0x%02x", + isl923x_emul_peek_reg(i2c_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(i2c_emul, 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); + } +} + void test_suite_isl923x(void) { - ztest_test_suite(isl923x, - ztest_unit_test(test_isl923x_set_current), - ztest_unit_test(test_isl923x_set_voltage), - ztest_unit_test(test_isl923x_set_input_current_limit), - ztest_unit_test(test_manufacturer_id), - ztest_unit_test(test_device_id), - ztest_unit_test(test_options), - ztest_unit_test(test_get_info), - ztest_unit_test(test_status), - ztest_unit_test(test_set_mode), - ztest_unit_test(test_post_init), - ztest_unit_test(test_set_ac_prochot), - ztest_unit_test(test_set_dc_prochot), - ztest_unit_test(test_comparator_inversion), - ztest_unit_test(test_discharge_on_ac), - ztest_unit_test(test_get_vbus_voltage), - ztest_unit_test(test_init)); + ztest_test_suite( + isl923x, ztest_unit_test(test_isl923x_set_current), + ztest_unit_test(test_isl923x_set_voltage), + ztest_unit_test(test_isl923x_set_input_current_limit), + ztest_unit_test(test_manufacturer_id), + ztest_unit_test(test_device_id), ztest_unit_test(test_options), + ztest_unit_test(test_get_info), ztest_unit_test(test_status), + ztest_unit_test(test_set_mode), ztest_unit_test(test_post_init), + ztest_unit_test(test_set_ac_prochot), + ztest_unit_test(test_set_dc_prochot), + ztest_unit_test(test_comparator_inversion), + ztest_unit_test(test_discharge_on_ac), + ztest_unit_test(test_get_vbus_voltage), + ztest_unit_test(test_init), + ztest_unit_test(test_isl923x_is_acok), + ztest_unit_test(test_isl923x_enable_asgate), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__happy_path, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__invalid_charger_number, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL0, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__fail_at_ISL923X_REG_CONTROL1, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL3, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__fail_at_ISL9238_REG_CONTROL4, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown( + test_isl923x_hibernate__adc_disable, + hibernate_test_setup, hibernate_test_teardown), + ztest_unit_test_setup_teardown(test_isl9238c_hibernate, + hibernate_test_teardown, + hibernate_test_teardown), + ztest_unit_test_setup_teardown(test_isl9238c_resume, + hibernate_test_teardown, + hibernate_test_teardown)); ztest_run_test_suite(isl923x); } diff --git a/zephyr/test/drivers/src/lis2dw12.c b/zephyr/test/drivers/src/lis2dw12.c index 287430e65b..24218aea9f 100644 --- a/zephyr/test/drivers/src/lis2dw12.c +++ b/zephyr/test/drivers/src/lis2dw12.c @@ -14,9 +14,34 @@ #define EMUL_LABEL DT_LABEL(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 void lis2dw12_setup(void) { lis2dw12_emul_reset(emul_get_binding(EMUL_LABEL)); + + /* Reset certain sensor struct values */ + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + + ms->current_range = 0; } static void test_lis2dw12_init__fail_read_who_am_i(void) @@ -97,23 +122,351 @@ static void test_lis2dw12_init__fail_set_bdu(void) "expected at least one soft reset"); } +static void test_lis2dw12_init__fail_set_lir(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + i2c_common_emul_set_read_fail_reg(lis2dw12_emul_to_i2c_emul(emul), + 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(struct i2c_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; +} + +static void test_lis2dw12_init__fail_set_power_mode(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct motion_sensor_t *ms = &motion_sensors[LIS2DW12_SENSOR_ID]; + int rv; + + i2c_common_emul_set_write_func( + lis2dw12_emul_to_i2c_emul(emul), + 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"); +} + +static void test_lis2dw12_init__success(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + 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); +} + +static void test_lis2dw12_set_power_mode(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + 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(lis2dw12_emul_to_i2c_emul(emul), + 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); +} + +static void test_lis2dw12_set_range(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + 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(lis2dw12_emul_to_i2c_emul(emul), + 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); +} + +static void test_lis2dw12_set_rate(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct i2c_emul *i2c_emul = lis2dw12_emul_to_i2c_emul(emul); + 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(i2c_emul), + LIS2DW12_ODR_POWER_OFF_VAL, + "Output data rate should be %d but got %d", + LIS2DW12_ODR_POWER_OFF_VAL, + lis2dw12_emul_peek_odr(i2c_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(i2c_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(i2c_emul); + uint8_t lpmode_bits = lis2dw12_emul_peek_lpmode(i2c_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); + } + } +} + +static void test_lis2dw12_read(void) +{ + const struct emul *emul = emul_get_binding(EMUL_LABEL); + struct i2c_emul *i2c_emul = lis2dw12_emul_to_i2c_emul(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(i2c_emul, 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(i2c_emul, + 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(i2c_emul, 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(i2c_emul, + 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); +} + void test_suite_lis2dw12(void) { ztest_test_suite(lis2dw12, ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_read_who_am_i, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_who_am_i, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_write_soft_reset, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__timeout_read_soft_reset, - lis2dw12_setup, unit_test_noop), + lis2dw12_setup, lis2dw12_setup), ztest_unit_test_setup_teardown( test_lis2dw12_init__fail_set_bdu, - lis2dw12_setup, unit_test_noop)); + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__fail_set_lir, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__fail_set_power_mode, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_init__success, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_power_mode, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_range, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_set_rate, + lis2dw12_setup, lis2dw12_setup), + ztest_unit_test_setup_teardown( + test_lis2dw12_read, + lis2dw12_setup, lis2dw12_setup) + ); ztest_run_test_suite(lis2dw12); } diff --git a/zephyr/test/drivers/src/main.c b/zephyr/test/drivers/src/main.c index 05fe12c8fc..687ea0785e 100644 --- a/zephyr/test/drivers/src/main.c +++ b/zephyr/test/drivers/src/main.c @@ -30,6 +30,8 @@ extern void test_suite_ppc_sn5s330(void); extern void test_suite_cros_cbi(void); extern void test_suite_tcpci(void); extern void test_suite_ps8xxx(void); +extern void test_suite_integration_usb(void); +extern void test_suite_power_common(void); void test_main(void) { @@ -61,4 +63,6 @@ void test_main(void) test_suite_cros_cbi(); test_suite_tcpci(); test_suite_ps8xxx(); + test_suite_integration_usb(); + test_suite_power_common(); } diff --git a/zephyr/test/drivers/src/power_common.c b/zephyr/test/drivers/src/power_common.c new file mode 100644 index 0000000000..86e03ea38c --- /dev/null +++ b/zephyr/test/drivers/src/power_common.c @@ -0,0 +1,677 @@ +/* Copyright 2021 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <ztest.h> +#include <drivers/gpio.h> +#include <drivers/gpio/gpio_emul.h> +#include <shell/shell.h> +#include <shell/shell_uart.h> + +#include "chipset.h" +#include "common.h" +#include "extpower.h" +#include "hooks.h" +#include "host_command.h" +#include "power.h" +#include "stubs.h" +#include "task.h" + +#include "emul/emul_common_i2c.h" +#include "emul/emul_smart_battery.h" + +#include "battery.h" +#include "battery_smart.h" + +#define BATTERY_ORD DT_DEP_ORD(DT_NODELABEL(battery)) + +#define GPIO_ACOK_OD_NODE DT_PATH(named_gpios, acok_od) +#define GPIO_ACOK_OD_PIN DT_GPIO_PIN(GPIO_ACOK_OD_NODE, gpios) + +/* 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 */ +static void test_power_chipset_in_state(void) +{ + 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 */ +static void test_power_chipset_in_or_transitioning_to_state(void) +{ + 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 */ +static void test_power_exit_hard_off(void) +{ + /* Force initial state */ + force_power_state(true, POWER_G3); + zassert_equal(POWER_G3, power_get_state(), NULL); + + /* Stop forcing state */ + force_power_state(false, 0); + + /* Test after exit hard off, we reach G3S5 */ + chipset_exit_hard_off(); + /* + * TODO(b/201420132) - chipset_exit_hard_off() is waking up + * TASK_ID_CHIPSET Sleep is required to run chipset task before + * continuing with test + */ + k_msleep(1); + zassert_equal(POWER_G3S5, power_get_state(), NULL); + + /* Go back to G3 and check we stay there */ + force_power_state(true, POWER_G3); + force_power_state(false, 0); + zassert_equal(POWER_G3, power_get_state(), NULL); + + /* Exit G3 again */ + chipset_exit_hard_off(); + /* TODO(b/201420132) - see comment above */ + k_msleep(1); + zassert_equal(POWER_G3S5, power_get_state(), NULL); + + /* Go to S5G3 */ + force_power_state(true, POWER_S5G3); + zassert_equal(POWER_S5G3, power_get_state(), NULL); + + /* Test exit hard off in S5G3 -- should immedietly exit G3 */ + chipset_exit_hard_off(); + /* Go back to G3 and check we exit it to G3S5 */ + force_power_state(true, POWER_G3); + zassert_equal(POWER_G3S5, power_get_state(), NULL); + + /* Test exit hard off is cleared on entering S5 */ + chipset_exit_hard_off(); + force_power_state(true, POWER_S5); + zassert_equal(POWER_S5, power_get_state(), NULL); + /* Go back to G3 and check we stay in G3 */ + force_power_state(true, POWER_G3); + force_power_state(false, 0); + zassert_equal(POWER_G3, power_get_state(), NULL); + + /* Test exit hard off doesn't work on other states */ + force_power_state(true, POWER_S5S3); + force_power_state(false, 0); + zassert_equal(POWER_S5S3, power_get_state(), NULL); + chipset_exit_hard_off(); + /* TODO(b/201420132) - see comment above */ + k_msleep(1); + + /* Go back to G3 and check we stay in G3 */ + force_power_state(true, POWER_G3); + force_power_state(false, 0); + zassert_equal(POWER_G3, power_get_state(), NULL); +} + +/* Test reboot ap on g3 host command is triggering reboot */ +static void test_power_reboot_ap_at_g3(void) +{ + 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 = ¶ms, + .params_size = sizeof(params), + }; + int offset_for_still_in_g3_test; + int delay_ms; + + /* Force initial state S0 */ + force_power_state(true, POWER_S0); + 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 */ + force_power_state(true, POWER_G3); + 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 */ + force_power_state(true, POWER_G3); + force_power_state(false, 0); + zassert_equal(POWER_G3, power_get_state(), NULL); + /* + * Arbitrary chosen offset before end of reboot delay to check if G3 + * state wasn't left too soon + */ + offset_for_still_in_g3_test = 50; + k_msleep(delay_ms - offset_for_still_in_g3_test); + /* Test if still in G3 */ + zassert_equal(POWER_G3, power_get_state(), NULL); + /* + * power_common_state() use for loop with 100ms sleeps. msleep() wait at + * least specified time, so wait 10% longer than specified delay to take + * this into account. + */ + k_msleep(offset_for_still_in_g3_test + delay_ms / 10); + /* Test if reboot is triggered */ + zassert_equal(POWER_G3S5, power_get_state(), NULL); +} + +/** Test setting cutoff and stay-up battery levels through host command */ +static void test_power_hc_smart_discharge(void) +{ + 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 i2c_emul *emul; + int hours_to_zero; + int hibern_drate; + int cutoff_drate; + int stayup_cap; + int cutoff_cap; + + emul = sbat_emul_get_ptr(BATTERY_ORD); + + /* 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(emul, SB_FULL_CHARGE_CAPACITY); + zassert_equal(EC_RES_UNAVAILABLE, host_command_process(&args), NULL); + i2c_common_emul_set_read_fail_reg(emul, 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. + */ +static void test_power_board_system_is_idle(void) +{ + 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; + struct i2c_emul *emul; + uint64_t last_shutdown_time = 0; + uint64_t target; + uint64_t now; + + emul = sbat_emul_get_ptr(BATTERY_ORD); + 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(emul, 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(emul, 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); +} + +/** + * 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) +{ + 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 device *acok_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_ACOK_OD_NODE, gpios)); + struct sbat_emul_bat_data *bat; + struct i2c_emul *emul; + + emul = sbat_emul_get_ptr(BATTERY_ORD); + 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 */ + force_power_state(true, POWER_G3); + zassert_equal(POWER_G3, power_get_state(), NULL); + + /* Stop forcing state */ + force_power_state(false, 0); + + /* Disable AC */ + zassert_ok(gpio_emul_input_set(acok_dev, GPIO_ACOK_OD_PIN, 0), NULL); + msleep(CONFIG_EXTPOWER_DEBOUNCE_MS + 1); + zassert_equal(0, extpower_is_present(), NULL); + + RESET_FAKE(system_hibernate); +} + +/** Test setting hibernation delay through host command */ +static void test_power_hc_hibernation_delay(void) +{ + 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); + const struct device *acok_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_ACOK_OD_NODE, gpios)); + uint32_t h_delay; + int sleep_time; + + /* 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 */ + zassert_ok(gpio_emul_input_set(acok_dev, GPIO_ACOK_OD_PIN, 1), NULL); + msleep(CONFIG_EXTPOWER_DEBOUNCE_MS + 1); + zassert_equal(1, extpower_is_present(), NULL); + + /* 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 */ + zassert_ok(gpio_emul_input_set(acok_dev, GPIO_ACOK_OD_PIN, 0), NULL); + msleep(CONFIG_EXTPOWER_DEBOUNCE_MS + 1); + zassert_equal(0, extpower_is_present(), NULL); + + /* Go to different state */ + force_power_state(true, POWER_G3S5); + zassert_equal(POWER_G3S5, power_get_state(), NULL); + + /* Stop forcing state */ + force_power_state(false, 0); + + /* 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 */ +static void test_power_cmd_hibernation_delay(void) +{ + uint32_t h_delay; + int sleep_time; + + /* Test success on call without argument */ + zassert_equal(EC_SUCCESS, + shell_execute_cmd(shell_backend_uart_get_ptr(), + "hibdelay"), NULL); + + /* Test error on hibernation delay argument that is not a number */ + zassert_equal(EC_ERROR_PARAM1, + shell_execute_cmd(shell_backend_uart_get_ptr(), + "hibdelay test1"), NULL); + + /* Set hibernate delay */ + h_delay = 3; + zassert_equal(EC_SUCCESS, + shell_execute_cmd(shell_backend_uart_get_ptr(), + "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); +} + +void test_suite_power_common(void) +{ + ztest_test_suite(power_common, + ztest_unit_test(test_power_chipset_in_state), + ztest_unit_test( + test_power_chipset_in_or_transitioning_to_state), + ztest_unit_test(test_power_exit_hard_off), + ztest_unit_test(test_power_reboot_ap_at_g3), + ztest_unit_test(test_power_hc_smart_discharge), + ztest_unit_test(test_power_board_system_is_idle), + ztest_unit_test_setup_teardown( + test_power_hc_hibernation_delay, + setup_hibernation_delay, unit_test_noop), + ztest_unit_test_setup_teardown( + test_power_cmd_hibernation_delay, + setup_hibernation_delay, unit_test_noop)); + ztest_run_test_suite(power_common); +} diff --git a/zephyr/test/drivers/src/ppc.c b/zephyr/test/drivers/src/ppc.c index 740c7a0aea..5a729de3d6 100644 --- a/zephyr/test/drivers/src/ppc.c +++ b/zephyr/test/drivers/src/ppc.c @@ -23,6 +23,109 @@ static const int syv682x_port = 1; +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"); +} + +static void test_ppc_syv682x_init(void) +{ + struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); + const struct device *gpio_dev = + DEVICE_DT_GET(DT_GPIO_CTLR(GPIO_USB_C1_FRS_EN_PATH, gpios)); + uint8_t reg; + int ilim; + + /* + * With a dead battery, the device powers up sinking VBUS, and the + * driver should keep that going.. + */ + zassert_ok(syv682x_emul_set_reg(emul, SYV682X_CONTROL_1_REG, + SYV682X_CONTROL_1_CH_SEL), NULL); + syv682x_emul_set_condition(emul, SYV682X_STATUS_VSAFE_5V, + SYV682X_CONTROL_4_NONE); + zassert_ok(ppc_init(syv682x_port), "PPC init failed"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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"); + + /* With VBUS at vSafe0V, init should set the default configuration. */ + zassert_ok(syv682x_emul_set_reg(emul, SYV682X_CONTROL_1_REG, + SYV682X_CONTROL_1_PWR_ENB), NULL); + syv682x_emul_set_condition(emul, SYV682X_STATUS_VSAFE_0V, + SYV682X_CONTROL_4_NONE); + zassert_ok(ppc_init(syv682x_port), "PPC init failed"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_REG, ®), + NULL); + check_control_1_default_init(reg); + + /* With sink disabled, init should do the same thing. */ + zassert_ok(syv682x_emul_set_reg(emul, SYV682X_CONTROL_1_REG, + SYV682X_CONTROL_1_CH_SEL), NULL); + syv682x_emul_set_condition(emul, SYV682X_STATUS_VSAFE_0V, + SYV682X_CONTROL_4_NONE); + zassert_ok(ppc_init(syv682x_port), "PPC init failed"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_REG, ®), + NULL); + check_control_1_default_init(reg); + + /* + * 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(gpio_dev, GPIO_USB_C1_FRS_EN_PORT), + 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); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_2_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); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_3_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); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_4_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); + + /* Disable the power path again. */ + zassert_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); + +} + static void test_ppc_syv682x_vbus_enable(void) { struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); @@ -51,21 +154,18 @@ static void test_ppc_syv682x_interrupt(void) uint8_t reg; /* An OC event less than 100 ms should not cause VBUS to turn off. */ - syv682x_emul_set_status(emul, SYV682X_STATUS_OC_5V); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_OC_5V, + SYV682X_CONTROL_4_NONE); msleep(50); - syv682x_interrupt(syv682x_port); zassert_true(ppc_is_sourcing_vbus(syv682x_port), "PPC is not sourcing VBUS after 50 ms OC"); /* But one greater than 100 ms should. */ - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ msleep(60); - syv682x_interrupt(syv682x_port); zassert_false(ppc_is_sourcing_vbus(syv682x_port), "PPC is sourcing VBUS after 100 ms OC"); - syv682x_emul_set_status(emul, 0x0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); /* * TODO(b/190519131): Organize the tests to be more hermetic and avoid * the following issue: The driver triggers overcurrent protection. If @@ -81,24 +181,24 @@ static void test_ppc_syv682x_interrupt(void) */ zassert_ok(ppc_vbus_source_enable(syv682x_port, true), "Source enable failed"); - syv682x_emul_set_status(emul, SYV682X_STATUS_TSD); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_TSD, + SYV682X_CONTROL_4_NONE); msleep(1); zassert_false(ppc_is_sourcing_vbus(syv682x_port), "PPC is sourcing power after TSD"); - syv682x_emul_set_status(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); /* An OVP event should cause the driver to disable the source path. */ zassert_ok(ppc_vbus_source_enable(syv682x_port, true), "Source enable failed"); - syv682x_emul_set_status(emul, SYV682X_STATUS_OVP); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_OVP, + SYV682X_CONTROL_4_NONE); msleep(1); zassert_false(ppc_is_sourcing_vbus(syv682x_port), "PPC is sourcing power after OVP"); - syv682x_emul_set_status(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); /* * A high-voltage OC while sinking should cause the driver to try to @@ -107,52 +207,45 @@ static void test_ppc_syv682x_interrupt(void) */ zassert_ok(ppc_vbus_sink_enable(syv682x_port, true), "Sink enable failed"); - syv682x_emul_set_status(emul, SYV682X_STATUS_OC_HV); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_OC_HV, + SYV682X_CONTROL_4_NONE); msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_REG, ®), "Reading CONTROL_1 failed"); zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB, 0, "Power path disabled after HV_OC handled"); - syv682x_emul_set_status(emul, SYV682X_STATUS_OC_HV); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_OC_HV, + SYV682X_CONTROL_4_NONE); msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_REG, ®), "Reading CONTROL_1 failed"); zassert_equal(reg & SYV682X_CONTROL_1_PWR_ENB, 0, "Power path disabled after HV_OC handled"); - syv682x_emul_set_status(emul, SYV682X_STATUS_OC_HV); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_OC_HV, + SYV682X_CONTROL_4_NONE); msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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"); - syv682x_emul_set_status(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); /* * 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_control_4(emul, SYV682X_CONTROL_4_VCONN_OCP); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_VCONN_OCP); msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_4_REG, ®), "Reading CONTROL_4 failed"); zassert_true(reg & (SYV682X_CONTROL_4_VCONN1 | SYV682X_CONTROL_4_VCONN2), "VCONN disabled after initial VCONN OC"); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ msleep(50); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ - msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_4_REG, ®), "Reading CONTROL_4 failed"); zassert_true(reg & @@ -162,17 +255,14 @@ static void test_ppc_syv682x_interrupt(void) * But if the event keeps going for over 100 ms continuously, the driver * should turn VCONN off. */ - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ msleep(60); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ - msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_4_REG, ®), "Reading CONTROL_4 failed"); zassert_false(reg & (SYV682X_CONTROL_4_VCONN1 | SYV682X_CONTROL_4_VCONN2), "VCONN enabled after long VCONN OC"); - syv682x_emul_set_control_4(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); /* * A VCONN over-voltage (VBAT_OVP) event will cause the device to @@ -181,9 +271,8 @@ static void test_ppc_syv682x_interrupt(void) * driver should then run generic CC over-voltage handling. */ ppc_set_vconn(syv682x_port, true); - syv682x_emul_set_control_4(emul, SYV682X_CONTROL_4_VBAT_OVP); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_VBAT_OVP); msleep(1); zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_4_REG, ®), "Reading CONTROL_4 failed"); @@ -199,7 +288,8 @@ static void test_ppc_syv682x_interrupt(void) * to a CC over-voltage event. There is currently no easy way to test * that a Hard Reset occurred. */ - syv682x_emul_set_control_4(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); } static void test_ppc_syv682x_frs(void) @@ -252,23 +342,167 @@ static void test_ppc_syv682x_frs(void) * An FRS event when the PPC is Sink should cause the PPC to switch from * Sink to Source. */ - syv682x_emul_set_status(emul, SYV682X_STATUS_FRS); - syv682x_interrupt(syv682x_port); - /* TODO(b/201420132): Simulate passage of time instead of sleeping. */ + syv682x_emul_set_condition(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_status(emul, 0); + syv682x_emul_set_condition(emul, SYV682X_STATUS_NONE, + SYV682X_CONTROL_4_NONE); +} + +static void test_ppc_syv682x_source_current_limit(void) +{ + struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); + 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"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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); + + zassert_ok(ppc_set_vbus_source_current_limit(syv682x_port, + TYPEC_RP_1A5), + "Could not set source current limit"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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); + zassert_ok(ppc_set_vbus_source_current_limit(syv682x_port, + TYPEC_RP_3A0), + "Could not set source current limit"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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); } -static void test_ppc_syv682x(void) +static void test_ppc_syv682x_write_busy(void) { - zassert_ok(ppc_init(syv682x_port), "PPC init failed"); + struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); + + /* + * Writes should fail while the BUSY bit is set, except that writes to + * CONTROL_4 should succeed on the SYV682C. 100 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(emul, 100); + 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(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(emul, 0); +} + +static void test_ppc_syv682x_dev_is_connected(void) +{ + struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); + 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(emul, SYV682X_CONTROL_2_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(emul, SYV682X_CONTROL_2_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"); +} + +static void test_ppc_syv682x_vbus_sink_enable(void) +{ + struct i2c_emul *emul = syv682x_emul_get(SYV682X_ORD); + uint8_t reg; + int ilim; + + /* + * If VBUS source is already enabled, disabling VBUS sink should + * trivially succeed. + */ + zassert_ok(ppc_vbus_source_enable(syv682x_port, true), + "VBUS enable failed"); + zassert_ok(ppc_vbus_sink_enable(syv682x_port, false), + "Sink disable failed"); + + /* + * After enabling VBUS sink, the HV power path should be enabled in sink + * mode with the configured current limit. + */ + zassert_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(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_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); + zassert_ok(ppc_vbus_sink_enable(syv682x_port, false), + "Sink disable failed"); + zassert_ok(syv682x_emul_get_reg(emul, SYV682X_CONTROL_1_REG, ®), + NULL); + zassert_true(reg & SYV682X_CONTROL_1_PWR_ENB, + "Sink disabled, but power path enabled"); +} + +static void test_ppc_syv682x_ppc_dump(void) +{ + /* + * 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"); +} + +static void test_ppc_syv682x(void) +{ + test_ppc_syv682x_init(); test_ppc_syv682x_vbus_enable(); test_ppc_syv682x_interrupt(); test_ppc_syv682x_frs(); + test_ppc_syv682x_source_current_limit(); + test_ppc_syv682x_write_busy(); + test_ppc_syv682x_dev_is_connected(); + test_ppc_syv682x_vbus_sink_enable(); + test_ppc_syv682x_ppc_dump(); } void test_suite_ppc(void) diff --git a/zephyr/test/drivers/src/ppc_sn5s330.c b/zephyr/test/drivers/src/ppc_sn5s330.c index 95556e28cf..429b9b8c26 100644 --- a/zephyr/test/drivers/src/ppc_sn5s330.c +++ b/zephyr/test/drivers/src/ppc_sn5s330.c @@ -3,10 +3,12 @@ * found in the LICENSE file. */ +#include <kernel.h> #include <device.h> #include <devicetree.h> #include <emul.h> #include <ztest.h> +#include <fff.h> #include "driver/ppc/sn5s330.h" #include "driver/ppc/sn5s330_public.h" @@ -17,12 +19,49 @@ /** This must match the index of the sn5s330 in ppc_chips[] */ #define SN5S330_PORT 0 #define EMUL emul_get_binding(DT_LABEL(DT_NODELABEL(sn5s330_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(struct i2c_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(struct i2c_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(struct i2c_emul *emul, int reg, uint8_t val, int bytes, void *data) { @@ -40,29 +79,300 @@ static void test_fail_once_func_set1(void) const struct emul *emul = EMUL; struct i2c_emul *i2c_emul = sn5s330_emul_to_i2c_emul(emul); uint32_t count = 1; - uint32_t func_set1_value; + uint8_t func_set1_value; i2c_common_emul_set_write_func(i2c_emul, fail_until_write_func, &count); zassert_ok(sn5s330_drv.init(SN5S330_PORT), NULL); zassert_equal(count, 0, NULL); - zassert_ok(sn5s330_emul_peek_reg(emul, SN5S330_FUNC_SET1, - &func_set1_value), - 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(i2c_emul, NULL, NULL); } +static void test_dead_battery_boot_force_pp2_fets_set(void) +{ + const struct emul *emul = EMUL; + struct i2c_emul *i2c_emul = sn5s330_emul_to_i2c_emul(emul); + 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(i2c_emul, intercept_write_func, + &test_write_data); + i2c_common_emul_set_read_func(i2c_emul, 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); +} + +static void test_enter_low_power_mode(void) +{ + 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); +} + +static void test_vbus_source_sink_enable(void) +{ + 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); +} + +static void test_vbus_discharge(void) +{ + 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); +} + +static void test_set_vbus_source_current_limit(void) +{ + 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); +} + +static void test_sn5s330_set_sbu(void) +#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 */ + +static void test_sn5s330_vbus_overcurrent(void) +{ + 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); +} + +static void test_sn5s330_disable_vbus_low_interrupt(void) +#ifdef CONFIG_USBC_PPC_VCONN +{ + 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); +} +#else +{ + ztest_test_skip(); +} +#endif /* CONFIG_USBC_PPC_VCONN */ + +static void test_sn5s330_set_vconn_fet(void) +{ + 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); +} + static void reset_sn5s330_state(void) { + struct i2c_emul *i2c_emul = sn5s330_emul_to_i2c_emul(EMUL); + + i2c_common_emul_set_write_func(i2c_emul, NULL, NULL); + i2c_common_emul_set_read_func(i2c_emul, NULL, NULL); sn5s330_emul_reset(EMUL); + RESET_FAKE(sn5s330_emul_interrupt_set_stub); } void test_suite_ppc_sn5s330(void) { - ztest_test_suite(ppc_sn5s330, - ztest_unit_test_setup_teardown( - test_fail_once_func_set1, reset_sn5s330_state, - reset_sn5s330_state)); + ztest_test_suite( + ppc_sn5s330, + ztest_unit_test_setup_teardown(test_sn5s330_set_vconn_fet, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown( + test_sn5s330_disable_vbus_low_interrupt, + reset_sn5s330_state, reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_sn5s330_vbus_overcurrent, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_sn5s330_set_sbu, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown( + test_set_vbus_source_current_limit, reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_vbus_discharge, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_vbus_source_sink_enable, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_enter_low_power_mode, + reset_sn5s330_state, + reset_sn5s330_state), + ztest_unit_test_setup_teardown( + test_dead_battery_boot_force_pp2_fets_set, + reset_sn5s330_state, reset_sn5s330_state), + ztest_unit_test_setup_teardown(test_fail_once_func_set1, + reset_sn5s330_state, + reset_sn5s330_state)); ztest_run_test_suite(ppc_sn5s330); } diff --git a/zephyr/test/drivers/src/ps8xxx.c b/zephyr/test/drivers/src/ps8xxx.c index 790eebf2db..a2052b43fc 100644 --- a/zephyr/test/drivers/src/ps8xxx.c +++ b/zephyr/test/drivers/src/ps8xxx.c @@ -8,8 +8,8 @@ #include "common.h" #include "emul/emul_common_i2c.h" -#include "emul/emul_tcpci.h" -#include "emul/emul_ps8xxx.h" +#include "emul/tcpc/emul_tcpci.h" +#include "emul/tcpc/emul_ps8xxx.h" #include "timer.h" #include "i2c.h" #include "stubs.h" @@ -911,7 +911,14 @@ static void test_ps8xxx_tcpci_low_power_mode(void) { const struct emul *ps8xxx_emul = emul_get_binding(PS8XXX_EMUL_LABEL); const struct emul *tcpci_emul = ps8xxx_emul_get_tcpci(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(tcpci_emul, USBC_PORT_C1); } diff --git a/zephyr/test/drivers/src/stubs.c b/zephyr/test/drivers/src/stubs.c index 68aab8ba12..85c528a5bd 100644 --- a/zephyr/test/drivers/src/stubs.c +++ b/zephyr/test/drivers/src/stubs.c @@ -11,6 +11,7 @@ #include "charger/isl923x_public.h" #include "charger/isl9241_public.h" #include "config.h" +#include "fff.h" #include "hooks.h" #include "i2c/i2c.h" #include "power.h" @@ -23,6 +24,13 @@ #include "usb_mux.h" #include "usb_pd_tcpm.h" #include "usbc_ppc.h" +#include "charge_state_v2.h" + +#include <logging/log.h> +LOG_MODULE_REGISTER(stubs); + +#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) +#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) /* All of these definitions are just to get the test to link. None of these * functions are useful or behave as they should. Please remove them once the @@ -105,6 +113,56 @@ const enum battery_type DEFAULT_BATTERY_TYPE = BATTERY_LGC011; int board_set_active_charge_port(int port) { + int is_real_port = (port >= 0 && + port < CONFIG_USB_PD_PORT_MAX_COUNT); + int i; + + if (!is_real_port && port != CHARGE_PORT_NONE) + return EC_ERROR_INVAL; + + if (port == CHARGE_PORT_NONE) { + CPRINTS("Disabling all charging port"); + + /* Disable all ports. */ + for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) { + /* + * Do not return early if one fails otherwise we can + * get into a boot loop assertion failure. + */ + if (board_vbus_sink_enable(i, 0)) + CPRINTS("Disabling p%d sink path failed.", i); + } + + return EC_SUCCESS; + } + + /* Check if the port is sourcing VBUS. */ + if (board_is_sourcing_vbus(port)) { + CPRINTS("Skip enable p%d", port); + return EC_ERROR_INVAL; + } + + + CPRINTS("New charge port: p%d", port); + + /* + * Turn off the other ports' sink path FETs, before enabling the + * requested charge port. + */ + for (i = 0; i < CONFIG_USB_PD_PORT_MAX_COUNT; i++) { + if (i == port) + continue; + + if (board_vbus_sink_enable(i, 0)) + CPRINTS("p%d: sink path disable failed.", i); + } + + /* Enable requested charge port. */ + if (board_vbus_sink_enable(port, 1)) { + CPRINTS("p%d: sink path enable failed.", port); + return EC_ERROR_UNKNOWN; + } + return EC_SUCCESS; } @@ -116,6 +174,8 @@ int board_is_vbus_too_low(int port, enum chg_ramp_vbus_state ramp_state) void board_set_charge_limit(int port, int supplier, int charge_ma, int max_ma, int charge_mv) { + charge_set_input_current_limit( + MAX(charge_ma, CONFIG_CHARGER_INPUT_CURRENT), charge_mv); } struct tcpc_config_t tcpc_config[] = { @@ -156,9 +216,16 @@ void board_set_ps8xxx_product_id(uint16_t product_id) ps8xxx_product_id = product_id; } +int board_vbus_sink_enable(int port, int enable) +{ + /* Both ports are controlled by PPC SN5S330 */ + return ppc_vbus_sink_enable(port, enable); +} + int board_is_sourcing_vbus(int port) { - return 0; + /* Both ports are controlled by PPC SN5S330 */ + return ppc_is_sourcing_vbus(port); } struct usb_mux usbc0_virtual_usb_mux = { @@ -235,9 +302,7 @@ struct ppc_config_t ppc_chips[] = { BUILD_ASSERT(ARRAY_SIZE(ppc_chips) == USBC_PORT_COUNT); unsigned int ppc_cnt = ARRAY_SIZE(ppc_chips); -void system_hibernate(uint32_t seconds, uint32_t microseconds) -{ -} +DEFINE_FAKE_VOID_FUNC(system_hibernate, uint32_t, uint32_t); uint16_t tcpc_get_alert_status(void) { @@ -265,17 +330,53 @@ enum power_state power_chipset_init(void) return POWER_G3; } -enum power_state mock_state = POWER_G3; +static enum power_state forced_state; +static bool force_state; -void set_mock_power_state(enum power_state state) +void force_power_state(bool force, enum power_state state) { - mock_state = state; - task_wake(TASK_ID_CHIPSET); + forced_state = state; + force_state = force; + + if (force) { + task_wake(TASK_ID_CHIPSET); + /* + * TODO(b/201420132) - setting power state requires to wake up + * TASK_ID_CHIPSET Sleep is required to run chipset task before + * continuing with test + */ + k_msleep(1); + } } enum power_state power_handle_state(enum power_state state) { - return mock_state; + switch (state) { + case POWER_G3S5: + case POWER_S5S3: + case POWER_S3S0: + case POWER_S0S3: + case POWER_S3S5: + case POWER_S5G3: +#ifdef CONFIG_POWER_S0IX + case POWER_S0ixS0: + case POWER_S0S0ix: +#endif + /* + * Wait for event in transition states to prevent dead loop in + * chipset task + */ + task_wait_event(-1); + break; + default: + break; + } + + if (force_state) { + state = forced_state; + } + + return state; } void chipset_reset(enum chipset_shutdown_reason reason) @@ -307,10 +408,24 @@ void tcpc_alert_event(enum gpio_signal signal) schedule_deferred_pd_interrupt(port); } +void ppc_alert(enum gpio_signal signal) +{ + switch (signal) { + case GPIO_USB_C0_PPC_INT_ODL: + ppc_chips[USBC_PORT_C0].drv->interrupt(USBC_PORT_C0); + break; + case GPIO_USB_C1_PPC_INT_ODL: + ppc_chips[USBC_PORT_C1].drv->interrupt(USBC_PORT_C1); + break; + default: + return; + } +} + /* TODO: This code should really be generic, and run based on something in * the dts. */ -static void usbc_interrupt_init(void) +static void stubs_interrupt_init(void) { /* Enable TCPC interrupts. */ gpio_enable_interrupt(GPIO_USB_C0_TCPC_INT_ODL); @@ -328,5 +443,12 @@ static void usbc_interrupt_init(void) gpio_set_level(GPIO_USB_C1_TCPC_RST_L, 0); msleep(PS8XXX_RESET_DELAY_MS); gpio_set_level(GPIO_USB_C1_TCPC_RST_L, 1); + + /* Enable PPC interrupts. */ + gpio_enable_interrupt(GPIO_USB_C0_PPC_INT_ODL); + gpio_enable_interrupt(GPIO_USB_C1_PPC_INT_ODL); + + /* Enable SwitchCap interrupt */ + gpio_enable_interrupt(GPIO_SWITCHCAP_PG_INT_L); } -DECLARE_HOOK(HOOK_INIT, usbc_interrupt_init, HOOK_PRIO_INIT_I2C + 1); +DECLARE_HOOK(HOOK_INIT, stubs_interrupt_init, HOOK_PRIO_INIT_I2C + 1); diff --git a/zephyr/test/drivers/src/tcpci.c b/zephyr/test/drivers/src/tcpci.c index d67680bacc..cdc13861ab 100644 --- a/zephyr/test/drivers/src/tcpci.c +++ b/zephyr/test/drivers/src/tcpci.c @@ -11,7 +11,7 @@ #include "common.h" #include "ec_tasks.h" #include "emul/emul_common_i2c.h" -#include "emul/emul_tcpci.h" +#include "emul/tcpc/emul_tcpci.h" #include "hooks.h" #include "i2c.h" #include "stubs.h" @@ -295,8 +295,9 @@ static void test_generic_tcpci_mux_init(void) zassert_equal(EC_ERROR_TIMEOUT, tcpci_tcpm_mux_init(tcpci_usb_mux), NULL); - /* Set correct power status for rest of the test */ - tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS, 0); + /* 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(i2c_emul, TCPC_REG_ALERT_MASK); diff --git a/zephyr/test/drivers/src/tcpci_test_common.c b/zephyr/test/drivers/src/tcpci_test_common.c index 57cc35b89c..a2925bf3be 100644 --- a/zephyr/test/drivers/src/tcpci_test_common.c +++ b/zephyr/test/drivers/src/tcpci_test_common.c @@ -8,7 +8,7 @@ #include "common.h" #include "emul/emul_common_i2c.h" -#include "emul/emul_tcpci.h" +#include "emul/tcpc/emul_tcpci.h" #include "tcpci_test_common.h" #include "tcpm/tcpci.h" @@ -57,7 +57,8 @@ void test_tcpci_init(const struct emul *emul, enum usbc_port port) 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, 0); + 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); @@ -69,7 +70,8 @@ void test_tcpci_init(const struct emul *emul, enum usbc_port port) /* 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_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); @@ -92,7 +94,8 @@ void test_tcpci_init(const struct emul *emul, enum usbc_port port) 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, 0); + 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); diff --git a/zephyr/test/drivers/src/usb_mux.c b/zephyr/test/drivers/src/usb_mux.c index cf6190eec9..517bb59107 100644 --- a/zephyr/test/drivers/src/usb_mux.c +++ b/zephyr/test/drivers/src/usb_mux.c @@ -14,6 +14,7 @@ #include "common.h" #include "ec_commands.h" #include "ec_tasks.h" +#include "fff.h" #include "hooks.h" #include "host_command.h" #include "i2c.h" @@ -27,86 +28,151 @@ /** Copy of original usb_muxes[USB_PORT_C1] */ struct usb_mux 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[3]; +const struct usb_mux *org_mux[NUM_OF_PROXY]; /** Proxy function which check calls from usb_mux framework to driver */ -static int proxy_init(const struct usb_mux *me) +FAKE_VALUE_FUNC1(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; - ztest_check_expected_value(i); + zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux"); if (org_mux[i] != NULL && org_mux[i]->driver->init != NULL) { - org_mux[i]->driver->init(org_mux[i]); + ec = org_mux[i]->driver->init(org_mux[i]); + } + + if (task_get_current() == TASK_ID_TEST_RUNNER) { + RETURN_FAKE_RESULT(proxy_init); } - return ztest_get_return_value(); + /* 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 */ -static int proxy_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) +FAKE_VALUE_FUNC3(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; - ztest_check_expected_value(i); - ztest_check_expected_value(mux_state); + zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux"); if (org_mux[i] != NULL && org_mux[i]->driver->set != NULL) { - org_mux[i]->driver->set(org_mux[i], mux_state, ack_required); + ec = org_mux[i]->driver->set(org_mux[i], mux_state, + ack_required); } - return ztest_get_return_value(); + 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 */ -static int proxy_get(const struct usb_mux *me, mux_state_t *mux_state) +FAKE_VALUE_FUNC2(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; - ztest_check_expected_value(i); + zassert_true(i < NUM_OF_PROXY, "Proxy called for non proxy usb_mux"); if (org_mux[i] != NULL && org_mux[i]->driver->get != NULL) { - org_mux[i]->driver->get(org_mux[i], mux_state); + 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); } - *mux_state = ztest_get_return_value(); + /* Discard this call if made from different thread */ + proxy_get_fake.call_count--; - return ztest_get_return_value(); + return ec; } /** Proxy function which check calls from usb_mux framework to driver */ -static int proxy_enter_low_power_mode(const struct usb_mux *me) +FAKE_VALUE_FUNC1(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; - ztest_check_expected_value(i); + 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) { - org_mux[i]->driver->enter_low_power_mode(org_mux[i]); + ec = org_mux[i]->driver->enter_low_power_mode(org_mux[i]); } - return ztest_get_return_value(); + 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 */ -static int proxy_chipset_reset(const struct usb_mux *me) +FAKE_VALUE_FUNC1(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; - ztest_check_expected_value(i); + 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) { - org_mux[i]->driver->chipset_reset(org_mux[i]); + ec = org_mux[i]->driver->chipset_reset(org_mux[i]); } - return ztest_get_return_value(); + 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 */ @@ -116,16 +182,22 @@ static bool proxy_fw_update_cap(void) } /** Proxy function which check calls from usb_mux framework to driver */ -static void proxy_hpd_update(const struct usb_mux *me, mux_state_t mux_state) +FAKE_VOID_FUNC3(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; - ztest_check_expected_value(i); - ztest_check_expected_value(mux_state); + 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); + org_mux[i]->hpd_update(org_mux[i], mux_state, ack_required); + } + + if (task_get_current() != TASK_ID_TEST_RUNNER) { + /* Discard this call if made from different thread */ + proxy_hpd_update_fake.call_count--; } } @@ -139,6 +211,71 @@ const struct usb_mux_driver proxy_usb_mux = { .is_retimer_fw_update_capable = &proxy_fw_update_cap, }; +/** Mock function used in init test */ +FAKE_VALUE_FUNC1(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_FUNC2(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_chain_2 = { .usb_port = USBC_PORT_C1, @@ -180,7 +317,7 @@ static void setup_usb_mux_proxy_chain(void) * each proxy */ t = &usb_mux_c1; - for (i = 0; i < 3; i++) { + for (i = 0; i < NUM_OF_PROXY; i++) { org_mux[i] = t; if (t != NULL) { t = t->next_mux; @@ -194,146 +331,96 @@ static void setup_usb_mux_proxy_chain(void) } } -static void suspend_usbc_task(bool suspend) -{ - static const task_id_t cros_tids[] = { - COND_CODE_1(HAS_TASK_PD_C0, (TASK_ID_PD_C0,), ()) - COND_CODE_1(HAS_TASK_PD_C1, (TASK_ID_PD_C1,), ()) - COND_CODE_1(HAS_TASK_PD_C2, (TASK_ID_PD_C2,), ()) - COND_CODE_1(HAS_TASK_PD_C3, (TASK_ID_PD_C3,), ()) - }; - - for (int i = 0; i < ARRAY_SIZE(cros_tids); ++i) - /* - * TODO(b/201420132): pd_set_suspend uses sleeps which we should - * minimize - */ - pd_set_suspend(TASK_ID_TO_PD_PORT(cros_tids[i]), suspend); -} - /** Restore original usb_mux chain without proxy */ -static void resotre_usb_mux_chain(void) +static void restore_usb_mux_chain(void) { - suspend_usbc_task(/*suspend=*/ false); memcpy(&usb_muxes[USBC_PORT_C1], &usb_mux_c1, sizeof(struct usb_mux)); } /** - * Setup expect values for proxy from first to last selected. - * Set value returned by proxy to ec. - */ -static void setup_ztest_proxy_init(int first, int last, int ec) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_init, i, i); - ztest_returns_value(proxy_init, ec); - } -} - -/** - * Setup expect values for proxy from first to last selected. - * Set value returned by proxy to ec. + * 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. */ -static void setup_ztest_proxy_set(int first, int last, int ec, mux_state_t exp) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_set, i, i); - ztest_expect_value(proxy_set, mux_state, exp); - ztest_returns_value(proxy_set, ec); - } -} +#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], \ + proxy##_fake.arg0_history[0], \ + NULL); \ + } \ + if (num >= 2) { \ + zassert_equal(&proxy_chain_1, \ + proxy##_fake.arg0_history[1], \ + NULL); \ + } \ + if (num >= 3) { \ + zassert_equal(&proxy_chain_2, \ + proxy##_fake.arg0_history[2], \ + NULL); \ + } \ + } while (0) /** - * Setup expect values for proxy from first to last selected. Set value - * returned by proxy to ec and value returned through mux_state to exp. + * 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. */ -static void setup_ztest_proxy_get(int first, int last, int ec, mux_state_t exp) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_get, i, i); - ztest_returns_value(proxy_get, exp); - ztest_returns_value(proxy_get, ec); - } -} - -/** - * Setup expect values for proxy from first to last selected. - * Set value returned by proxy to ec. - */ -static void setup_ztest_proxy_enter_lpm(int first, int last, int ec) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_enter_low_power_mode, i, i); - ztest_returns_value(proxy_enter_low_power_mode, ec); - } -} - -/** - * Setup expect values for proxy from first to last selected. - * Set value returned by proxy to ec. - */ -static void setup_ztest_proxy_chipset_reset(int first, int last, int ec) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_chipset_reset, i, i); - ztest_returns_value(proxy_chipset_reset, ec); - } -} - -/** Setup expect values for proxy from first to last selected */ -static void setup_ztest_proxy_hpd_update(int first, int last, mux_state_t exp) -{ - for (int i = first; i <= last; i++) { - ztest_expect_value(proxy_hpd_update, i, i); - ztest_expect_value(proxy_hpd_update, mux_state, exp); - } -} - -/** Mock function used in set test */ -static int mock_board_set(const struct usb_mux *me, mux_state_t mux_state) -{ - int i = me->i2c_addr_flags; - - ztest_check_expected_value(i); - - return EC_SUCCESS; -} +#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 */ static void test_usb_mux_init(void) { + int fail_on_2nd_ret[] = {EC_SUCCESS, EC_ERROR_NOT_POWERED}; + /* Set AP to normal state to init BB retimer */ - set_mock_power_state(POWER_S0); - /* - * TODO(b/201420132) - setting power state requires to wake up - * TASK_ID_CHIPSET Sleep is required to run chipset task before - * continuing with test - */ - k_msleep(1); + power_set_state(POWER_S0); /* Test successful initialisation */ - setup_ztest_proxy_init(0, 2, EC_SUCCESS); 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 */ - setup_ztest_proxy_init(0, 0, EC_SUCCESS); - setup_ztest_proxy_init(1, 1, 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); /* Test board init callback */ - proxy_chain_1.board_init = proxy_init; - setup_ztest_proxy_init(0, 0, EC_SUCCESS); - /* - * board_init of second mux mock is set to init mock function, so it - * should be called two times. - */ - setup_ztest_proxy_init(1, 1, EC_SUCCESS); - setup_ztest_proxy_init(1, 2, EC_SUCCESS); - + proxy_chain_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, mock_board_init_fake.arg0_history[0], + NULL); proxy_chain_1.board_init = NULL; } @@ -341,40 +428,57 @@ static void test_usb_mux_init(void) /** Test usb_mux setting mux mode */ static void test_usb_mux_set(void) { + int fail_on_2nd_ret[] = {EC_SUCCESS, EC_ERROR_UNKNOWN}; mux_state_t exp_mode; - /* usb mux 1 shouldn't be set with polarity mode */ + /* Set flag for usb mux 1 to disable polarity setting */ proxy_chain_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; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); 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; - setup_ztest_proxy_set(0, 0, EC_SUCCESS, - exp_mode | USB_PD_MUX_POLARITY_INVERTED); - setup_ztest_proxy_set(1, 1, EC_SUCCESS, exp_mode); - setup_ztest_proxy_set(2, 2, EC_SUCCESS, - exp_mode | USB_PD_MUX_POLARITY_INVERTED); 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 */ - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); + reset_proxy_fakes(); proxy_chain_1.board_set = &mock_board_set; - ztest_expect_value(mock_board_set, i, 1); 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, 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 */ - setup_ztest_proxy_set(0, 0, EC_SUCCESS, exp_mode); - setup_ztest_proxy_set(1, 1, EC_ERROR_UNKNOWN, exp_mode); + 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_chain_1.board_set = NULL; } @@ -385,115 +489,125 @@ static void test_usb_mux_reset_in_g3(void) mux_state_t exp_mode = USB_PD_MUX_USB_ENABLED; /* Test that init is called */ - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); + 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 */ usb_muxes[USBC_PORT_C1].flags = 0; hook_notify(HOOK_CHIPSET_HARD_OFF); /* Test that init is not called */ - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); + 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 */ static void test_usb_mux_get(void) { + 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; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_get(0, 2, EC_SUCCESS, exp_mode); + 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 one inverted polarisation */ + /* Test getting mux mode with inverted polarisation in one mux */ + reset_proxy_fakes(); exp_mode = USB_PD_MUX_TBT_COMPAT_ENABLED; - setup_ztest_proxy_get(0, 0, EC_SUCCESS, exp_mode); - setup_ztest_proxy_get(1, 1, EC_SUCCESS, - exp_mode | USB_PD_MUX_POLARITY_INVERTED); - setup_ztest_proxy_get(2, 2, EC_SUCCESS, exp_mode); + 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 */ - setup_ztest_proxy_get(0, 0, EC_SUCCESS, USB_PD_MUX_TBT_COMPAT_ENABLED); - setup_ztest_proxy_get(1, 1, EC_ERROR_UNKNOWN, - USB_PD_MUX_TBT_COMPAT_ENABLED); + 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 */ static void test_usb_mux_low_power_mode(void) { + int fail_on_2nd_ret[] = {EC_SUCCESS, EC_ERROR_NOT_POWERED}; mux_state_t exp_mode, mode; - /* - * Virtual mux return ack_required in some cases, but this requires to - * run usb_mux_set in TASK_PD_C1 context. Remove virtual mux from chain - * for this test. - * - * TODO: Find way to setup PD stack in such state that notifing PD task - * results in required usb_mux_set call. - */ - org_mux[1] = NULL; - /* Test enter to low power mode */ exp_mode = USB_PD_MUX_NONE; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); - setup_ztest_proxy_enter_lpm(0, 2, EC_SUCCESS); 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; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); 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 */ - setup_ztest_proxy_init(0, 0, EC_SUCCESS); - setup_ztest_proxy_init(1, 1, 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; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); 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; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); - setup_ztest_proxy_enter_lpm(0, 2, EC_SUCCESS); 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; - setup_ztest_proxy_init(0, 0, EC_SUCCESS); - setup_ztest_proxy_init(1, 1, EC_ERROR_NOT_POWERED); 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 */ @@ -501,32 +615,34 @@ static void test_usb_mux_flip(void) { mux_state_t exp_mode; - /* usb mux mock 1 shouldn't be set with polarity mode */ + /* Set flag for usb mux 1 to disable polarity setting */ proxy_chain_1.flags = USB_MUX_FLAG_SET_WITHOUT_FLIP; - /* Makes sure that usb muxes of port 1 are not init */ - usb_muxes[USBC_PORT_C1].flags = USB_MUX_FLAG_RESETS_IN_G3; - hook_notify(HOOK_CHIPSET_HARD_OFF); - /* Test flip port without polarity inverted */ exp_mode = USB_PD_MUX_USB_ENABLED; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_get(0, 2, EC_SUCCESS, exp_mode); - exp_mode |= USB_PD_MUX_POLARITY_INVERTED; - setup_ztest_proxy_set(0, 0, EC_SUCCESS, exp_mode); - setup_ztest_proxy_set(1, 1, EC_SUCCESS, - exp_mode & ~USB_PD_MUX_POLARITY_INVERTED); - setup_ztest_proxy_set(2, 2, EC_SUCCESS, exp_mode); + 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 */ - setup_ztest_proxy_get(0, 0, EC_SUCCESS, exp_mode); - setup_ztest_proxy_get(1, 1, EC_SUCCESS, - exp_mode & ~USB_PD_MUX_POLARITY_INVERTED); - setup_ztest_proxy_get(2, 2, EC_SUCCESS, exp_mode); + 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; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); 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); } void test_usb_mux_hpd_update(void) @@ -538,40 +654,50 @@ void test_usb_mux_hpd_update(void) /* Test no hpd level and no irq */ exp_mode = virt_mode; - setup_ztest_proxy_init(0, 2, EC_SUCCESS); - setup_ztest_proxy_hpd_update(0, 2, exp_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; - setup_ztest_proxy_hpd_update(0, 2, exp_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, 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; - setup_ztest_proxy_hpd_update(0, 2, exp_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, 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; - setup_ztest_proxy_hpd_update(0, 2, exp_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, 0); + CHECK_PROXY_FAKE_CALL_CNT_MUX_STATE(proxy_hpd_update, NUM_OF_PROXY, + exp_mode); } void test_usb_mux_fw_update_port_info(void) @@ -585,9 +711,9 @@ void test_usb_mux_fw_update_port_info(void) void test_usb_mux_chipset_reset(void) { - setup_ztest_proxy_chipset_reset(0, 2, EC_SUCCESS); /* 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 */ @@ -596,13 +722,9 @@ static void test_usb_mux_hc_mux_info(void) 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); + BUILD_HOST_COMMAND(EC_CMD_USB_PD_MUX_INFO, 0, response, params); mux_state_t exp_mode; - /* Set up host command parameters */ - args.params = ¶ms; - args.params_size = sizeof(params); - /* Test invalid port parameter */ params.port = 5; zassert_equal(EC_RES_INVALID_PARAM, host_command_process(&args), NULL); @@ -611,27 +733,32 @@ static void test_usb_mux_hc_mux_info(void) params.port = USBC_PORT_C1; /* Test error on getting mux mode */ - setup_ztest_proxy_get(0, 0, EC_ERROR_UNKNOWN, - USB_PD_MUX_TBT_COMPAT_ENABLED); + 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; - setup_ztest_proxy_get(0, 2, EC_SUCCESS, exp_mode); + 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; - setup_ztest_proxy_get(0, 2, EC_SUCCESS, exp_mode); - setup_ztest_proxy_hpd_update(0, 2, USB_PD_MUX_HPD_LVL); + 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 */ @@ -667,96 +794,102 @@ static void test_usb_mux_typec_command(void) * Test success on correct port number. Command should print mux state * on console, but it is not possible to check that in unit test. */ - setup_ztest_proxy_get(0, 2, EC_SUCCESS, USB_PD_MUX_TBT_COMPAT_ENABLED); + set_proxy_get_mux_state_seq(USB_PD_MUX_TBT_COMPAT_ENABLED); zassert_equal(EC_SUCCESS, shell_execute_cmd(shell_backend_uart_get_ptr(), "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; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); - /* Mux will enter low power mode */ - setup_ztest_proxy_enter_lpm(0, 2, EC_SUCCESS); zassert_equal(EC_SUCCESS, shell_execute_cmd(shell_backend_uart_get_ptr(), "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); /* Test setting USB mode */ + reset_proxy_fakes(); exp_mode = USB_PD_MUX_USB_ENABLED; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); - /* Mux will exit low power mode */ - setup_ztest_proxy_init(0, 2, EC_SUCCESS); zassert_equal(EC_SUCCESS, shell_execute_cmd(shell_backend_uart_get_ptr(), "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; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); zassert_equal(EC_SUCCESS, shell_execute_cmd(shell_backend_uart_get_ptr(), "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; - setup_ztest_proxy_set(0, 2, EC_SUCCESS, exp_mode); zassert_equal(EC_SUCCESS, shell_execute_cmd(shell_backend_uart_get_ptr(), "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 setup_uninit_mux(void) { - suspend_usbc_task(/*suspend=*/ true); setup_usb_mux_proxy_chain(); + set_test_runner_tid(); /* Makes sure that usb muxes of port 1 are not init */ usb_muxes[USBC_PORT_C1].flags = USB_MUX_FLAG_RESETS_IN_G3; hook_notify(HOOK_CHIPSET_HARD_OFF); + reset_proxy_fakes(); } /** Setup proxy chain and init usb muxes */ void setup_init_mux(void) { - suspend_usbc_task(/*suspend=*/ true); setup_usb_mux_proxy_chain(); + set_test_runner_tid(); /* Makes sure that usb muxes of port 1 are init */ - setup_ztest_proxy_init(0, 2, EC_SUCCESS); usb_mux_init(USBC_PORT_C1); + reset_proxy_fakes(); } void test_suite_usb_mux(void) { ztest_test_suite(usb_mux, ztest_unit_test_setup_teardown(test_usb_mux_init, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown(test_usb_mux_set, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_reset_in_g3, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown(test_usb_mux_get, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_low_power_mode, - setup_init_mux, resotre_usb_mux_chain), + setup_init_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown(test_usb_mux_flip, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown(test_usb_mux_hpd_update, - setup_uninit_mux, resotre_usb_mux_chain), + setup_uninit_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_fw_update_port_info, - setup_init_mux, resotre_usb_mux_chain), + setup_init_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_chipset_reset, - setup_init_mux, resotre_usb_mux_chain), + setup_init_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_hc_mux_info, - setup_init_mux, resotre_usb_mux_chain), + setup_init_mux, restore_usb_mux_chain), ztest_unit_test_setup_teardown( test_usb_mux_typec_command, - setup_init_mux, resotre_usb_mux_chain)); + setup_init_mux, restore_usb_mux_chain)); ztest_run_test_suite(usb_mux); } |