diff options
Diffstat (limited to 'zephyr/test/drivers/default/src/virtual_battery.c')
-rw-r--r-- | zephyr/test/drivers/default/src/virtual_battery.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/zephyr/test/drivers/default/src/virtual_battery.c b/zephyr/test/drivers/default/src/virtual_battery.c new file mode 100644 index 0000000000..0e69c641a5 --- /dev/null +++ b/zephyr/test/drivers/default/src/virtual_battery.c @@ -0,0 +1,259 @@ +/* Copyright 2022 The ChromiumOS Authors + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <zephyr/kernel.h> +#include <zephyr/ztest.h> + +#include "battery.h" +#include "battery_smart.h" +#include "ec_commands.h" +#include "emul/emul_smart_battery.h" +#include "host_command.h" +#include "test/drivers/test_state.h" + +/* The param buffer has at most 2 msg's (write + read) and 1 byte write len. */ +static uint8_t param_buf[sizeof(struct ec_params_i2c_passthru) + + sizeof(struct ec_params_i2c_passthru_msg) * 2 + 1]; + +/* The response buffer has at most 32 bytes returned result. */ +static uint8_t response_buf[sizeof(struct ec_response_i2c_passthru) + 32]; + +static void i2c_passthru_xfer(uint8_t port, uint8_t addr, uint8_t *write_buf, + int write_len, uint8_t **read_buf, int read_len) +{ + struct ec_params_i2c_passthru *params = + (struct ec_params_i2c_passthru *)¶m_buf; + struct ec_response_i2c_passthru *response = + (struct ec_response_i2c_passthru *)&response_buf; + struct ec_params_i2c_passthru_msg *msg = params->msg; + struct host_cmd_handler_args args = + BUILD_HOST_COMMAND_SIMPLE(EC_CMD_I2C_PASSTHRU, 0); + uint8_t *pdata; + int size; + + params->port = port; + params->num_msgs = (read_len != 0) + (write_len != 0); + + size = sizeof(*params) + params->num_msgs * sizeof(*msg); + pdata = (uint8_t *)params + size; + + if (write_len) { + msg->addr_flags = addr; + msg->len = write_len; + memcpy(pdata, write_buf, write_len); + msg++; + } + + if (read_len) { + msg->addr_flags = addr | EC_I2C_FLAG_READ; + msg->len = read_len; + } + + args.params = params; + args.params_size = size + write_len; + args.response = response; + args.response_max = sizeof(*response) + read_len; + + /* Execute the I2C passthru host command */ + zassert_ok(host_command_process(&args), NULL); + zassert_ok(args.result, NULL); + zassert_ok(response->i2c_status, NULL); + zassert_equal(args.response_size, sizeof(*response) + read_len, NULL); + + /* Return the data portion */ + if (read_len) + *read_buf = response->data; +} + +static inline void virtual_battery_xfer(uint8_t *write_buf, int write_len, + uint8_t **read_buf, int read_len) +{ + i2c_passthru_xfer(I2C_PORT_VIRTUAL_BATTERY, VIRTUAL_BATTERY_ADDR_FLAGS, + write_buf, write_len, read_buf, read_len); +} + +static uint16_t virtual_battery_read16(uint8_t command) +{ + uint8_t write_buf[1] = { command }; + uint8_t *read_buf; + + virtual_battery_xfer(write_buf, 1, &read_buf, 2); + + /* Little endian */ + return ((int)read_buf[1] << 8) | read_buf[0]; +} + +static void virtual_battery_write16(uint8_t command, uint16_t data) +{ + uint8_t write_buf[3] = { command }; + + *((uint16_t *)&write_buf[1]) = data; + + virtual_battery_xfer(write_buf, 3, NULL, 0); +} + +static int virtual_battery_read_str(uint8_t command, char **read_buf, + int read_len) +{ + uint8_t write_buf[1] = { command }; + int len; + + virtual_battery_xfer(write_buf, 1, (uint8_t **)read_buf, read_len); + + /* Battery v2 embeds the strlen in the first byte so shift 1 byte. */ + len = **read_buf; + (*read_buf)++; + + return len; +} + +static void virtual_battery_read_data(uint8_t command, char **read_buf, + int read_len) +{ + uint8_t write_buf[1] = { command }; + + virtual_battery_xfer(write_buf, 1, (uint8_t **)read_buf, read_len); +} + +#define BATTERY_NODE DT_NODELABEL(battery) + +ZTEST_USER(virtual_battery, test_read_regs) +{ + const struct emul *emul = EMUL_DT_GET(BATTERY_NODE); + struct sbat_emul_bat_data *bat = sbat_emul_get_bat_data(emul); + int16_t int16; + uint16_t word; + int expected; + char *str; + int len; + + /* + * Iterate all the registers, which issues the I2C passthru host + * command to query the emulated smart battery. Most of the values + * are the same as the emulated battery, but with some exceptions. + */ + word = virtual_battery_read16(SB_BATTERY_MODE); + zassert_equal(bat->mode, word, "%d != %d", bat->mode, word); + + word = virtual_battery_read16(SB_SERIAL_NUMBER); + zassert_equal(bat->sn, word, "%d != %d", bat->sn, word); + + word = virtual_battery_read16(SB_VOLTAGE); + zassert_equal(bat->volt, word, "%d != %d", bat->volt, word); + + /* The expected value is calculated */ + expected = 100 * bat->cap / bat->full_cap; + word = virtual_battery_read16(SB_RELATIVE_STATE_OF_CHARGE); + + zassert_equal(expected, word, "%d != %d", expected, word); + + word = virtual_battery_read16(SB_TEMPERATURE); + zassert_equal(bat->temp, word, "%d != %d", bat->temp, word); + + int16 = virtual_battery_read16(SB_CURRENT); + zassert_equal(bat->cur, int16, "%d != %d", bat->cur, int16); + + int16 = virtual_battery_read16(SB_AVERAGE_CURRENT); + zassert_equal(bat->avg_cur, int16, "%d != %d", bat->avg_cur, int16); + + /* The virtual battery modifies the return value to make kernel happy */ + expected = BATTERY_LEVEL_SHUTDOWN; + word = virtual_battery_read16(SB_MAX_ERROR); + zassert_equal(expected, word, "%d != %d", expected, word); + + word = virtual_battery_read16(SB_FULL_CHARGE_CAPACITY); + zassert_equal(bat->full_cap, word, "%d != %d", bat->full_cap, word); + + word = virtual_battery_read16(SB_CYCLE_COUNT); + zassert_equal(bat->cycle_count, word, "%d != %d", bat->cycle_count, + word); + + word = virtual_battery_read16(SB_DESIGN_CAPACITY); + zassert_equal(bat->design_cap, word, "%d != %d", bat->design_cap, word); + + word = virtual_battery_read16(SB_REMAINING_CAPACITY); + zassert_equal(bat->cap, word, "%d != %d", bat->cap, word); + + len = virtual_battery_read_str(SB_MANUFACTURER_NAME, &str, + SB_MAX_STR_SIZE); + zassert_equal(bat->mf_name_len, len, "%d != %d", bat->mf_name_len, len); + zassert_mem_equal(str, bat->mf_name, bat->mf_name_len, "%s != %s", str, + bat->mf_name); + + len = virtual_battery_read_str(SB_DEVICE_NAME, &str, SB_MAX_STR_SIZE); + zassert_equal(bat->dev_name_len, len, "%d != %d", bat->dev_name_len, + len); + zassert_mem_equal(str, bat->dev_name, bat->dev_name_len, "%s != %s", + str, bat->dev_name); + + len = virtual_battery_read_str(SB_DEVICE_CHEMISTRY, &str, + SB_MAX_STR_SIZE); + zassert_equal(bat->dev_chem_len, len, "%d != %d", bat->dev_chem_len, + len); + zassert_mem_equal(str, bat->dev_chem, bat->dev_chem_len, "%s != %s", + str, bat->dev_chem); + + /* Use the API to query the expected value */ + battery_time_to_full(&expected); + word = virtual_battery_read16(SB_AVERAGE_TIME_TO_FULL); + zassert_equal(expected, word, "%d != %d", expected, word); + + battery_time_to_empty(&expected); + word = virtual_battery_read16(SB_AVERAGE_TIME_TO_EMPTY); + zassert_equal(expected, word, "%d != %d", expected, word); + + battery_run_time_to_empty(&expected); + word = virtual_battery_read16(SB_RUN_TIME_TO_EMPTY); + zassert_equal(expected, word, "%d != %d", expected, word); + + word = virtual_battery_read16(SB_CHARGING_CURRENT); + zassert_equal(bat->desired_charg_cur, word, "%d != %d", + bat->desired_charg_cur, word); + + word = virtual_battery_read16(SB_CHARGING_VOLTAGE); + zassert_equal(bat->desired_charg_volt, word, "%d != %d", + bat->desired_charg_volt, word); + + word = virtual_battery_read16(SB_MANUFACTURE_DATE); + zassert_equal(bat->mf_date, word, "%d != %d", bat->mf_date, word); + + /* Hard-coded return value: v1.1 without PEC */ + expected = 0x0011; + word = virtual_battery_read16(SB_SPECIFICATION_INFO); + zassert_equal(expected, word, "%d != %d", expected, word); + + zassume_ok(battery_status(&expected)); + word = virtual_battery_read16(SB_BATTERY_STATUS); + zassert_equal(expected, word, "%d != %d", expected, word); + + zassume_ok(battery_design_voltage(&expected)); + word = virtual_battery_read16(SB_DESIGN_VOLTAGE); + zassert_equal(expected, word, "%d != %d", expected, word); + + virtual_battery_read_data(SB_MANUFACTURER_DATA, &str, bat->mf_data_len); + zassert_mem_equal(str, bat->mf_data, bat->mf_data_len, "%s != %s", str, + bat->mf_data); + + /* At present, this command is used nowhere in our codebase. */ + virtual_battery_read_data(SB_MANUFACTURE_INFO, &str, bat->mf_info_len); + zassert_mem_equal(str, bat->mf_info, bat->mf_info_len, "%s != %s", str, + bat->mf_info); +} + +ZTEST_USER(virtual_battery, test_write_mfgacc) +{ + struct sbat_emul_bat_data *bat; + const struct emul *emul = EMUL_DT_GET(BATTERY_NODE); + uint16_t cmd = PARAM_OPERATION_STATUS; + + bat = sbat_emul_get_bat_data(emul); + + /* Write the command to the SB_MANUFACTURER_ACCESS and check */ + virtual_battery_write16(SB_MANUFACTURER_ACCESS, cmd); + zassert_equal(bat->mf_access, cmd, "%d != %d", bat->mf_access, cmd); +} + +ZTEST_SUITE(virtual_battery, drivers_predicate_post_main, NULL, NULL, NULL, + NULL); |