From c11b139b0bdee8e9fc8dec8cd65ccb3bbb46c7db Mon Sep 17 00:00:00 2001 From: Tomasz Michalec Date: Thu, 25 Nov 2021 14:50:44 +0100 Subject: zephyr: drivers: Add unit test for smart discharge Add unit test of setting smart discharge zones using host command. Test if generic board_system_is_idle() recognizes smart discharge zones correctly. BUG=b:206903370 BRANCH=none TEST=zmake configure --test zephyr/test/drivers Signed-off-by: Tomasz Michalec Change-Id: Ia8e8f9a33183fc0bf6ed4f6705c96e86e4f1ef5d Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3302214 Tested-by: Tomasz Michalec Commit-Queue: Tomasz Michalec Reviewed-by: Fabio Baltieri --- zephyr/test/drivers/src/power_common.c | 174 ++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/zephyr/test/drivers/src/power_common.c b/zephyr/test/drivers/src/power_common.c index fe056397d3..8c043d7a43 100644 --- a/zephyr/test/drivers/src/power_common.c +++ b/zephyr/test/drivers/src/power_common.c @@ -12,6 +12,14 @@ #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)) + /* Description of all power states with chipset state masks */ static struct { /* Power state */ @@ -274,6 +282,168 @@ static void test_power_reboot_ap_at_g3(void) 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); + 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 */ + args.params = ¶ms; + args.params_size = sizeof(params); + + 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); + 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 */ + args.params = ¶ms; + args.params_size = sizeof(params); + 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); +} + void test_suite_power_common(void) { ztest_test_suite(power_common, @@ -281,6 +451,8 @@ void test_suite_power_common(void) 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_reboot_ap_at_g3), + ztest_unit_test(test_power_hc_smart_discharge), + ztest_unit_test(test_power_board_system_is_idle)); ztest_run_test_suite(power_common); } -- cgit v1.2.1