diff options
author | Jack Rosenthal <jrosenth@chromium.org> | 2021-11-04 12:11:58 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-11-05 04:22:34 +0000 |
commit | 252457d4b21f46889eebad61d4c0a65331919cec (patch) | |
tree | 01856c4d31d710b20e85a74c8d7b5836e35c3b98 /zephyr/emul | |
parent | 08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff) | |
download | chrome-ec-stabilize-14469.58.B-ish.tar.gz |
ish: Trim down the release branchstabilize-wristpin-14469.59.B-ishstabilize-voshyr-14637.B-ishstabilize-quickfix-14695.187.B-ishstabilize-quickfix-14695.124.B-ishstabilize-quickfix-14526.91.B-ishstabilize-14695.85.B-ishstabilize-14695.107.B-ishstabilize-14682.B-ishstabilize-14633.B-ishstabilize-14616.B-ishstabilize-14589.B-ishstabilize-14588.98.B-ishstabilize-14588.14.B-ishstabilize-14588.123.B-ishstabilize-14536.B-ishstabilize-14532.B-ishstabilize-14528.B-ishstabilize-14526.89.B-ishstabilize-14526.84.B-ishstabilize-14526.73.B-ishstabilize-14526.67.B-ishstabilize-14526.57.B-ishstabilize-14498.B-ishstabilize-14496.B-ishstabilize-14477.B-ishstabilize-14469.9.B-ishstabilize-14469.8.B-ishstabilize-14469.58.B-ishstabilize-14469.41.B-ishstabilize-14442.B-ishstabilize-14438.B-ishstabilize-14411.B-ishstabilize-14396.B-ishstabilize-14395.B-ishstabilize-14388.62.B-ishstabilize-14388.61.B-ishstabilize-14388.52.B-ishstabilize-14385.B-ishstabilize-14345.B-ishstabilize-14336.B-ishstabilize-14333.B-ishrelease-R99-14469.B-ishrelease-R98-14388.B-ishrelease-R102-14695.B-ishrelease-R101-14588.B-ishrelease-R100-14526.B-ishfirmware-cherry-14454.B-ishfirmware-brya-14505.B-ishfirmware-brya-14505.71.B-ishfactory-kukui-14374.B-ishfactory-guybrush-14600.B-ishfactory-cherry-14455.B-ishfactory-brya-14517.B-ish
In the interest of making long-term branch maintenance incur as little
technical debt on us as possible, we should not maintain any files on
the branch we are not actually using.
This has the added effect of making it extremely clear when merging CLs
from the main branch when changes have the possibility to affect us.
The follow-on CL adds a convenience script to actually pull updates from
the main branch and generate a CL for the update.
BUG=b:204206272
BRANCH=ish
TEST=make BOARD=arcada_ish && make BOARD=drallion_ish
Signed-off-by: Jack Rosenthal <jrosenth@chromium.org>
Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038
Reviewed-by: Jett Rink <jettrink@chromium.org>
Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'zephyr/emul')
-rw-r--r-- | zephyr/emul/CMakeLists.txt | 17 | ||||
-rw-r--r-- | zephyr/emul/Kconfig | 72 | ||||
-rw-r--r-- | zephyr/emul/Kconfig.i2c_mock | 22 | ||||
-rw-r--r-- | zephyr/emul/Kconfig.lis2dw12 | 23 | ||||
-rw-r--r-- | zephyr/emul/Kconfig.ln9310 | 22 | ||||
-rw-r--r-- | zephyr/emul/emul_bb_retimer.c | 365 | ||||
-rw-r--r-- | zephyr/emul/emul_bma255.c | 1042 | ||||
-rw-r--r-- | zephyr/emul/emul_bmi.c | 1116 | ||||
-rw-r--r-- | zephyr/emul/emul_bmi160.c | 770 | ||||
-rw-r--r-- | zephyr/emul/emul_bmi260.c | 571 | ||||
-rw-r--r-- | zephyr/emul/emul_common_i2c.c | 432 | ||||
-rw-r--r-- | zephyr/emul/emul_lis2dw12.c | 161 | ||||
-rw-r--r-- | zephyr/emul/emul_ln9310.c | 388 | ||||
-rw-r--r-- | zephyr/emul/emul_pi3usb9201.c | 195 | ||||
-rw-r--r-- | zephyr/emul/emul_smart_battery.c | 893 | ||||
-rw-r--r-- | zephyr/emul/emul_syv682x.c | 219 | ||||
-rw-r--r-- | zephyr/emul/emul_tcs3400.c | 650 | ||||
-rw-r--r-- | zephyr/emul/i2c_mock.c | 70 |
18 files changed, 0 insertions, 7028 deletions
diff --git a/zephyr/emul/CMakeLists.txt b/zephyr/emul/CMakeLists.txt deleted file mode 100644 index 02b176b942..0000000000 --- a/zephyr/emul/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# 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. - -zephyr_library_sources_ifdef(CONFIG_EMUL_COMMON_I2C emul_common_i2c.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_SMART_BATTERY emul_smart_battery.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BMA255 emul_bma255.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BC12_DETECT_PI3USB9201 emul_pi3usb9201.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_PPC_SYV682X emul_syv682x.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi160.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BMI emul_bmi260.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_TCS3400 emul_tcs3400.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_BB_RETIMER emul_bb_retimer.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_LN9310 emul_ln9310.c) -zephyr_library_sources_ifdef(CONFIG_EMUL_LIS2DW12 emul_lis2dw12.c) -zephyr_library_sources_ifdef(CONFIG_I2C_MOCK i2c_mock.c) diff --git a/zephyr/emul/Kconfig b/zephyr/emul/Kconfig deleted file mode 100644 index 8d9c8e42ea..0000000000 --- a/zephyr/emul/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# 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. - -config EMUL_COMMON_I2C - bool "Common handler for I2C emulator messages" - help - Enable common code that is used by many emulators of devices on I2C - bus. It allows to share code for handling I2C messages, locking and - custom user handlers between these emulators. - -config EMUL_SMART_BATTERY - bool "Smart Battery emulator" - select EMUL_COMMON_I2C - help - Enable the Smart Battery emulator. This driver use emulated I2C bus. - -config EMUL_BMA255 - bool "BMA255 emulator" - select EMUL_COMMON_I2C - help - Enable the BMA255 emulator. This driver use emulated I2C bus. - It is used to test bma2x2 driver. Emulators API is available in - zephyr/include/emul/emul_bma255.h - -config EMUL_BC12_DETECT_PI3USB9201 - bool "PI3USB9201 emulator" - help - Enable the PI3USB9201 emulator. PI3USB9201 is a BC1.2 charger - detector/advertiser. The emulator supports reading and writing the - 4 I2C registers of the PI3USB9201 using the emulated I2C bus. - -config EMUL_PPC_SYV682X - bool "Silergy SYV682x PPC emulator" - select PLATFORM_EC_USBC_PPC_SYV682X - help - Enable the SYV682x emulator. SYV682 is a USB Type-C PPC. This driver - uses the emulated I2C bus. - -config EMUL_BMI - bool "BMI emulator" - select EMUL_COMMON_I2C - help - Enable the BMI emulator. This driver use emulated I2C bus. - It is used to test bmi 160 and 260 drivers. Emulators API is - available in zephyr/include/emul/emul_bmi.h - -config EMUL_TCS3400 - bool "TCS3400 emulator" - select EMUL_COMMON_I2C - help - Enable the TCS3400 light sensor. This driver use emulated I2C bus. - It is used to test als_tcs3400 driver. It supports reading sensor - values which are correctly scaled using current gain and integration - time configuration, switching between IR and clear sensor and - clearing status register using clear interrupt registers. Other - TCS3400 registers support read and write with optional checking - of proper access to reserved bits. Emulators API is available in - zephyr/include/emul/emul_tcs3400.h - -config EMUL_BB_RETIMER - bool "BB retimer emulator" - select EMUL_COMMON_I2C - help - Enable the BB (Burnside Bridge) retimer emulator. This driver use - emulated I2C bus. It is used to test bb_retimer driver. It supports - reads and writes to all emulator registers. Emulators API is - available in zephyr/include/emul/emul_bb_retimer.h - -rsource "Kconfig.ln9310" -rsource "Kconfig.lis2dw12" -rsource "Kconfig.i2c_mock" diff --git a/zephyr/emul/Kconfig.i2c_mock b/zephyr/emul/Kconfig.i2c_mock deleted file mode 100644 index 6c98a32739..0000000000 --- a/zephyr/emul/Kconfig.i2c_mock +++ /dev/null @@ -1,22 +0,0 @@ -# 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. - -DT_COMPAT_I2C_MOCK := cros,i2c-mock - -menuconfig I2C_MOCK - bool "Mock implementation of an I2C device" - default $(dt_compat_enabled,$(DT_COMPAT_I2C_MOCK)) - depends on I2C_EMUL - help - Enable the I2C mock. This driver is a pure mock and does nothing by - default. It is used to test common i2c code. Mock API is available in - zephyr/include/emul/i2c_mock.h - -if I2C_MOCK - -module = I2C_MOCK -module-str = i2c_mock -source "subsys/logging/Kconfig.template.log_config" - -endif # I2C_MOCK diff --git a/zephyr/emul/Kconfig.lis2dw12 b/zephyr/emul/Kconfig.lis2dw12 deleted file mode 100644 index 2263255418..0000000000 --- a/zephyr/emul/Kconfig.lis2dw12 +++ /dev/null @@ -1,23 +0,0 @@ -# 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. - -DT_COMPAT_LIS2DW12_EMUL := cros,lis2dw12-emul - -menuconfig EMUL_LIS2DW12 - bool "LIS2DW12 accelerometer emulator" - default $(dt_compat_enabled,$(DT_COMPAT_LIS2DW12_EMUL)) - depends on I2C_EMUL - select PLATFORM_EC_ACCEL_LIS2DW12 - help - Enable the LIS2DW12 emulator. This driver uses the emulated I2C bus. - It is used to test the lis2dw12 driver. Emulator API is available in - zephyr/include/emul/emul_lis2dw12.h - -if EMUL_LIS2DW12 - -module = LIS2DW12_EMUL -module-str = lis2dw12_emul -source "subsys/logging/Kconfig.template.log_config" - -endif # EMUL_LIS2DW12 diff --git a/zephyr/emul/Kconfig.ln9310 b/zephyr/emul/Kconfig.ln9310 deleted file mode 100644 index 5773cf3721..0000000000 --- a/zephyr/emul/Kconfig.ln9310 +++ /dev/null @@ -1,22 +0,0 @@ -# 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. - -DT_COMPAT_LN9310_EMUL := cros,ln9310-emul - -menuconfig EMUL_LN9310 - bool "LN9310 switchcap emulator" - default $(dt_compat_enabled,$(DT_COMPAT_LN9310_EMUL)) - depends on I2C_EMUL - help - Enable the LN9310 emulator. This driver uses the emulated I2C bus. It - is used to test the ln9310 driver. Emulator API is available in - zephyr/include/emul/emul_ln9310.h - -if EMUL_LN9310 - -module = LN9310_EMUL -module-str = ln9310_emul -source "subsys/logging/Kconfig.template.log_config" - -endif # EMUL_LN9310 diff --git a/zephyr/emul/emul_bb_retimer.c b/zephyr/emul/emul_bb_retimer.c deleted file mode 100644 index b391070b1f..0000000000 --- a/zephyr/emul/emul_bb_retimer.c +++ /dev/null @@ -1,365 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT cros_bb_retimer_emul - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_bb_retimer); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" -#include "emul/emul_bb_retimer.h" - -#include "driver/retimer/bb_retimer.h" - -#define BB_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct bb_emul_data, common) - -/** Run-time data used by the emulator */ -struct bb_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Current state of all emulated BB retimer registers */ - uint32_t reg[BB_RETIMER_REG_COUNT]; - - /** Vendor ID of emulated device */ - uint32_t vendor_id; - - /** Return error when trying to write to RO register */ - bool error_on_ro_write; - /** Return error when trying to write 1 to reserved bit */ - bool error_on_rsvd_write; - - /** Value of data dword in ongoing i2c message */ - uint32_t data_dword; -}; - -/** Check description in emul_bb_retimer.h */ -void bb_emul_set_reg(struct i2c_emul *emul, int reg, uint32_t val) -{ - struct bb_emul_data *data; - - if (reg < 0 || reg > BB_RETIMER_REG_COUNT) { - return; - } - - data = BB_DATA_FROM_I2C_EMUL(emul); - data->reg[reg] = val; -} - -/** Check description in emul_bb_retimer.h */ -uint32_t bb_emul_get_reg(struct i2c_emul *emul, int reg) -{ - struct bb_emul_data *data; - - if (reg < 0 || reg > BB_RETIMER_REG_COUNT) { - return 0; - } - - data = BB_DATA_FROM_I2C_EMUL(emul); - - return data->reg[reg]; -} - -/** Check description in emul_bb_retimer.h */ -void bb_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - data->error_on_ro_write = set; -} - -/** Check description in emul_bb_retimer.h */ -void bb_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - data->error_on_rsvd_write = set; -} - -/** Mask reserved bits in each register of BB retimer */ -static const uint32_t bb_emul_rsvd_mask[] = { - [BB_RETIMER_REG_VENDOR_ID] = 0x00000000, - [BB_RETIMER_REG_DEVICE_ID] = 0x00000000, - [0x02] = 0xffffffff, /* Reserved */ - [0x03] = 0xffffffff, /* Reserved */ - [BB_RETIMER_REG_CONNECTION_STATE] = 0xc0201000, - [BB_RETIMER_REG_TBT_CONTROL] = 0xffffdfff, - [0x06] = 0xffffffff, /* Reserved */ - [BB_RETIMER_REG_EXT_CONNECTION_MODE] = 0x08007f00, -}; - -/** - * @brief Reset registers to default values - * - * @param emul Pointer to BB retimer emulator - */ -static void bb_emul_reset(struct i2c_emul *emul) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - - data->reg[BB_RETIMER_REG_VENDOR_ID] = data->vendor_id; - data->reg[BB_RETIMER_REG_DEVICE_ID] = BB_RETIMER_DEVICE_ID; - data->reg[0x02] = 0x00; /* Reserved */ - data->reg[0x03] = 0x00; /* Reserved */ - data->reg[BB_RETIMER_REG_CONNECTION_STATE] = 0x00; - data->reg[BB_RETIMER_REG_TBT_CONTROL] = 0x00; - data->reg[0x06] = 0x00; /* Reserved */ - data->reg[BB_RETIMER_REG_EXT_CONNECTION_MODE] = 0x00; -} - -/** - * @brief Handle I2C write message. It is checked if accessed register isn't RO - * and reserved bits are set to 0. Write set value of reg field of BB - * retimer emulator data ignoring reserved bits and write only bits. - * - * @param emul Pointer to BB retimer emulator - * @param reg Register which is written - * @param msg_len Length of handled I2C message - * - * @return 0 on success - * @return -EIO on error - */ -static int bb_emul_handle_write(struct i2c_emul *emul, int reg, int msg_len) -{ - struct bb_emul_data *data; - uint32_t val; - - data = BB_DATA_FROM_I2C_EMUL(emul); - - /* This write only selected register for I2C read message */ - if (msg_len < 2) { - return 0; - } - - val = data->data_dword; - - /* - * BB retimer ignores data bytes above 4 and use zeros if there is less - * then 4 data bytes. Emulator prints warning in that case. - */ - if (msg_len != 6) { - LOG_WRN("Got %d bytes of WR data, expected 4", msg_len - 2); - } - - if (reg <= BB_RETIMER_REG_DEVICE_ID || - reg >= BB_RETIMER_REG_COUNT || - reg == BB_RETIMER_REG_TBT_CONTROL) { - if (data->error_on_ro_write) { - LOG_ERR("Writing to reg 0x%x which is RO", reg); - return -EIO; - } - - return 0; - } - - if (data->error_on_rsvd_write && bb_emul_rsvd_mask[reg] & val) { - LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x", - val, reg, bb_emul_rsvd_mask[reg]); - return -EIO; - } - - /* Ignore all reserved bits */ - val &= ~bb_emul_rsvd_mask[reg]; - val |= data->reg[reg] & bb_emul_rsvd_mask[reg]; - - data->reg[reg] = val; - - return 0; -} - -/** - * @brief Handle I2C read message. Response is obtained from reg field of bb - * emul data. - * - * @param emul Pointer to BB retimer emulator - * @param reg Register address to read - * - * @return 0 on success - * @return -EIO on error - */ -static int bb_emul_handle_read(struct i2c_emul *emul, int reg) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - - if (reg >= BB_RETIMER_REG_COUNT) { - LOG_ERR("Read unknown register 0x%x", reg); - - return -EIO; - } - - data->data_dword = data->reg[reg]; - - return 0; -} - -/** - * @brief Function called for each byte of write message. Data are stored - * in data_dword field of bb_emul_data - * - * @param emul Pointer to BB retimer emulator - * @param reg First byte of write message - * @param val Received byte of write message - * @param bytes Number of bytes already received - * - * @return 0 on success - */ -static int bb_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - - if (bytes == 1) { - data->data_dword = 0; - if (val != 4) { - LOG_WRN("Invalid write size"); - } - } else if (bytes < 6) { - data->data_dword |= val << (8 * (bytes - 2)); - } - - return 0; -} - -/** - * @brief Function called for each byte of read message. data_dword is converted - * to read message response. - * - * @param emul Pointer to BB retimer emulator - * @param reg First byte of last write message - * @param val Pointer where byte to read should be stored - * @param bytes Number of bytes already readed - * - * @return 0 on success - */ -static int bb_emul_read_byte(struct i2c_emul *emul, int reg, uint8_t *val, - int bytes) -{ - struct bb_emul_data *data; - - data = BB_DATA_FROM_I2C_EMUL(emul); - - /* First byte of read message is read size which is always 4 */ - if (bytes == 0) { - *val = 4; - return 0; - } - - *val = data->data_dword & 0xff; - data->data_dword >>= 8; - - return 0; -} - -/** - * @brief Get currently accessed register, which always equals to selected - * register. - * - * @param emul Pointer to BB retimer emulator - * @param reg First byte of last write message - * @param bytes Number of bytes already handled from current message - * @param read If currently handled is read message - * - * @return Currently accessed register - */ -static int bb_emul_access_reg(struct i2c_emul *emul, int reg, int bytes, - bool read) -{ - return reg; -} - -/* Device instantiation */ - -static struct i2c_emul_api bb_emul_api = { - .transfer = i2c_common_emul_transfer, -}; - -/** - * @brief Set up a new BB retimer emulator - * - * This should be called for each BB retimer device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int bb_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = cfg->data; - int ret; - - data->emul.api = &bb_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - bb_emul_reset(&data->emul); - - return ret; -} - -#define BB_RETIMER_EMUL(n) \ - static struct bb_emul_data bb_emul_data_##n = { \ - .vendor_id = DT_STRING_TOKEN(DT_DRV_INST(n), vendor), \ - .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\ - .error_on_rsvd_write = DT_INST_PROP(n, \ - error_on_reserved_bit_write), \ - .common = { \ - .start_write = NULL, \ - .write_byte = bb_emul_write_byte, \ - .finish_write = bb_emul_handle_write, \ - .start_read = bb_emul_handle_read, \ - .read_byte = bb_emul_read_byte, \ - .finish_read = NULL, \ - .access_reg = bb_emul_access_reg, \ - }, \ - }; \ - \ - static const struct i2c_common_emul_cfg bb_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &bb_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(bb_emul_init, DT_DRV_INST(n), &bb_emul_cfg_##n, \ - &bb_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(BB_RETIMER_EMUL) - -#define BB_RETIMER_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &bb_emul_data_##n.common.emul; - -/** Check description in emul_bb_emulator.h */ -struct i2c_emul *bb_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(BB_RETIMER_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_bma255.c b/zephyr/emul/emul_bma255.c deleted file mode 100644 index 77b1f5246c..0000000000 --- a/zephyr/emul/emul_bma255.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_bma255 - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_bma255); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" -#include "emul/emul_bma255.h" - -#include "driver/accel_bma2x2.h" - -#define BMA_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct bma_emul_data, common) - -/** Run-time data used by the emulator */ -struct bma_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Value of data byte in ongoing write message */ - uint8_t write_byte; - - /** Current state of all emulated BMA255 registers */ - uint8_t reg[0x40]; - /** Current state of NVM where offset and GP0/1 can be saved */ - uint8_t nvm_x; - uint8_t nvm_y; - uint8_t nvm_z; - uint8_t nvm_gp0; - uint8_t nvm_gp1; - /** Internal offset values used in calculations */ - int16_t off_x; - int16_t off_y; - int16_t off_z; - /** Internal values of accelerometr */ - int16_t acc_x; - int16_t acc_y; - int16_t acc_z; - - /** - * Return error when trying to start offset compensation when not ready - * flag is set. - */ - bool error_on_cal_trg_nrdy; - /** - * Return error when trying to start offset compensation with range - * set to value different than 2G. - */ - bool error_on_cal_trg_bad_range; - /** Return error when trying to write to RO register */ - bool error_on_ro_write; - /** Return error when trying to write 1 to reserved bit */ - bool error_on_rsvd_write; - /** Return error when trying to access MSB before LSB */ - bool error_on_msb_first; - /** - * Flag set when LSB register is accessed and cleared when MSB is - * accessed. Allows to track order of accessing acc registers - */ - bool lsb_x_read; - bool lsb_y_read; - bool lsb_z_read; -}; - -/** Check description in emul_bma255.h */ -void bma_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) -{ - struct bma_emul_data *data; - - if (reg < 0 || reg > BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - return; - } - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->reg[reg] = val; -} - -/** Check description in emul_bma255.h */ -uint8_t bma_emul_get_reg(struct i2c_emul *emul, int reg) -{ - struct bma_emul_data *data; - - if (reg < 0 || reg > BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - return 0; - } - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - return data->reg[reg]; -} - -/** - * @brief Convert @p val to two's complement representation. It makes sure that - * bit representation is correct even on platforms which represent - * signed inteager in different format. Unsigned bit representation - * allows to use well defined bitwise operations on returned value. - * - * @param val Inteager that is converted - * - * @return two's complement representation of @p val - */ -static uint16_t bma_emul_val_to_twos_comp(int16_t val) -{ - uint16_t twos_comp_val; - - /* Make sure that value is converted to twos compliment format */ - if (val < 0) { - twos_comp_val = (uint16_t)(-val); - twos_comp_val = ~twos_comp_val + 1; - } else { - twos_comp_val = (uint16_t)val; - } - - return twos_comp_val; -} - -/** - * @brief Convert value from NVM format (8bit, 0x01 == 7.8mg) to internal - * offset format (16bit, 0x01 == 0.97mg). - * - * @param nvm Value in NVM format (8bit, 0x01 == 7.8mg). This is binary - * representation of two's complement signed number. - * - * @return offset Internal representation of @p nvm (16bit, 0x01 == 0.97mg) - */ -static int16_t bma_emul_nvm_to_off(uint8_t nvm) -{ - int16_t offset; - int8_t sign; - - if (nvm & BIT(7)) { - sign = -1; - /* NVM value is in two's complement format */ - nvm = ~nvm + 1; - } else { - sign = 1; - } - - offset = (int16_t)nvm; - /* LSB in NVM is 7.8mg, while LSB in internal offset is 0.97mg */ - offset *= sign * 8; - - return offset; -} - -/** - * @brief Convert value from internal offset format (16bit, 0x01 == 0.97mg) to - * NVM format (8bit, 0x01 == 7.8mg). Function makes sure that NVM value - * is representation of two's complement signed number. - * - * @param val Value in internal offset format (16bit, 0x01 == 0.97mg). - * - * @return nvm NVM format representation of @p val (8bit, 0x01 == 7.8mg) - */ -static uint8_t bma_emul_off_to_nvm(int16_t off) -{ - uint16_t twos_comp_val; - uint8_t nvm = 0; - - twos_comp_val = bma_emul_val_to_twos_comp(off); - - /* - * LSB in internal representation has value 0.97mg, while in NVM - * LSB is 7.8mg. Skip 0.97mg, 1.9mg and 3.9mg bits. - */ - nvm |= (twos_comp_val >> 3) & 0x7f; - /* Set sign bit */ - nvm |= (twos_comp_val & BIT(15)) ? BIT(7) : 0x00; - - return nvm; -} - -/** Check description in emul_bma255.h */ -int16_t bma_emul_get_off(struct i2c_emul *emul, int axis) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMA_EMUL_AXIS_X: - return data->off_x; - case BMA_EMUL_AXIS_Y: - return data->off_y; - case BMA_EMUL_AXIS_Z: - return data->off_z; - } - - return 0; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_off(struct i2c_emul *emul, int axis, int16_t val) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMA_EMUL_AXIS_X: - data->off_x = val; - data->reg[BMA2x2_OFFSET_X_AXIS_ADDR] = bma_emul_off_to_nvm( - data->off_x); - break; - case BMA_EMUL_AXIS_Y: - data->off_y = val; - data->reg[BMA2x2_OFFSET_Y_AXIS_ADDR] = bma_emul_off_to_nvm( - data->off_y); - break; - case BMA_EMUL_AXIS_Z: - data->off_z = val; - data->reg[BMA2x2_OFFSET_Z_AXIS_ADDR] = bma_emul_off_to_nvm( - data->off_z); - break; - } -} - -/** Check description in emul_bma255.h */ -int16_t bma_emul_get_acc(struct i2c_emul *emul, int axis) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMA_EMUL_AXIS_X: - return data->acc_x; - case BMA_EMUL_AXIS_Y: - return data->acc_y; - case BMA_EMUL_AXIS_Z: - return data->acc_z; - } - - return 0; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_acc(struct i2c_emul *emul, int axis, int16_t val) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMA_EMUL_AXIS_X: - data->acc_x = val; - break; - case BMA_EMUL_AXIS_Y: - data->acc_y = val; - break; - case BMA_EMUL_AXIS_Z: - data->acc_z = val; - break; - } -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_err_on_cal_nrdy(struct i2c_emul *emul, bool set) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->error_on_cal_trg_nrdy = set; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_err_on_cal_bad_range(struct i2c_emul *emul, bool set) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->error_on_cal_trg_bad_range = set; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->error_on_ro_write = set; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->error_on_rsvd_write = set; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_err_on_msb_first(struct i2c_emul *emul, bool set) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - data->error_on_msb_first = set; -} - -/** Mask reserved bits in each register of BMA255 */ -static const uint8_t bma_emul_rsvd_mask[] = { - [BMA2x2_CHIP_ID_ADDR] = 0x00, - [0x01] = 0xff, /* Reserved */ - [BMA2x2_X_AXIS_LSB_ADDR] = 0x0e, - [BMA2x2_X_AXIS_MSB_ADDR] = 0x00, - [BMA2x2_Y_AXIS_LSB_ADDR] = 0x0e, - [BMA2x2_Y_AXIS_MSB_ADDR] = 0x00, - [BMA2x2_Z_AXIS_LSB_ADDR] = 0x0e, - [BMA2x2_Z_AXIS_MSB_ADDR] = 0x00, - [BMA2x2_TEMP_ADDR] = 0x00, - [BMA2x2_STAT1_ADDR] = 0x00, - [BMA2x2_STAT2_ADDR] = 0x1f, - [BMA2x2_STAT_TAP_SLOPE_ADDR] = 0x00, - [BMA2x2_STAT_ORIENT_HIGH_ADDR] = 0x00, - [0x0d] = 0xff, /* Reserved */ - [BMA2x2_STAT_FIFO_ADDR] = 0x00, - [BMA2x2_RANGE_SELECT_ADDR] = 0xf0, - [BMA2x2_BW_SELECT_ADDR] = 0xe0, - [BMA2x2_MODE_CTRL_ADDR] = 0x01, - [BMA2x2_LOW_NOISE_CTRL_ADDR] = 0x9f, - [BMA2x2_DATA_CTRL_ADDR] = 0x3f, - [BMA2x2_RST_ADDR] = 0x00, - [0x15] = 0xff, /* Reserved */ - [BMA2x2_INTR_ENABLE1_ADDR] = 0x08, - [BMA2x2_INTR_ENABLE2_ADDR] = 0x80, - [BMA2x2_INTR_SLOW_NO_MOTION_ADDR] = 0xf0, - [BMA2x2_INTR1_PAD_SELECT_ADDR] = 0x00, - [BMA2x2_INTR_DATA_SELECT_ADDR] = 0x18, - [BMA2x2_INTR2_PAD_SELECT_ADDR] = 0x00, - [0x1c] = 0xff, /* Reserved */ - [0x1d] = 0xff, /* Reserved */ - [BMA2x2_INTR_SOURCE_ADDR] = 0xc0, - [0x1f] = 0xff, /* Reserved */ - [BMA2x2_INTR_SET_ADDR] = 0xf0, - [BMA2x2_INTR_CTRL_ADDR] = 0x70, - [BMA2x2_LOW_DURN_ADDR] = 0x00, - [BMA2x2_LOW_THRES_ADDR] = 0x00, - [BMA2x2_LOW_HIGH_HYST_ADDR] = 0x38, - [BMA2x2_HIGH_DURN_ADDR] = 0x00, - [BMA2x2_HIGH_THRES_ADDR] = 0x00, - [BMA2x2_SLOPE_DURN_ADDR] = 0x00, - [BMA2x2_SLOPE_THRES_ADDR] = 0x00, - [BMA2x2_SLOW_NO_MOTION_THRES_ADDR] = 0x00, - [BMA2x2_TAP_PARAM_ADDR] = 0x38, - [BMA2x2_TAP_THRES_ADDR] = 0x20, - [BMA2x2_ORIENT_PARAM_ADDR] = 0x80, - [BMA2x2_THETA_BLOCK_ADDR] = 0x80, - [BMA2x2_THETA_FLAT_ADDR] = 0xc0, - [BMA2x2_FLAT_HOLD_TIME_ADDR] = 0xc8, - [BMA2x2_FIFO_WML_TRIG] = 0xc0, - [0x31] = 0xff, /* Reserved */ - [BMA2x2_SELFTEST_ADDR] = 0xf8, - [BMA2x2_EEPROM_CTRL_ADDR] = 0x00, - [BMA2x2_SERIAL_CTRL_ADDR] = 0xf8, - [0x35] = 0xff, /* Reserved */ - [BMA2x2_OFFSET_CTRL_ADDR] = 0x08, - [BMA2x2_OFC_SETTING_ADDR] = 0x80, - [BMA2x2_OFFSET_X_AXIS_ADDR] = 0x00, - [BMA2x2_OFFSET_Y_AXIS_ADDR] = 0x00, - [BMA2x2_OFFSET_Z_AXIS_ADDR] = 0x00, - [BMA2x2_GP0_ADDR] = 0x00, - [BMA2x2_GP1_ADDR] = 0x00, - [0x3d] = 0xff, /* Reserved */ - [BMA2x2_FIFO_MODE_ADDR] = 0x3c, - [BMA2x2_FIFO_DATA_OUTPUT_ADDR] = 0x00, -}; - -/** - * @brief Reset register values and internal representation of offset and two - * general purpose registers - * - * @param emul Pointer to BMA255 emulator - */ -static void bma_emul_restore_nvm(struct i2c_emul *emul) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - /* Restore registers values */ - data->reg[BMA2x2_OFFSET_X_AXIS_ADDR] = data->nvm_x; - data->reg[BMA2x2_OFFSET_Y_AXIS_ADDR] = data->nvm_y; - data->reg[BMA2x2_OFFSET_Z_AXIS_ADDR] = data->nvm_z; - data->reg[BMA2x2_GP0_ADDR] = data->nvm_gp0; - data->reg[BMA2x2_GP1_ADDR] = data->nvm_gp1; - - /* Restore internal offset values */ - data->off_x = bma_emul_nvm_to_off(data->nvm_x); - data->off_y = bma_emul_nvm_to_off(data->nvm_y); - data->off_z = bma_emul_nvm_to_off(data->nvm_z); -} - -/** - * @brief Reset registers to default values and restore registers backed by NVM - * - * @param emul Pointer to BMA255 emulator - */ -static void bma_emul_reset(struct i2c_emul *emul) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - data->reg[BMA2x2_CHIP_ID_ADDR] = 0xfa; - data->reg[0x01] = 0x00; /* Reserved */ - data->reg[BMA2x2_X_AXIS_LSB_ADDR] = 0x00; - data->reg[BMA2x2_X_AXIS_MSB_ADDR] = 0x00; - data->reg[BMA2x2_Y_AXIS_LSB_ADDR] = 0x00; - data->reg[BMA2x2_Y_AXIS_MSB_ADDR] = 0x00; - data->reg[BMA2x2_Z_AXIS_LSB_ADDR] = 0x00; - data->reg[BMA2x2_Z_AXIS_MSB_ADDR] = 0x00; - data->reg[BMA2x2_TEMP_ADDR] = 0x00; - data->reg[BMA2x2_STAT1_ADDR] = 0x00; - data->reg[BMA2x2_STAT2_ADDR] = 0x00; - data->reg[BMA2x2_STAT_TAP_SLOPE_ADDR] = 0x00; - data->reg[BMA2x2_STAT_ORIENT_HIGH_ADDR] = 0x00; - data->reg[0x0d] = 0xff; /* Reserved */ - data->reg[BMA2x2_STAT_FIFO_ADDR] = 0x00; - data->reg[BMA2x2_RANGE_SELECT_ADDR] = 0x03; - data->reg[BMA2x2_BW_SELECT_ADDR] = 0x0f; - data->reg[BMA2x2_MODE_CTRL_ADDR] = 0x00; - data->reg[BMA2x2_LOW_NOISE_CTRL_ADDR] = 0x00; - data->reg[BMA2x2_DATA_CTRL_ADDR] = 0x00; - data->reg[BMA2x2_RST_ADDR] = 0x00; - data->reg[0x15] = 0xff; /* Reserved */ - data->reg[BMA2x2_INTR_ENABLE1_ADDR] = 0x00; - data->reg[BMA2x2_INTR_ENABLE2_ADDR] = 0x00; - data->reg[BMA2x2_INTR_SLOW_NO_MOTION_ADDR] = 0x00; - data->reg[BMA2x2_INTR1_PAD_SELECT_ADDR] = 0x00; - data->reg[BMA2x2_INTR_DATA_SELECT_ADDR] = 0x00; - data->reg[BMA2x2_INTR2_PAD_SELECT_ADDR] = 0x00; - data->reg[0x1c] = 0xff; /* Reserved */ - data->reg[0x1d] = 0xff; /* Reserved */ - data->reg[BMA2x2_INTR_SOURCE_ADDR] = 0x00; - data->reg[0x1f] = 0xff; /* Reserved */ - data->reg[BMA2x2_INTR_SET_ADDR] = 0x05; - data->reg[BMA2x2_INTR_CTRL_ADDR] = 0x00; - data->reg[BMA2x2_LOW_DURN_ADDR] = 0x09; - data->reg[BMA2x2_LOW_THRES_ADDR] = 0x30; - data->reg[BMA2x2_LOW_HIGH_HYST_ADDR] = 0x81; - data->reg[BMA2x2_HIGH_DURN_ADDR] = 0x0f; - data->reg[BMA2x2_HIGH_THRES_ADDR] = 0xc0; - data->reg[BMA2x2_SLOPE_DURN_ADDR] = 0x00; - data->reg[BMA2x2_SLOPE_THRES_ADDR] = 0x14; - data->reg[BMA2x2_SLOW_NO_MOTION_THRES_ADDR] = 0x14; - data->reg[BMA2x2_TAP_PARAM_ADDR] = 0x04; - data->reg[BMA2x2_TAP_THRES_ADDR] = 0x0a; - data->reg[BMA2x2_ORIENT_PARAM_ADDR] = 0x18; - data->reg[BMA2x2_THETA_BLOCK_ADDR] = 0x48; - data->reg[BMA2x2_THETA_FLAT_ADDR] = 0x08; - data->reg[BMA2x2_FLAT_HOLD_TIME_ADDR] = 0x11; - data->reg[BMA2x2_FIFO_WML_TRIG] = 0x00; - data->reg[0x31] = 0xff; /* Reserved */ - data->reg[BMA2x2_SELFTEST_ADDR] = 0x00; - data->reg[BMA2x2_EEPROM_CTRL_ADDR] = 0xf0; - data->reg[BMA2x2_SERIAL_CTRL_ADDR] = 0x00; - data->reg[0x35] = 0x00; /* Reserved */ - data->reg[BMA2x2_OFFSET_CTRL_ADDR] = 0x10; - data->reg[BMA2x2_OFC_SETTING_ADDR] = 0x00; - data->reg[0x3d] = 0xff; /* Reserved */ - data->reg[BMA2x2_FIFO_MODE_ADDR] = 0x00; - data->reg[BMA2x2_FIFO_DATA_OUTPUT_ADDR] = 0x00; - - /* Restore registers backed in NVM */ - bma_emul_restore_nvm(emul); -} - -/** - * @brief Convert range in format of RANGE_SELECT register to number of bits - * that should be shifted right to obtain 12 bit reported accelerometer - * value from internal 16 bit value - * - * @param range Value of RANGE_SELECT register - * - * @return shift Number of LSB that should be ignored from internal - * accelerometer value - */ -static int bma_emul_range_to_shift(uint8_t range) -{ - switch (range & BMA2x2_RANGE_SELECT_MSK) { - case BMA2x2_RANGE_2G: - return 0; - case BMA2x2_RANGE_4G: - return 1; - case BMA2x2_RANGE_8G: - return 2; - case BMA2x2_RANGE_16G: - return 3; - default: - return -1; - } -} - -/** - * @brief Handle write requests to NVM control register. Allows to load/store - * NVM only when ready in current NVM control register is set. Load and - * stores to NVM are backed in bma_emul_data structure - * - * @param emul Pointer to BMA255 emulator - * @param val Value that is being written to NVM contorl register - * - * @return 0 on success - */ -static int bma_emul_handle_nvm_write(struct i2c_emul *emul, uint8_t val) -{ - struct bma_emul_data *data; - uint8_t writes_rem; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - /* NVM not ready, ignore write/load requests */ - if (!(data->reg[BMA2x2_EEPROM_CTRL_ADDR] & BMA2x2_EEPROM_RDY)) { - return 0; - } - - /* Restore data from NVM */ - if (val & BMA2x2_EEPROM_LOAD) { - bma_emul_restore_nvm(emul); - } - - writes_rem = (data->reg[BMA2x2_EEPROM_CTRL_ADDR] & - BMA2x2_EEPROM_REMAIN_MSK) >> BMA2x2_EEPROM_REMAIN_OFF; - /* Trigger write is set, write is unlocked and writes remaining */ - if (val & BMA2x2_EEPROM_PROG && - data->reg[BMA2x2_EEPROM_CTRL_ADDR] & BMA2x2_EEPROM_PROG_EN && - writes_rem > 0) { - data->nvm_x = data->reg[BMA2x2_OFFSET_X_AXIS_ADDR]; - data->nvm_y = data->reg[BMA2x2_OFFSET_Y_AXIS_ADDR]; - data->nvm_z = data->reg[BMA2x2_OFFSET_Z_AXIS_ADDR]; - data->nvm_gp0 = data->reg[BMA2x2_GP0_ADDR]; - data->nvm_gp1 = data->reg[BMA2x2_GP1_ADDR]; - /* Decrement number of remaining writes and save it in reg */ - writes_rem--; - data->reg[BMA2x2_EEPROM_CTRL_ADDR] &= - ~BMA2x2_EEPROM_REMAIN_MSK; - data->reg[BMA2x2_EEPROM_CTRL_ADDR] |= - writes_rem << BMA2x2_EEPROM_REMAIN_OFF; - } - - return 0; -} - -/** - * @brief Clear all interrupt registers - * - * @param emul Pointer to BMA255 emulator - */ -static void bma_emul_clear_int(struct i2c_emul *emul) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - data->reg[BMA2x2_STAT1_ADDR] = 0x00; - data->reg[BMA2x2_STAT2_ADDR] = 0x00; - data->reg[BMA2x2_STAT_TAP_SLOPE_ADDR] = 0x00; - data->reg[BMA2x2_STAT_ORIENT_HIGH_ADDR] = 0x00; -} - -/** - * @brief Get target value from offset compensation setting register for given - * @p axis - * - * @param emul Pointer to BMA255 emulator - * @param axis Axis to access: 0 - X, 1 - Y, 2 - Z - * - * @return target Value to which offset compensation should be calculated - */ -static int16_t bma_emul_get_target(struct i2c_emul *emul, int axis) -{ - struct bma_emul_data *data; - uint8_t target; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - target = data->reg[BMA2x2_OFC_SETTING_ADDR] >> - BMA2x2_OFC_TARGET_AXIS(axis); - switch (target) { - case BMA2x2_OFC_TARGET_0G: - return 0; - case BMA2x2_OFC_TARGET_PLUS_1G: - return BMA_EMUL_1G; - case BMA2x2_OFC_TARGET_MINUS_1G: - return -((int)BMA_EMUL_1G); - } - - return 0; -} - -/** - * @brief Handle writes to offset compensation control register. It allows to - * reset offset registers. It check if offset compenstation is ready - * and if range is set to 2G (required for fast compensation according - * to BMA255 documentation). If fast compensation is successfully - * triggered, internal offset value is set to - * (target - internal accelerometer value). - * - * @param emul Pointer to BMA255 emulator - * @param val Value being written to offset compensation control register - * - * @return 0 on success - * @return -EIO when trying to start fast compensation in wrong emulator state - */ -static int bma_emul_handle_off_comp(struct i2c_emul *emul, uint8_t val) -{ - struct bma_emul_data *data; - uint8_t trigger; - int16_t target; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - if (val & BMA2x2_OFFSET_RESET) { - data->off_x = 0; - data->off_y = 0; - data->off_z = 0; - data->reg[BMA2x2_OFFSET_X_AXIS_ADDR] = 0; - data->reg[BMA2x2_OFFSET_Y_AXIS_ADDR] = 0; - data->reg[BMA2x2_OFFSET_Z_AXIS_ADDR] = 0; - } - - - trigger = (val & BMA2x2_OFFSET_TRIGGER_MASK) >> - BMA2x2_OFFSET_TRIGGER_OFF; - - if (!(data->reg[BMA2x2_OFFSET_CTRL_ADDR] & BMA2x2_OFFSET_CAL_READY)) { - if (data->error_on_cal_trg_nrdy && trigger) { - LOG_ERR("Trying to start offset comp when not ready"); - return -EIO; - } - - return 0; - } - - if (bma_emul_range_to_shift(data->reg[BMA2x2_RANGE_SELECT_ADDR]) != 0 && - trigger && data->error_on_cal_trg_bad_range) { - LOG_ERR("Trying to start offset comp with range other than 2G"); - return -EIO; - } - - switch (trigger) { - case 1: - target = bma_emul_get_target(emul, BMA_EMUL_AXIS_X); - bma_emul_set_off(emul, BMA_EMUL_AXIS_X, target - data->acc_x); - break; - case 2: - target = bma_emul_get_target(emul, BMA_EMUL_AXIS_Y); - bma_emul_set_off(emul, BMA_EMUL_AXIS_Y, target - data->acc_y); - break; - case 3: - target = bma_emul_get_target(emul, BMA_EMUL_AXIS_Z); - bma_emul_set_off(emul, BMA_EMUL_AXIS_Z, target - data->acc_z); - break; - } - - return 0; -} - -/** - * @brief Handle I2C write message. It is checked if accessed register isn't RO - * and reserved bits are set to 0. Write set value of reg field of bma - * emulator data ignoring reserved bits and write only bits. Some - * commands are handled specialy. - * - * @param emul Pointer to BMA255 emulator - * @param reg Register which is written - * @param bytes Number of bytes in I2C write message - * - * @return 0 on success - * @return -EIO on error - */ -static int bma_emul_handle_write(struct i2c_emul *emul, int reg, int bytes) -{ - struct bma_emul_data *data; - uint8_t val; - int ret; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - val = data->write_byte; - - if (bytes > 2) { - LOG_ERR("Too long write command"); - return -EIO; - } - - /* This write only selected register for I2C read message */ - if (bytes < 2) { - return 0; - } - - if (reg <= BMA2x2_STAT_FIFO_ADDR || - reg >= BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - if (data->error_on_ro_write) { - LOG_ERR("Writing to reg 0x%x which is RO", reg); - return -EIO; - } - - return 0; - } - - if (data->error_on_rsvd_write && bma_emul_rsvd_mask[reg] & val) { - LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x", - val, reg, bma_emul_rsvd_mask[reg]); - return -EIO; - } - - - switch (reg) { - case BMA2x2_RST_ADDR: - if (val == BMA2x2_CMD_SOFT_RESET) { - bma_emul_reset(emul); - } - return 0; - case BMA2x2_INTR_CTRL_ADDR: - if (val & BMA2x2_INTR_CTRL_RST_INT) { - bma_emul_clear_int(emul); - } - /* Don't set write only bit in register */ - val &= ~BMA2x2_INTR_CTRL_RST_INT; - break; - case BMA2x2_EEPROM_CTRL_ADDR: - bma_emul_handle_nvm_write(emul, val); - /* Only programing enable bit is RW */ - val &= BMA2x2_EEPROM_PROG_EN; - val |= data->reg[reg] & ~BMA2x2_EEPROM_PROG_EN; - break; - case BMA2x2_OFFSET_CTRL_ADDR: - ret = bma_emul_handle_off_comp(emul, val); - if (ret) { - return -EIO; - } - /* Only slow compensation bits are RW */ - val &= BMA2x2_OFFSET_CAL_SLOW_X | BMA2x2_OFFSET_CAL_SLOW_Y | - BMA2x2_OFFSET_CAL_SLOW_Z; - val |= data->reg[reg] & ~(BMA2x2_OFFSET_CAL_SLOW_X | - BMA2x2_OFFSET_CAL_SLOW_Y | - BMA2x2_OFFSET_CAL_SLOW_Z); - break; - /* Change internal offset to value set in I2C message */ - case BMA2x2_OFFSET_X_AXIS_ADDR: - data->off_x = bma_emul_nvm_to_off(val); - break; - case BMA2x2_OFFSET_Y_AXIS_ADDR: - data->off_y = bma_emul_nvm_to_off(val); - break; - case BMA2x2_OFFSET_Z_AXIS_ADDR: - data->off_z = bma_emul_nvm_to_off(val); - break; - case BMA2x2_RANGE_SELECT_ADDR: - ret = bma_emul_range_to_shift(val); - if (ret < 0) { - LOG_ERR("Unknown range select value 0x%x", val); - return -EIO; - } - break; - } - - /* Ignore all reserved bits */ - val &= ~bma_emul_rsvd_mask[reg]; - val |= data->reg[reg] & bma_emul_rsvd_mask[reg]; - - data->reg[reg] = val; - - return 0; -} - -/** - * @brief Get set accelerometer value for given register using internal axis - * state @p val. In case of accessing MSB with enabled shadowing, - * check if LSB was accessed first. - * - * @param emul Pointer to BMA255 emulator - * @param lsb_reg LSB register address (BMA2x2_X_AXIS_LSB_ADDR, - * BMA2x2_Y_AXIS_LSB_ADDR, BMA2x2_Z_AXIS_LSB_ADDR) - * @param lsb_read Pointer to variable which represent if last access to this - * accelerometer value was through LSB register - * @param lsb True if now accessing LSB, Flase if now accessing MSB - * @param val Internal value of accessed accelerometer axis - * - * @return 0 on success - * @return -EIO when accessing MSB before LSB with enabled shadowing - */ -static int bma_emul_get_acc_val(struct i2c_emul *emul, int lsb_reg, - bool *lsb_read, bool lsb, int16_t val) -{ - struct bma_emul_data *data; - uint16_t twos_comp_val; - uint8_t new_data; - int msb_reg; - int shift; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - if (lsb) { - *lsb_read = 1; - } else if (!(data->reg[BMA2x2_DATA_CTRL_ADDR] & - BMA2x2_DATA_SHADOW_DIS)) { - /* - * If shadowing is enabled, error on first accessing MSB and - * LSB wasn't accessed before, then return error. - */ - if (data->error_on_msb_first && !(*lsb_read)) { - return -EIO; - } - *lsb_read = 0; - /* If shadowing is enabled, LSB read should set correct value */ - return 0; - } - - twos_comp_val = bma_emul_val_to_twos_comp(val); - msb_reg = lsb_reg + 1; - shift = bma_emul_range_to_shift(data->reg[BMA2x2_RANGE_SELECT_ADDR]); - - /* Save new data bit from register */ - new_data = data->reg[lsb_reg] & BMA2x2_AXIS_LSB_NEW_DATA; - /* Shift 16 bit value to 12 bit set in range register */ - twos_comp_val >>= shift; - /* Set [3:0] bits in first register */ - data->reg[lsb_reg] = ((twos_comp_val << 4) & 0xf0) | new_data; - /* Set [11:4] bits in second register */ - data->reg[msb_reg] = (twos_comp_val >> 4) & 0xff; - - return 0; -} - -/** Check description in emul_bma255.h */ -int bma_emul_access_reg(struct i2c_emul *emul, int reg, int bytes, bool read) -{ - /* - * Exclude first byte (select register) from total number of bytes - * in I2C write message - */ - if (!read) { - bytes--; - } - - if (reg <= BMA2x2_FIFO_DATA_OUTPUT_ADDR && - reg + bytes >= BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - return BMA2x2_FIFO_DATA_OUTPUT_ADDR; - } - - return reg + bytes; -} - -/** - * @brief Handle I2C read message. Response is obtained from reg field of bma - * emul data. When accessing accelerometer value, register data is first - * computed using internal emulator state. - * - * @param emul Pointer to BMA255 emulator - * @param reg Register address to read - * @param val Pointer where resultat should be stored - * @param bytes Number of bytes in I2C read message - * - * @return 0 on success - * @return -EIO on error - */ -static int bma_emul_handle_read(struct i2c_emul *emul, int reg, uint8_t *val, - int bytes) -{ - struct bma_emul_data *data; - int ret; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - reg = bma_emul_access_reg(emul, reg, bytes, true /* = read */); - - switch (reg) { - case BMA2x2_X_AXIS_LSB_ADDR: - /* Shouldn't fail for LSB */ - ret = bma_emul_get_acc_val(emul, reg, &data->lsb_x_read, true, - data->acc_x + data->off_x); - break; - case BMA2x2_X_AXIS_MSB_ADDR: - ret = bma_emul_get_acc_val(emul, reg - 1, &data->lsb_x_read, - false, data->acc_x + data->off_x); - if (ret) { - LOG_ERR("MSB X readed before LSB X"); - return -EIO; - } - break; - case BMA2x2_Y_AXIS_LSB_ADDR: - /* Shouldn't fail for LSB */ - ret = bma_emul_get_acc_val(emul, reg, &data->lsb_y_read, true, - data->acc_y + data->off_y); - break; - case BMA2x2_Y_AXIS_MSB_ADDR: - ret = bma_emul_get_acc_val(emul, reg - 1, &data->lsb_y_read, - false, data->acc_y + data->off_y); - if (ret) { - LOG_ERR("MSB Y readed before LSB Y"); - return -EIO; - } - break; - case BMA2x2_Z_AXIS_LSB_ADDR: - /* Shouldn't fail for LSB */ - ret = bma_emul_get_acc_val(emul, reg, &data->lsb_z_read, true, - data->acc_z + data->off_z); - break; - case BMA2x2_Z_AXIS_MSB_ADDR: - ret = bma_emul_get_acc_val(emul, reg - 1, &data->lsb_z_read, - false, data->acc_z + data->off_z); - if (ret) { - LOG_ERR("MSB Z readed before LSB Z"); - return -EIO; - } - break; - } - - *val = data->reg[reg]; - - return 0; -} - -/** - * @brief Handle I2C write message. Saves data that will be stored in register. - * - * @param emul Pointer to BMA emulator - * @param reg Register address that is accessed - * @param val Data to write to the register - * @param bytes Number of bytes already handled in this read message - * - * @return 0 on success - * @return -EIO on error - */ -static int bma_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct bma_emul_data *data; - - data = BMA_DATA_FROM_I2C_EMUL(emul); - - data->write_byte = val; - - return 0; -} - -/* Device instantiation */ - -static struct i2c_emul_api bma_emul_api = { - .transfer = i2c_common_emul_transfer, -}; - -/** - * @brief Set up a new BMA255 emulator - * - * This should be called for each BMA255 device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int bma_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = cfg->data; - int ret; - - data->emul.api = &bma_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - bma_emul_reset(&data->emul); - - return ret; -} - -#define BMA255_EMUL(n) \ - static struct bma_emul_data bma_emul_data_##n = { \ - .nvm_x = DT_INST_PROP(n, nvm_off_x), \ - .nvm_y = DT_INST_PROP(n, nvm_off_y), \ - .nvm_z = DT_INST_PROP(n, nvm_off_z), \ - .nvm_gp0 = DT_INST_PROP(n, nvm_gp0), \ - .nvm_gp1 = DT_INST_PROP(n, nvm_gp1), \ - .acc_x = DT_INST_PROP(n, nvm_acc_x), \ - .acc_y = DT_INST_PROP(n, nvm_acc_y), \ - .acc_z = DT_INST_PROP(n, nvm_acc_z), \ - .error_on_cal_trg_nrdy = DT_INST_PROP(n, \ - error_on_compensation_not_ready), \ - .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\ - .error_on_rsvd_write = DT_INST_PROP(n, \ - error_on_reserved_bit_write), \ - .error_on_msb_first = DT_INST_PROP(n, \ - error_on_msb_first_access), \ - .lsb_x_read = 0, \ - .lsb_y_read = 0, \ - .lsb_z_read = 0, \ - .common = { \ - .start_write = NULL, \ - .write_byte = bma_emul_write_byte, \ - .finish_write = bma_emul_handle_write, \ - .start_read = NULL, \ - .read_byte = bma_emul_handle_read, \ - .finish_read = NULL, \ - .access_reg = bma_emul_access_reg, \ - }, \ - }; \ - \ - static const struct i2c_common_emul_cfg bma_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &bma_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(bma_emul_init, DT_DRV_INST(n), &bma_emul_cfg_##n, \ - &bma_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(BMA255_EMUL) - -#define BMA255_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &bma_emul_data_##n.common.emul; - -/** Check description in emul_bma255.h */ -struct i2c_emul *bma_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(BMA255_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_bmi.c b/zephyr/emul/emul_bmi.c deleted file mode 100644 index 7923fe0eb5..0000000000 --- a/zephyr/emul/emul_bmi.c +++ /dev/null @@ -1,1116 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_bmi - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_bmi); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" -#include "emul/emul_bmi.h" - -#include "driver/accelgyro_bmi160.h" -#include "driver/accelgyro_bmi260.h" -#include "driver/accelgyro_bmi_common.h" - -#define BMI_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct bmi_emul_data, common) - -/** Run-time data used by the emulator */ -struct bmi_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Current state of all emulated BMI registers */ - uint8_t reg[BMI_EMUL_MAX_REG]; - /** Internal offset values used in calculations */ - int16_t off_acc_x; - int16_t off_acc_y; - int16_t off_acc_z; - int16_t off_gyr_x; - int16_t off_gyr_y; - int16_t off_gyr_z; - /** Internal values of sensors */ - int32_t acc_x; - int32_t acc_y; - int32_t acc_z; - int32_t gyr_x; - int32_t gyr_y; - int32_t gyr_z; - /** Current state of NVM where offset and configuration can be saved */ - uint8_t nvm[BMI_EMUL_MAX_NVM_REGS]; - - /** Return error when trying to write to RO register */ - bool error_on_ro_write; - /** Return error when trying to write 1 to reserved bit */ - bool error_on_rsvd_write; - /** - * If effect of command is vissable after simulated time from issuing - * command - */ - bool simulate_command_exec_time; - /** Return error when trying to read WO register */ - bool error_on_wo_read; - - /** Value of data byte in ongoing write message */ - uint8_t write_byte; - - /** List of FIFO frames */ - struct bmi_emul_frame *fifo_frame; - /** First FIFO frame in byte format */ - uint8_t fifo[21]; - /** Number of FIFO frames that were skipped */ - uint8_t fifo_skip; - /** Currently accessed byte of first frame */ - int fifo_frame_byte; - /** Length of first frame */ - int fifo_frame_len; - - /** Last time when emulator was resetted in sensor time units */ - int64_t zero_time; - /** Time when current command should end */ - uint32_t cmd_end_time; - - /** Emulated model of BMI */ - int type; - /** Pointer to data specific for emulated model of BMI */ - const struct bmi_emul_type_data *type_data; -}; - -/** Check description in emul_bmi.h */ -void bmi_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) -{ - struct bmi_emul_data *data; - - if (reg < 0 || reg > BMI_EMUL_MAX_REG) { - return; - } - - data = BMI_DATA_FROM_I2C_EMUL(emul); - data->reg[reg] = val; -} - -/** Check description in emul_bmi.h */ -uint8_t bmi_emul_get_reg(struct i2c_emul *emul, int reg) -{ - struct bmi_emul_data *data; - - if (reg < 0 || reg > BMI_EMUL_MAX_REG) { - return 0; - } - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - return data->reg[reg]; -} - -/** - * @brief Convert @p val to two's complement representation. It makes sure that - * bit representation is correct even on platforms which represent - * signed inteager in different format. Unsigned bit representation - * allows to use well defined bitwise operations on returned value. - * - * @param val Inteager that is converted - * - * @return two's complement representation of @p val - */ -static uint32_t bmi_emul_val_to_twos_comp(int32_t val) -{ - uint32_t twos_comp_val; - - /* Make sure that value is converted to twos compliment format */ - if (val < 0) { - twos_comp_val = (uint32_t)(-val); - twos_comp_val = ~twos_comp_val + 1; - } else { - twos_comp_val = (uint32_t)val; - } - - return twos_comp_val; -} - -/** - * @brief Convert accelerometer value from NVM format (8bit, 0x01 == 3.9mg) - * to internal offset format (16bit, 0x01 == 0.061mg). - * - * @param nvm Value in NVM format (8bit, 0x01 == 3.9mg). This is binary - * representation of two's complement signed number. - * - * @return offset Internal representation of @p nvm (16bit, 0x01 == 0.061mg) - */ -static int16_t bmi_emul_acc_nvm_to_off(uint8_t nvm) -{ - int16_t offset; - int8_t sign; - - if (nvm & BIT(7)) { - sign = -1; - /* NVM value is in two's complement format */ - nvm = ~nvm + 1; - } else { - sign = 1; - } - - offset = (int16_t)nvm; - /* LSB in NVM is 3.9mg, while LSB in internal offset is 0.061mg */ - offset *= sign * 64; - - return offset; -} - -/** - * @brief Convert gyroscope value from NVM format (10bit, 0x01 == 0.061 °/s) - * to internal offset format (16bit, 0x01 == 0.0038 °/s) - * - * @param nvm Value in NVM format (10bit, 0x01 == 0.061 °/s). This is binary - * representation of two's complement signed number. - * - * @return offset Internal representation of @p nvm (16bit, 0x01 == 0.0038 °/s) - */ -static int16_t bmi_emul_gyr_nvm_to_off(uint16_t nvm) -{ - int16_t offset; - int8_t sign; - - if (nvm & BIT(9)) { - sign = -1; - /* NVM value is in two's complement format */ - nvm = ~nvm + 1; - } else { - sign = 1; - } - - /* Mask 10 bits which holds value */ - nvm &= 0x3ff; - - offset = (int16_t)nvm; - /* LSB in NVM is 0.061°/s, while LSB in internal offset is 0.0038°/s */ - offset *= sign * 16; - - return offset; -} - -/** - * @brief Convert accelerometer value from internal offset format - * (16bit, 0x01 == 0.061mg) to NVM format (8bit, 0x01 == 7.8mg). - * Function makes sure that NVM value is representation of two's - * complement signed number. - * - * @param val Value in internal offset format (16bit, 0x01 == 0.061mg). - * - * @return nvm NVM format representation of @p val (8bit, 0x01 == 3.9mg) - */ -static uint8_t bmi_emul_acc_off_to_nvm(int16_t off) -{ - uint32_t twos_comp_val; - uint8_t nvm = 0; - - twos_comp_val = bmi_emul_val_to_twos_comp(off); - - /* - * LSB in internal representation has value 0.061mg, while in NVM - * LSB is 3.9mg. Skip 0.06mg, 0.12mg, 0.24mg, 0.48mg, 0.97mg and - * 1.9mg bits. - */ - nvm |= (twos_comp_val >> 6) & 0x7f; - /* Set sign bit */ - nvm |= (twos_comp_val & BIT(31)) ? BIT(7) : 0x00; - - return nvm; -} - -/** - * @brief Convert gyroscope value from internal offset format - * (16bit, 0x01 == 0.0038°/s) to NVM format (10bit, 0x01 == 0.061°/s). - * Function makes sure that NVM value is representation of two's - * complement signed number. - * - * @param val Value in internal offset format (16bit, 0x01 == 0.0038°/s). - * - * @return nvm NVM format representation of @p val (10bit, 0x01 == 0.061°/s) - */ -static uint16_t bmi_emul_gyr_off_to_nvm(int16_t off) -{ - uint32_t twos_comp_val; - uint16_t nvm = 0; - - twos_comp_val = bmi_emul_val_to_twos_comp(off); - - /* - * LSB in internal representation has value 0.0038°/s, while in NVM - * LSB is 0.061°/s. Skip 0.0038°/s, 0.0076°/s, 0.015°/s, and - * 0.03°/s bits. - */ - nvm |= (twos_comp_val >> 4) & 0x1ff; - /* Set sign bit */ - nvm |= (twos_comp_val & BIT(31)) ? BIT(9) : 0x00; - - return nvm; -} - -/** Check description in emul_bmi.h */ -int16_t bmi_emul_get_off(struct i2c_emul *emul, enum bmi_emul_axis axis) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMI_EMUL_ACC_X: - return data->off_acc_x; - case BMI_EMUL_ACC_Y: - return data->off_acc_y; - case BMI_EMUL_ACC_Z: - return data->off_acc_z; - case BMI_EMUL_GYR_X: - return data->off_gyr_x; - case BMI_EMUL_GYR_Y: - return data->off_gyr_y; - case BMI_EMUL_GYR_Z: - return data->off_gyr_z; - } - - return 0; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_off(struct i2c_emul *emul, enum bmi_emul_axis axis, - int16_t val) -{ - struct bmi_emul_data *data; - uint16_t gyr_off; - uint8_t gyr98_shift; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMI_EMUL_ACC_X: - data->off_acc_x = val; - data->reg[data->type_data->acc_off_reg] = - bmi_emul_acc_off_to_nvm(data->off_acc_x); - break; - case BMI_EMUL_ACC_Y: - data->off_acc_y = val; - data->reg[data->type_data->acc_off_reg + 1] = - bmi_emul_acc_off_to_nvm(data->off_acc_y); - break; - case BMI_EMUL_ACC_Z: - data->off_acc_z = val; - data->reg[data->type_data->acc_off_reg + 2] = - bmi_emul_acc_off_to_nvm(data->off_acc_z); - break; - case BMI_EMUL_GYR_X: - data->off_gyr_x = val; - gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_x); - data->reg[data->type_data->gyr_off_reg] = gyr_off & 0xff; - gyr98_shift = 0; - data->reg[data->type_data->gyr98_off_reg] &= - ~(0x3 << gyr98_shift); - data->reg[data->type_data->gyr98_off_reg] |= - (gyr_off & 0x300) >> (8 - gyr98_shift); - break; - case BMI_EMUL_GYR_Y: - data->off_gyr_y = val; - gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_y); - data->reg[data->type_data->gyr_off_reg + 1] = gyr_off & 0xff; - gyr98_shift = 2; - data->reg[data->type_data->gyr98_off_reg] &= - ~(0x3 << gyr98_shift); - data->reg[data->type_data->gyr98_off_reg] |= - (gyr_off & 0x300) >> (8 - gyr98_shift); - break; - case BMI_EMUL_GYR_Z: - data->off_gyr_z = val; - gyr_off = bmi_emul_gyr_off_to_nvm(data->off_gyr_z); - data->reg[data->type_data->gyr_off_reg + 2] = gyr_off & 0xff; - gyr98_shift = 4; - data->reg[data->type_data->gyr98_off_reg] &= - ~(0x3 << gyr98_shift); - data->reg[data->type_data->gyr98_off_reg] |= - (gyr_off & 0x300) >> (8 - gyr98_shift); - break; - } -} - -/** Check description in emul_bmi.h */ -int32_t bmi_emul_get_value(struct i2c_emul *emul, enum bmi_emul_axis axis) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMI_EMUL_ACC_X: - return data->acc_x; - case BMI_EMUL_ACC_Y: - return data->acc_y; - case BMI_EMUL_ACC_Z: - return data->acc_z; - case BMI_EMUL_GYR_X: - return data->gyr_x; - case BMI_EMUL_GYR_Y: - return data->gyr_y; - case BMI_EMUL_GYR_Z: - return data->gyr_z; - } - - return 0; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_value(struct i2c_emul *emul, enum bmi_emul_axis axis, - int32_t val) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case BMI_EMUL_ACC_X: - data->acc_x = val; - break; - case BMI_EMUL_ACC_Y: - data->acc_y = val; - break; - case BMI_EMUL_ACC_Z: - data->acc_z = val; - break; - case BMI_EMUL_GYR_X: - data->gyr_x = val; - break; - case BMI_EMUL_GYR_Y: - data->gyr_y = val; - break; - case BMI_EMUL_GYR_Z: - data->gyr_z = val; - break; - } -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - data->error_on_ro_write = set; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - data->error_on_rsvd_write = set; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_err_on_wo_read(struct i2c_emul *emul, bool set) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - data->error_on_wo_read = set; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_simulate_cmd_exec_time(struct i2c_emul *emul, bool set) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - data->simulate_command_exec_time = set; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_skipped_frames(struct i2c_emul *emul, uint8_t skip) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - data->fifo_skip = skip; -} - -/** - * @brief Convert current time to sensor time (39 us units) - * - * @return time in 39 us units - */ -static int64_t bmi_emul_get_sensortime(void) -{ - return k_uptime_ticks() * 1000000 / 39 / CONFIG_SYS_CLOCK_TICKS_PER_SEC; -} - -/** - * @brief Set registers at address @p reg with sensor time that elapsed since - * last reset of emulator - * - * @param emul Pointer to BMI emulator - * @param reg Pointer to 3 byte array, where current sensor time should be - * stored - */ -static void bmi_emul_set_sensortime_reg(struct i2c_emul *emul, uint8_t *reg) -{ - struct bmi_emul_data *data; - uint32_t twos_comp_val; - int64_t time; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - time = bmi_emul_get_sensortime(); - - twos_comp_val = bmi_emul_val_to_twos_comp(time - data->zero_time); - - *reg = twos_comp_val & 0xff; - *(reg + 1) = (twos_comp_val >> 8) & 0xff; - *(reg + 2) = (twos_comp_val >> 16) & 0xff; -} - -/** - * @brief Convert given sensor axis @p val from internal units to register - * units. It shifts value by @p shift bits to the right to account - * range set in emulator's registers. Result is saved at address @p reg - * - * @param emul Pointer to BMI emulator - * @param val Accelerometer or gyroscope value in internal units - * @param reg Pointer to 2 byte array, where sensor value should be stored - * @param shift How many bits should be shift to the right - */ -static void bmi_emul_set_data_reg(struct i2c_emul *emul, int32_t val, - uint8_t *reg, int shift) -{ - struct bmi_emul_data *data; - uint32_t twos_comp_val; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - twos_comp_val = bmi_emul_val_to_twos_comp(val); - - /* Shift unused bits because of selected range */ - twos_comp_val >>= shift; - - *reg = twos_comp_val & 0xff; - *(reg + 1) = (twos_comp_val >> 8) & 0xff; -} - -/** - * @brief Compute length of given FIFO @p frame. If frame is null then length - * of empty frame is returned. - * - * @param emul Pointer to BMI emulator - * @param frame Pointer to FIFO frame - * @param tag_time Indicate if sensor time should be included in empty frame - * @param header Indicate if header should be included in frame - * - * @return length of frame - */ -static uint8_t bmi_emul_get_frame_len(struct i2c_emul *emul, - struct bmi_emul_frame *frame, - bool tag_time, bool header) -{ - struct bmi_emul_data *data; - int len; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - /* Empty FIFO frame */ - if (frame == NULL) { - if (tag_time && header) { - /* Header of sensortime + sensortime + empty FIFO */ - return 5; - } - - /* Empty fifo */ - return 1; - } - - /* Config FIFO frame */ - if (frame->type & BMI_EMUL_FRAME_CONFIG) { - if (header) { - /* Header + byte of data */ - len = 2; - if (data->type_data->sensortime_follow_config_frame) { - /* Sensortime data */ - len += 3; - } - - return len; - } - - /* This frame doesn't exist in headerless mode */ - return 0; - } - - /* Sensor data FIFO frame */ - if (header) { - len = 1; - } else { - len = 0; - } - - if (frame->type & BMI_EMUL_FRAME_ACC) { - len += 6; - } - if (frame->type & BMI_EMUL_FRAME_MAG) { - len += 8; - } - if (frame->type & BMI_EMUL_FRAME_GYR) { - len += 6; - } - - return len; -} - -/** - * @brief Set given FIFO @p frame as current frame in fifo field of emulator - * data structure - * - * @param emul Pointer to BMI emulator - * @param frame Pointer to FIFO frame - * @param tag_time Indicate if sensor time should be included in empty frame - * @param header Indicate if header should be included in frame - * @param acc_shift How many bits should be right shifted from accelerometer - * data - * @param gyr_shift How many bits should be right shifted from gyroscope data - */ -static void bmi_emul_set_current_frame(struct i2c_emul *emul, - struct bmi_emul_frame *frame, - bool tag_time, bool header, - int acc_shift, int gyr_shift) -{ - struct bmi_emul_data *data; - int i = 0; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - data->fifo_frame_byte = 0; - data->fifo_frame_len = bmi_emul_get_frame_len(emul, frame, tag_time, - header); - /* Empty FIFO frame */ - if (frame == NULL) { - if (tag_time && header) { - /* Header */ - data->fifo[0] = BMI_EMUL_FIFO_HEAD_TIME; - bmi_emul_set_sensortime_reg(emul, &(data->fifo[1])); - i = 4; - } - - /* Empty header */ - data->fifo[i] = BMI_EMUL_FIFO_HEAD_EMPTY; - - return; - } - - /* Config FIFO frame */ - if (frame->type & BMI_EMUL_FRAME_CONFIG) { - /* Header */ - data->fifo[0] = BMI_EMUL_FIFO_HEAD_CONFIG; - data->fifo[1] = frame->config; - if (data->type_data->sensortime_follow_config_frame) { - bmi_emul_set_sensortime_reg(emul, &(data->fifo[2])); - } - - return; - } - - /* Sensor data FIFO frame */ - if (header) { - data->fifo[0] = BMI_EMUL_FIFO_HEAD_DATA; - data->fifo[0] |= frame->type & BMI_EMUL_FRAME_MAG ? - BMI_EMUL_FIFO_HEAD_DATA_MAG : 0; - data->fifo[0] |= frame->type & BMI_EMUL_FRAME_GYR ? - BMI_EMUL_FIFO_HEAD_DATA_GYR : 0; - data->fifo[0] |= frame->type & BMI_EMUL_FRAME_ACC ? - BMI_EMUL_FIFO_HEAD_DATA_ACC : 0; - data->fifo[0] |= frame->tag & BMI_EMUL_FIFO_HEAD_DATA_TAG_MASK; - i = 1; - } - - if (frame->type & BMI_EMUL_FRAME_MAG) { - bmi_emul_set_data_reg(emul, frame->mag_x, &(data->fifo[i]), 0); - i += 2; - bmi_emul_set_data_reg(emul, frame->mag_y, &(data->fifo[i]), 0); - i += 2; - bmi_emul_set_data_reg(emul, frame->mag_z, &(data->fifo[i]), 0); - i += 2; - bmi_emul_set_data_reg(emul, frame->rhall, &(data->fifo[i]), 0); - i += 2; - } - - if (frame->type & BMI_EMUL_FRAME_GYR) { - bmi_emul_set_data_reg(emul, frame->gyr_x, &(data->fifo[i]), - gyr_shift); - i += 2; - bmi_emul_set_data_reg(emul, frame->gyr_y, &(data->fifo[i]), - gyr_shift); - i += 2; - bmi_emul_set_data_reg(emul, frame->gyr_z, &(data->fifo[i]), - gyr_shift); - i += 2; - } - - if (frame->type & BMI_EMUL_FRAME_ACC) { - bmi_emul_set_data_reg(emul, frame->acc_x, &(data->fifo[i]), - acc_shift); - i += 2; - bmi_emul_set_data_reg(emul, frame->acc_y, &(data->fifo[i]), - acc_shift); - i += 2; - bmi_emul_set_data_reg(emul, frame->acc_z, &(data->fifo[i]), - acc_shift); - i += 2; - } -} - -/** - * @brief Update internal sensors offset values using values from emulated - * registers. - * - * @param emul Pointer to BMI emulator - */ -static void bmi_emul_updata_int_off(struct i2c_emul *emul) -{ - struct bmi_emul_data *data; - uint16_t gyr_nvm; - uint8_t gyr98; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - data->off_acc_x = bmi_emul_acc_nvm_to_off( - data->reg[data->type_data->acc_off_reg]); - data->off_acc_y = bmi_emul_acc_nvm_to_off( - data->reg[data->type_data->acc_off_reg + 1]); - data->off_acc_z = bmi_emul_acc_nvm_to_off( - data->reg[data->type_data->acc_off_reg + 2]); - - gyr98 = data->reg[data->type_data->gyr98_off_reg]; - - gyr_nvm = data->reg[data->type_data->gyr_off_reg]; - gyr_nvm |= (gyr98 & 0x3) << 8; - data->off_gyr_x = bmi_emul_gyr_nvm_to_off(gyr_nvm); - gyr_nvm = data->reg[data->type_data->gyr_off_reg + 1]; - gyr_nvm |= (gyr98 & 0xc) << 6; - data->off_gyr_y = bmi_emul_gyr_nvm_to_off(gyr_nvm); - gyr_nvm = data->reg[data->type_data->gyr_off_reg + 2]; - gyr_nvm |= (gyr98 & 0x30) << 4; - data->off_gyr_z = bmi_emul_gyr_nvm_to_off(gyr_nvm); -} - -/** - * @brief Restore registers backed in NVM to emulator's registers. Each model - * of BMI may have different set of NVM backed registers. - * - * @param emul Pointer to BMI emulator - */ -static void bmi_emul_restore_nvm(struct i2c_emul *emul) -{ - struct bmi_emul_data *data; - int i; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - ASSERT(data->type_data->nvm_len <= BMI_EMUL_MAX_NVM_REGS); - - /* Restore registers values */ - for (i = 0; i < data->type_data->nvm_len; i++) { - data->reg[data->type_data->nvm_reg[i]] = data->nvm[i]; - } - - bmi_emul_updata_int_off(emul); -} - -/** Check description in emul_bmi.h */ -void bmi_emul_flush_fifo(struct i2c_emul *emul, bool tag_time, bool header) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - data->fifo_skip = 0; - data->fifo_frame = NULL; - /* - * Gyroscope and accelerometer shift (last two arguments) - * are not important for NULL (empty) FIFO frame. - */ - bmi_emul_set_current_frame(emul, NULL, tag_time, header, 0, 0); -} - -/** Check description in emul_bmi.h */ -void bmi_emul_reset_common(struct i2c_emul *emul, bool tag_time, bool header) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - /* Restore registers backed in NVM */ - bmi_emul_restore_nvm(emul); - - /* Flush FIFO */ - bmi_emul_flush_fifo(emul, tag_time, header); - - /* Reset sensor timer */ - data->zero_time = bmi_emul_get_sensortime(); -} - -/** Check description in emul_bmi.h */ -void bmi_emul_set_cmd_end_time(struct i2c_emul *emul, int time) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - data->cmd_end_time = k_uptime_get_32() + time; -} - -/** Check description in emul_bmi.h */ -bool bmi_emul_is_cmd_end(struct i2c_emul *emul) -{ - struct bmi_emul_data *data; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - /* We are simulating command execution time and it doesn't expired */ - if (data->simulate_command_exec_time && - data->cmd_end_time > k_uptime_get_32()) { - return false; - } - - return true; -} - -/** - * @brief Handle I2C write message. BMI model specific write function is called. - * It is checked if accessed register isn't RO and reserved bits are set - * to 0. Write set value of reg field of bmi emulator data ignoring - * reserved bits. If required internal sensor offset values are updated. - * - * @param emul Pointer to BMI emulator - * @param reg Register which is written - * @param val Value being written to @p reg - * @param byte Number of handled bytes in this write command - * - * @return 0 on success - * @return -EIO on error - */ -static int bmi_emul_handle_write(struct i2c_emul *emul, int reg, uint8_t val, - int byte) -{ - struct bmi_emul_data *data; - uint8_t rsvd_mask; - int ret; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - ret = data->type_data->handle_write(data->reg, emul, reg, byte, val); - reg = data->type_data->access_reg(emul, reg, byte, false /* = read */); - if (ret != 0) { - if (ret == BMI_EMUL_ACCESS_E) { - if (!data->error_on_ro_write) { - return 0; - } - LOG_ERR("Writing to reg 0x%x which is RO", reg); - } - - return -EIO; - } - - rsvd_mask = data->type_data->rsvd_mask[reg]; - - if (data->error_on_rsvd_write && rsvd_mask & val) { - LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x", - val, reg, rsvd_mask); - return -EIO; - } - - /* Ignore all reserved bits */ - val &= ~rsvd_mask; - val |= data->reg[reg] & rsvd_mask; - - data->reg[reg] = val; - - if ((reg >= data->type_data->acc_off_reg && - reg <= data->type_data->acc_off_reg + 2) || - (reg >= data->type_data->gyr_off_reg && - reg <= data->type_data->gyr_off_reg + 2) || - reg == data->type_data->gyr98_off_reg) { - /* - * Internal offset value should be updated to new value of - * offset registers - */ - bmi_emul_updata_int_off(emul); - } - - return 0; -} - -/** Check description in emul_bmi.h */ -void bmi_emul_state_to_reg(struct i2c_emul *emul, int acc_shift, - int gyr_shift, int acc_reg, int gyr_reg, - int sensortime_reg, bool acc_off_en, - bool gyr_off_en) -{ - struct bmi_emul_data *data; - int32_t val[3]; - int i; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - if (gyr_off_en) { - val[0] = data->gyr_x - data->off_gyr_x; - val[1] = data->gyr_y - data->off_gyr_y; - val[2] = data->gyr_z - data->off_gyr_z; - } else { - val[0] = data->gyr_x; - val[1] = data->gyr_y; - val[2] = data->gyr_z; - } - - for (i = 0; i < 3; i++) { - bmi_emul_set_data_reg(emul, val[i], - &(data->reg[gyr_reg + i * 2]), gyr_shift); - } - - if (acc_off_en) { - val[0] = data->acc_x - data->off_acc_x; - val[1] = data->acc_y - data->off_acc_y; - val[2] = data->acc_z - data->off_acc_z; - } else { - val[0] = data->acc_x; - val[1] = data->acc_y; - val[2] = data->acc_z; - } - - for (i = 0; i < 3; i++) { - bmi_emul_set_data_reg(emul, val[i], - &(data->reg[acc_reg + i * 2]), acc_shift); - } - - bmi_emul_set_sensortime_reg(emul, &(data->reg[sensortime_reg])); -} - -/** Check description in emul_bmi.h */ -void bmi_emul_append_frame(struct i2c_emul *emul, struct bmi_emul_frame *frame) -{ - struct bmi_emul_data *data; - struct bmi_emul_frame *tmp_frame; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - if (data->fifo_frame == NULL) { - data->fifo_frame = frame; - } else { - tmp_frame = data->fifo_frame; - while (tmp_frame->next != NULL) { - tmp_frame = tmp_frame->next; - } - tmp_frame->next = frame; - } -} - -/** Check description in emul_bmi.h */ -uint16_t bmi_emul_fifo_len(struct i2c_emul *emul, bool tag_time, bool header) -{ - struct bmi_emul_frame *frame; - struct bmi_emul_data *data; - uint16_t len = 0; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - if (data->fifo_skip != 0 && header) { - len += 2; - } - - frame = data->fifo_frame; - while (frame != NULL) { - len += bmi_emul_get_frame_len(emul, frame, tag_time, header); - frame = frame->next; - } - - len += bmi_emul_get_frame_len(emul, NULL, tag_time, header); - /* Do not count last empty frame byte */ - len--; - - return len; -} - -/** Check description in emul_bmi.h */ -uint8_t bmi_emul_get_fifo_data(struct i2c_emul *emul, int byte, - bool tag_time, bool header, int acc_shift, - int gyr_shift) -{ - struct bmi_emul_data *data; - int ret; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - if (byte == 0) { - /* Repeat uncompleated read of frame */ - bmi_emul_set_current_frame(emul, data->fifo_frame, tag_time, - header, acc_shift, gyr_shift); - - /* Return header for skip frame */ - if (data->fifo_skip != 0 && header) { - return BMI_EMUL_FIFO_HEAD_SKIP; - } - } - - if (data->fifo_skip != 0 && byte == 1 && header) { - /* Return number of skipped frames */ - ret = data->fifo_skip; - data->fifo_skip = 0; - - return ret; - } - - /* Get next valid frame */ - while (data->fifo_frame_byte >= data->fifo_frame_len) { - /* No data */ - if (data->fifo_frame == NULL) { - return 0; - } - data->fifo_frame = data->fifo_frame->next; - bmi_emul_set_current_frame(emul, data->fifo_frame, tag_time, - header, acc_shift, gyr_shift); - } - - return data->fifo[data->fifo_frame_byte++]; -} - -/** - * @brief Handle I2C read message. BMI model specific read function is called. - * It is checked if accessed register isn't WO. - * - * @param emul Pointer to BMI emulator - * @param reg Register address to read - * @param buf Pointer where result should be stored - * @param byte Byte which is accessed during block read - * - * @return 0 on success - * @return -EIO on error - */ -static int bmi_emul_handle_read(struct i2c_emul *emul, int reg, uint8_t *buf, - int byte) -{ - struct bmi_emul_data *data; - int ret; - - data = BMI_DATA_FROM_I2C_EMUL(emul); - - ret = data->type_data->handle_read(data->reg, emul, reg, byte, buf); - reg = data->type_data->access_reg(emul, reg, byte, true /* = read */); - if (ret == BMI_EMUL_ACCESS_E && data->error_on_wo_read) { - LOG_ERR("Reading reg 0x%x which is WO", reg); - } else if (ret != 0) { - return ret; - } - - return 0; -} - -/* Device instantiation */ - -static struct i2c_emul_api bmi_emul_api = { - .transfer = i2c_common_emul_transfer, -}; - -/** - * @brief Set up a new BMI emulator - * - * This should be called for each BMI device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int bmi_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = cfg->data; - struct bmi_emul_data *bmi_data; - int ret; - - data->emul.api = &bmi_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - bmi_data = CONTAINER_OF(data, struct bmi_emul_data, common); - - switch (bmi_data->type) { - case BMI_EMUL_160: - bmi_data->type_data = get_bmi160_emul_type_data(); - break; - case BMI_EMUL_260: - bmi_data->type_data = get_bmi260_emul_type_data(); - break; - } - - /* Set callback access_reg to type specific function */ - data->access_reg = bmi_data->type_data->access_reg; - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - bmi_data->type_data->reset(bmi_data->reg, &data->emul); - - return ret; -} - -#define BMI_EMUL(n) \ - static struct bmi_emul_data bmi_emul_data_##n = { \ - .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\ - .error_on_wo_read = DT_INST_PROP(n, error_on_wo_read), \ - .error_on_rsvd_write = DT_INST_PROP(n, \ - error_on_reserved_bit_write), \ - .simulate_command_exec_time = DT_INST_PROP(n, \ - simulate_command_exec_time), \ - .type = DT_STRING_TOKEN(DT_DRV_INST(n), device_model), \ - .common = { \ - .start_write = NULL, \ - .write_byte = bmi_emul_handle_write, \ - .finish_write = NULL, \ - .start_read = NULL, \ - .read_byte = bmi_emul_handle_read, \ - .finish_read = NULL, \ - .access_reg = NULL, \ - }, \ - }; \ - \ - static const struct i2c_common_emul_cfg bmi_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &bmi_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(bmi_emul_init, DT_DRV_INST(n), &bmi_emul_cfg_##n, \ - &bmi_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(BMI_EMUL) - -#define BMI_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &bmi_emul_data_##n.common.emul; - -/** Check description in emul_bmi.h */ -struct i2c_emul *bmi_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(BMI_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_bmi160.c b/zephyr/emul/emul_bmi160.c deleted file mode 100644 index 2a68b688ff..0000000000 --- a/zephyr/emul/emul_bmi160.c +++ /dev/null @@ -1,770 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_bmi - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_bmi160); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_bmi.h" - -#include "driver/accelgyro_bmi160.h" -#include "driver/accelgyro_bmi_common.h" - -/** Mask reserved bits in each register of BMI160 */ -static const uint8_t bmi_emul_160_rsvd_mask[] = { - [BMI160_CHIP_ID] = 0x00, - [0x01] = 0xff, /* Reserved */ - [BMI160_ERR_REG] = 0x00, - [BMI160_PMU_STATUS] = 0xc0, - [BMI160_MAG_X_L_G] = 0x00, - [BMI160_MAG_X_H_G] = 0x00, - [BMI160_MAG_Y_L_G] = 0x00, - [BMI160_MAG_Y_H_G] = 0x00, - [BMI160_MAG_Z_L_G] = 0x00, - [BMI160_MAG_Z_H_G] = 0x00, - [BMI160_RHALL_L_G] = 0x00, - [BMI160_RHALL_H_G] = 0x00, - [BMI160_GYR_X_L_G] = 0x00, - [BMI160_GYR_X_H_G] = 0x00, - [BMI160_GYR_Y_L_G] = 0x00, - [BMI160_GYR_Y_H_G] = 0x00, - [BMI160_GYR_Z_L_G] = 0x00, - [BMI160_GYR_Z_H_G] = 0x00, - [BMI160_ACC_X_L_G] = 0x00, - [BMI160_ACC_X_H_G] = 0x00, - [BMI160_ACC_Y_L_G] = 0x00, - [BMI160_ACC_Y_H_G] = 0x00, - [BMI160_ACC_Z_L_G] = 0x00, - [BMI160_ACC_Z_H_G] = 0x00, - [BMI160_SENSORTIME_0] = 0x00, - [BMI160_SENSORTIME_1] = 0x00, - [BMI160_SENSORTIME_2] = 0x00, - [BMI160_STATUS] = 0x01, - [BMI160_INT_STATUS_0] = 0x00, - [BMI160_INT_STATUS_1] = 0x03, - [BMI160_INT_STATUS_2] = 0x00, - [BMI160_INT_STATUS_3] = 0x00, - [BMI160_TEMPERATURE_0] = 0x00, - [BMI160_TEMPERATURE_1] = 0x00, - [BMI160_FIFO_LENGTH_0] = 0x00, - [BMI160_FIFO_LENGTH_1] = 0xf8, - [BMI160_FIFO_DATA] = 0x00, - [0x25 ... 0x3f] = 0xff, /* Reserved */ - [BMI160_ACC_CONF] = 0x00, - [BMI160_ACC_RANGE] = 0xf0, - [BMI160_GYR_CONF] = 0xc0, - [BMI160_GYR_RANGE] = 0xf8, - [BMI160_MAG_CONF] = 0xf0, - [BMI160_FIFO_DOWNS] = 0x00, - [BMI160_FIFO_CONFIG_0] = 0x00, - [BMI160_FIFO_CONFIG_1] = 0x01, - [0x48 ... 0x4a] = 0xff, /* Reserved */ - [BMI160_MAG_IF_0] = 0x01, - [BMI160_MAG_IF_1] = 0x40, - [BMI160_MAG_IF_2] = 0x00, - [BMI160_MAG_IF_3] = 0x00, - [BMI160_MAG_IF_4] = 0x00, - [BMI160_INT_EN_0] = 0x08, - [BMI160_INT_EN_1] = 0x80, - [BMI160_INT_EN_2] = 0xf0, - [BMI160_INT_OUT_CTRL] = 0x00, - [BMI160_INT_LATCH] = 0xc0, - [BMI160_INT_MAP_0] = 0x00, - [BMI160_INT_MAP_1] = 0x00, - [BMI160_INT_MAP_2] = 0x00, - [BMI160_INT_DATA_0] = 0x77, - [BMI160_INT_DATA_1] = 0x7f, - [BMI160_INT_LOW_HIGH_0] = 0x00, - [BMI160_INT_LOW_HIGH_1] = 0x00, - [BMI160_INT_LOW_HIGH_2] = 0x3c, - [BMI160_INT_LOW_HIGH_3] = 0x00, - [BMI160_INT_LOW_HIGH_4] = 0x00, - [BMI160_INT_MOTION_0] = 0x00, - [BMI160_INT_MOTION_1] = 0x00, - [BMI160_INT_MOTION_2] = 0x00, - [BMI160_INT_MOTION_3] = 0xc0, - [BMI160_INT_TAP_0] = 0x38, - [BMI160_INT_TAP_1] = 0xe0, - [BMI160_INT_ORIENT_0] = 0x00, - [BMI160_INT_ORIENT_1] = 0x00, - [BMI160_INT_FLAT_0] = 0xc0, - [BMI160_INT_FLAT_1] = 0xc8, - [BMI160_FOC_CONF] = 0x80, - [BMI160_CONF] = 0xfd, - [BMI160_IF_CONF] = 0xce, - [BMI160_PMU_TRIGGER] = 0x80, - [BMI160_SELF_TEST] = 0xe0, - [0x6e] = 0xff, /* Reserved */ - [0x6f] = 0xff, /* Reserved */ - [BMI160_NV_CONF] = 0xf0, - [BMI160_OFFSET_ACC70] = 0x00, - [BMI160_OFFSET_ACC70 + 1] = 0x00, - [BMI160_OFFSET_ACC70 + 2] = 0x00, - [BMI160_OFFSET_GYR70] = 0x00, - [BMI160_OFFSET_GYR70 + 1] = 0x00, - [BMI160_OFFSET_GYR70 + 2] = 0x00, - [BMI160_OFFSET_EN_GYR98] = 0x00, - [BMI160_STEP_CNT_0] = 0x00, - [BMI160_STEP_CNT_1] = 0x00, - [BMI160_STEP_CONF_0] = 0x00, - [BMI160_STEP_CONF_1] = 0xf0, - [0x7c] = 0xff, /* Reserved */ - [0x7d] = 0xff, /* Reserved */ - [BMI160_CMD_REG] = 0x00, -}; - -/** - * @brief Convert range in format of ACC_RANGE register to number of bits - * that should be shifted right to obtain 16 bit reported accelerometer - * value from internal 32 bit value - * - * @param range Value of ACC_RANGE register - * - * @return shift Number of LSB that should be ignored from internal - * accelerometer value - */ -static int bmi160_emul_acc_range_to_shift(uint8_t range) -{ - switch (range & 0xf) { - case BMI160_GSEL_2G: - return 0; - case BMI160_GSEL_4G: - return 1; - case BMI160_GSEL_8G: - return 2; - case BMI160_GSEL_16G: - return 3; - default: - return 0; - } -} - -/** - * @brief Convert range in format of GYR_RANGE register to number of bits - * that should be shifted right to obtain 16 bit reported gyroscope - * value from internal 32 bit value - * - * @param range Value of GYR_RANGE register - * - * @return shift Number of LSB that should be ignored from internal - * gyroscope value - */ -static int bmi160_emul_gyr_range_to_shift(uint8_t range) -{ - switch (range & 0x7) { - case BMI160_DPS_SEL_2000: - return 4; - case BMI160_DPS_SEL_1000: - return 3; - case BMI160_DPS_SEL_500: - return 2; - case BMI160_DPS_SEL_250: - return 1; - case BMI160_DPS_SEL_125: - return 0; - default: - return 0; - } -} - -/** - * @brief Reset registers to default values and restore registers backed by NVM - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - */ -static void bmi160_emul_reset(uint8_t *regs, struct i2c_emul *emul) -{ - bool tag_time; - bool header; - - regs[BMI160_CHIP_ID] = 0xd1; - regs[BMI160_ERR_REG] = 0x00; - regs[BMI160_PMU_STATUS] = 0x00; - regs[BMI160_MAG_X_L_G] = 0x00; - regs[BMI160_MAG_X_H_G] = 0x00; - regs[BMI160_MAG_Y_L_G] = 0x00; - regs[BMI160_MAG_Y_H_G] = 0x00; - regs[BMI160_MAG_Z_L_G] = 0x00; - regs[BMI160_MAG_Z_H_G] = 0x00; - regs[BMI160_RHALL_L_G] = 0x00; - regs[BMI160_RHALL_H_G] = 0x00; - regs[BMI160_GYR_X_L_G] = 0x00; - regs[BMI160_GYR_X_H_G] = 0x00; - regs[BMI160_GYR_Y_L_G] = 0x00; - regs[BMI160_GYR_Y_H_G] = 0x00; - regs[BMI160_GYR_Z_L_G] = 0x00; - regs[BMI160_GYR_Z_H_G] = 0x00; - regs[BMI160_ACC_X_L_G] = 0x00; - regs[BMI160_ACC_X_H_G] = 0x00; - regs[BMI160_ACC_Y_L_G] = 0x00; - regs[BMI160_ACC_Y_H_G] = 0x00; - regs[BMI160_ACC_Z_L_G] = 0x00; - regs[BMI160_ACC_Z_H_G] = 0x00; - regs[BMI160_SENSORTIME_0] = 0x00; - regs[BMI160_SENSORTIME_1] = 0x00; - regs[BMI160_SENSORTIME_2] = 0x00; - regs[BMI160_STATUS] = 0x01; - regs[BMI160_INT_STATUS_0] = 0x00; - regs[BMI160_INT_STATUS_1] = 0x00; - regs[BMI160_INT_STATUS_2] = 0x00; - regs[BMI160_INT_STATUS_3] = 0x00; - regs[BMI160_TEMPERATURE_0] = 0x00; - regs[BMI160_TEMPERATURE_1] = 0x00; - regs[BMI160_FIFO_LENGTH_0] = 0x00; - regs[BMI160_FIFO_LENGTH_1] = 0x00; - regs[BMI160_FIFO_DATA] = 0x00; - regs[BMI160_ACC_CONF] = 0x28; - regs[BMI160_ACC_RANGE] = 0x03; - regs[BMI160_GYR_CONF] = 0x28; - regs[BMI160_GYR_RANGE] = 0x00; - regs[BMI160_MAG_CONF] = 0x0b; - regs[BMI160_FIFO_DOWNS] = 0x88; - regs[BMI160_FIFO_CONFIG_0] = 0x80; - regs[BMI160_FIFO_CONFIG_1] = 0x10; - regs[BMI160_MAG_IF_0] = 0x20; - regs[BMI160_MAG_IF_1] = 0x80; - regs[BMI160_MAG_IF_2] = 0x42; - regs[BMI160_MAG_IF_3] = 0x4c; - regs[BMI160_MAG_IF_4] = 0x00; - regs[BMI160_INT_EN_0] = 0x00; - regs[BMI160_INT_EN_1] = 0x00; - regs[BMI160_INT_EN_2] = 0x00; - regs[BMI160_INT_OUT_CTRL] = 0x00; - regs[BMI160_INT_LATCH] = 0x00; - regs[BMI160_INT_MAP_0] = 0x00; - regs[BMI160_INT_MAP_1] = 0x00; - regs[BMI160_INT_MAP_2] = 0x00; - regs[BMI160_INT_DATA_0] = 0x00; - regs[BMI160_INT_DATA_1] = 0x00; - regs[BMI160_INT_LOW_HIGH_0] = 0x07; - regs[BMI160_INT_LOW_HIGH_1] = 0x30; - regs[BMI160_INT_LOW_HIGH_2] = 0x81; - regs[BMI160_INT_LOW_HIGH_3] = 0xdb; - regs[BMI160_INT_LOW_HIGH_4] = 0xc0; - regs[BMI160_INT_MOTION_0] = 0x00; - regs[BMI160_INT_MOTION_1] = 0x14; - regs[BMI160_INT_MOTION_2] = 0x14; - regs[BMI160_INT_MOTION_3] = 0x24; - regs[BMI160_INT_TAP_0] = 0x04; - regs[BMI160_INT_TAP_1] = 0xda; - regs[BMI160_INT_ORIENT_0] = 0x18; - regs[BMI160_INT_ORIENT_1] = 0x48; - regs[BMI160_INT_FLAT_0] = 0x08; - regs[BMI160_INT_FLAT_1] = 0x11; - regs[BMI160_FOC_CONF] = 0x00; - regs[BMI160_CONF] = 0x00; - regs[BMI160_IF_CONF] = 0x00; - regs[BMI160_PMU_TRIGGER] = 0x00; - regs[BMI160_SELF_TEST] = 0x00; - regs[BMI160_STEP_CNT_0] = 0x00; - regs[BMI160_STEP_CNT_1] = 0x00; - regs[BMI160_STEP_CONF_0] = 0x00; - regs[BMI160_STEP_CONF_1] = 0x15; - regs[BMI160_CMD_REG] = 0x03; - - /* Call generic reset */ - tag_time = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_TAG_TIME_EN; - header = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_HEADER_EN; - bmi_emul_reset_common(emul, tag_time, header); -} - -/** - * @brief Clear all interrupt registers - * - * @param regs Pointer to array of emulator's registers - */ -static void bmi160_emul_clear_int(uint8_t *regs) -{ - regs[BMI160_INT_STATUS_0] = 0x00; - regs[BMI160_INT_STATUS_1] = 0x00; - regs[BMI160_INT_STATUS_2] = 0x00; - regs[BMI160_INT_STATUS_3] = 0x00; -} - -/** - * @brief Get offset value for given gyroscope value. If gyroscope value is - * above maximum (belowe minimum), then minimum -31,25°/s - * (maximum 31,25°/s) offset value is returned. - * - * @param gyr Gyroscope value - */ -static int16_t bmi160_emul_get_gyr_target_off(int32_t gyr) -{ - if (gyr > (int32_t)BMI_EMUL_125_DEG_S / 4) { - return -((int32_t)BMI_EMUL_125_DEG_S / 4); - } - - if (gyr < -((int32_t)BMI_EMUL_125_DEG_S / 4)) { - return BMI_EMUL_125_DEG_S / 4; - } - - return -gyr; -} - -/** - * @brief Get offset value for given accelerometer value. If accelerometer - * value - target is above maximum (belowe minimum), then minimum -0.5g - * (maximum 0.5g) offset value is returned. - * - * @param acc Accelerometer value - * @param target Target value in FOC configuration register format - */ -static int16_t bmi160_emul_get_acc_target_off(int32_t acc, uint8_t target) -{ - switch (target) { - case BMI160_FOC_ACC_PLUS_1G: - acc -= BMI_EMUL_1G; - break; - case BMI160_FOC_ACC_MINUS_1G: - acc += BMI_EMUL_1G; - break; - } - - if (acc > (int32_t)BMI_EMUL_1G / 2) { - return -((int32_t)BMI_EMUL_1G / 2); - } - - if (acc < -((int32_t)BMI_EMUL_1G / 2)) { - return BMI_EMUL_1G / 2; - } - - return -acc; -} - -/** - * @brief Handle fast offset compensation. Check FOC configuration register - * and sets gyroscope and/or accelerometer offset using current emulator - * state. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - */ -static void bmi160_emul_handle_off_comp(uint8_t *regs, struct i2c_emul *emul) -{ - uint8_t target; - int16_t off; - int32_t val; - - if (regs[BMI160_FOC_CONF] & BMI160_FOC_GYRO_EN) { - val = bmi_emul_get_value(emul, BMI_EMUL_GYR_X); - off = bmi160_emul_get_gyr_target_off(val); - bmi_emul_set_off(emul, BMI_EMUL_GYR_X, off); - val = bmi_emul_get_value(emul, BMI_EMUL_GYR_Y); - off = bmi160_emul_get_gyr_target_off(val); - bmi_emul_set_off(emul, BMI_EMUL_GYR_Y, off); - val = bmi_emul_get_value(emul, BMI_EMUL_GYR_Z); - off = bmi160_emul_get_gyr_target_off(val); - bmi_emul_set_off(emul, BMI_EMUL_GYR_Z, off); - } - - target = (regs[BMI160_FOC_CONF] >> BMI160_FOC_ACC_X_OFFSET) & 0x3; - if (target) { - val = bmi_emul_get_value(emul, BMI_EMUL_ACC_X); - off = bmi160_emul_get_acc_target_off(val, target); - bmi_emul_set_off(emul, BMI_EMUL_ACC_X, off); - } - - target = (regs[BMI160_FOC_CONF] >> BMI160_FOC_ACC_Y_OFFSET) & 0x3; - if (target) { - val = bmi_emul_get_value(emul, BMI_EMUL_ACC_Y); - off = bmi160_emul_get_acc_target_off(val, target); - bmi_emul_set_off(emul, BMI_EMUL_ACC_Y, off); - } - - target = (regs[BMI160_FOC_CONF] >> BMI160_FOC_ACC_Z_OFFSET) & 0x3; - if (target) { - val = bmi_emul_get_value(emul, BMI_EMUL_ACC_Z); - off = bmi160_emul_get_acc_target_off(val, target); - bmi_emul_set_off(emul, BMI_EMUL_ACC_Z, off); - } -} - -/** - * @brief Execute first part of command. Emulate state of device which is - * during handling command (status bits etc). This function save time - * on which command should end. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param cmd Command that is starting - * - * @return 0 on success - * @return -EIO on failure - */ -static int bmi160_emul_start_cmd(uint8_t *regs, struct i2c_emul *emul, int cmd) -{ - int time; - - switch (cmd) { - case BMI160_CMD_SOFT_RESET: - time = 1; - break; - case BMI160_CMD_START_FOC: - if ((regs[BMI160_FOC_CONF] & BMI160_FOC_GYRO_EN) && - ((regs[BMI160_PMU_STATUS] & - (0x3 << BMI160_PMU_GYR_OFFSET)) != - BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET)) { - LOG_ERR("Starting gyroscope FOC in low power mode"); - return -EIO; - } - - if ((regs[BMI160_FOC_CONF] & ~BMI160_FOC_GYRO_EN) && - ((regs[BMI160_PMU_STATUS] & - (0x3 << BMI160_PMU_ACC_OFFSET)) != - BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET)) { - LOG_ERR("Starting accelerometer FOC in low power mode"); - return -EIO; - } - - regs[BMI160_STATUS] &= ~BMI160_FOC_RDY; - time = 250; - break; - case BMI160_CMD_ACC_MODE_SUSP: - case BMI160_CMD_GYR_MODE_SUSP: - case BMI160_CMD_MAG_MODE_SUSP: - time = 0; - break; - /* Real hardware probably switch faster if not in suspend mode */ - case BMI160_CMD_ACC_MODE_NORMAL: - case BMI160_CMD_ACC_MODE_LOWPOWER: - time = 4; - break; - case BMI160_CMD_GYR_MODE_NORMAL: - case BMI160_CMD_GYR_MODE_FAST_STARTUP: - time = 80; - break; - case BMI160_CMD_MAG_MODE_NORMAL: - case BMI160_CMD_MAG_MODE_LOWPOWER: - time = 1; - break; - case BMI160_CMD_FIFO_FLUSH: - time = 0; - break; - case BMI160_CMD_INT_RESET: - time = 0; - break; - default: - LOG_ERR("Unknown command 0x%x", cmd); - return -EIO; - } - - regs[BMI160_CMD_REG] = cmd; - bmi_emul_set_cmd_end_time(emul, time); - - return 0; -} - -/** - * @brief Emulate end of ongoing command. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - */ -static void bmi160_emul_end_cmd(uint8_t *regs, struct i2c_emul *emul) -{ - uint8_t pmu_status; - bool tag_time; - bool header; - int cmd; - - pmu_status = regs[BMI160_PMU_STATUS]; - cmd = regs[BMI160_CMD_REG]; - regs[BMI160_CMD_REG] = BMI160_CMD_NOOP; - tag_time = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_TAG_TIME_EN; - header = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_HEADER_EN; - - switch (cmd) { - case BMI160_CMD_SOFT_RESET: - bmi160_emul_reset(regs, emul); - break; - case BMI160_CMD_START_FOC: - bmi160_emul_handle_off_comp(regs, emul); - regs[BMI160_STATUS] |= BMI160_FOC_RDY; - break; - case BMI160_CMD_ACC_MODE_SUSP: - pmu_status &= ~(0x3 << BMI160_PMU_ACC_OFFSET); - pmu_status |= BMI160_PMU_SUSPEND << BMI160_PMU_ACC_OFFSET; - break; - case BMI160_CMD_ACC_MODE_NORMAL: - pmu_status &= ~(0x3 << BMI160_PMU_ACC_OFFSET); - pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_ACC_OFFSET; - break; - case BMI160_CMD_ACC_MODE_LOWPOWER: - pmu_status &= ~(0x3 << BMI160_PMU_ACC_OFFSET); - pmu_status |= BMI160_PMU_LOW_POWER << BMI160_PMU_ACC_OFFSET; - break; - case BMI160_CMD_GYR_MODE_SUSP: - pmu_status &= ~(0x3 << BMI160_PMU_GYR_OFFSET); - pmu_status |= BMI160_PMU_SUSPEND << BMI160_PMU_GYR_OFFSET; - break; - case BMI160_CMD_GYR_MODE_NORMAL: - pmu_status &= ~(0x3 << BMI160_PMU_GYR_OFFSET); - pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_GYR_OFFSET; - break; - case BMI160_CMD_GYR_MODE_FAST_STARTUP: - pmu_status &= ~(0x3 << BMI160_PMU_GYR_OFFSET); - pmu_status |= BMI160_PMU_FAST_STARTUP << BMI160_PMU_GYR_OFFSET; - break; - case BMI160_CMD_MAG_MODE_SUSP: - pmu_status &= ~(0x3 << BMI160_PMU_MAG_OFFSET); - pmu_status |= BMI160_PMU_SUSPEND << BMI160_PMU_MAG_OFFSET; - break; - case BMI160_CMD_MAG_MODE_NORMAL: - pmu_status &= ~(0x3 << BMI160_PMU_MAG_OFFSET); - pmu_status |= BMI160_PMU_NORMAL << BMI160_PMU_MAG_OFFSET; - break; - case BMI160_CMD_MAG_MODE_LOWPOWER: - pmu_status &= ~(0x3 << BMI160_PMU_MAG_OFFSET); - pmu_status |= BMI160_PMU_LOW_POWER << BMI160_PMU_MAG_OFFSET; - break; - case BMI160_CMD_FIFO_FLUSH: - bmi_emul_flush_fifo(emul, tag_time, header); - break; - case BMI160_CMD_INT_RESET: - bmi160_emul_clear_int(regs); - break; - } - - /* Clear FIFO on sensor on/off in headerless mode */ - if (pmu_status != regs[BMI160_PMU_STATUS] && !header) { - bmi_emul_flush_fifo(emul, tag_time, header); - } - - regs[BMI160_PMU_STATUS] = pmu_status; -} - -/** - * @brief BMI160 specific write function. It doesn't handle block writes. - * Check if read only register is not accessed. Before writing value, - * ongoing command is finished if possible. Write to CMD register is - * handled by BMI160 specific function. On changing of FIFO - * header/headerless mode, FIFO is flushed. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param reg Register address that is accessed - * @param byte Number of handled bytes in this write command - * @param val Value that is being written - * - * @return 0 on success - * @return BMI_EMUL_ACCESS_E on RO register access - * @return -EIO on error - */ -static int bmi160_emul_handle_write(uint8_t *regs, struct i2c_emul *emul, - int reg, int byte, uint8_t val) -{ - bool tag_time; - bool header; - - if (byte > 1) { - LOG_ERR("Block writes are not allowed"); - return -EIO; - } - - if (reg <= BMI160_FIFO_DATA || - (reg >= BMI160_STEP_CNT_0 && reg <= BMI160_STEP_CNT_1)) { - return BMI_EMUL_ACCESS_E; - } - - /* Stop on going command if required */ - if (regs[BMI160_CMD_REG] != BMI160_CMD_NOOP && - bmi_emul_is_cmd_end(emul)) { - bmi160_emul_end_cmd(regs, emul); - } - - switch (reg) { - case BMI160_CMD_REG: - if (regs[BMI160_CMD_REG] != BMI160_CMD_NOOP) { - LOG_ERR("Issued command before previous end"); - return -EIO; - } - - return bmi160_emul_start_cmd(regs, emul, val); - case BMI160_FIFO_CONFIG_1: - tag_time = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_TAG_TIME_EN; - header = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_HEADER_EN; - /* - * Clear FIFO on transition between headerless and - * header mode - */ - if (!!(val & BMI160_FIFO_HEADER_EN) != header) { - bmi_emul_flush_fifo(emul, tag_time, header); - } - break; - } - - return 0; -} - -/** - * @brief Get currently accessed register. It is first register plus number of - * handled bytes for all registers except BMI160_FIFO_DATA for which - * address incrementation is disabled. - * - * @param emul Pointer to BMI emulator - * @param reg First byte of last write message - * @param bytes Number of bytes already handled from current message - * @param read If currently handled is read message - * - * @return Currently accessed register - */ -static int bmi160_emul_access_reg(struct i2c_emul *emul, int reg, int byte, - bool read) -{ - if (!read) { - return reg; - } - - /* - * If register is FIFO data, then read data from FIFO. - * Else block read access subsequent registers. - */ - if (reg <= BMI160_FIFO_DATA && reg + byte >= BMI160_FIFO_DATA) { - return BMI160_FIFO_DATA; - } - - return reg + byte; -} - -/** - * @brief BMI160 specific read function. It handle block reads but only if - * device is not suspended. FIFO data register is trap register, so - * after reaching it, register address is not increased on block reads. - * Before reading value, ongoing command is finished if possible. - * Read of sensor data traps current emulator state in registers. - * Read of FIFO length and FIFO data triggers default BMI functions. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param reg Register address that is accessed - * @param byte Byte which is accessed during block read - * @param buf Pointer where read byte should be stored - * - * @return 0 on success - * @return BMI_EMUL_ACCESS_E on WO register access - * @return -EIO on other error - */ -static int bmi160_emul_handle_read(uint8_t *regs, struct i2c_emul *emul, - int reg, int byte, char *buf) -{ - uint16_t fifo_len; - bool acc_off_en; - bool gyr_off_en; - bool tag_time; - bool header; - int gyr_shift; - int acc_shift; - int fifo_byte; - - /* Get number of bytes readed from FIFO */ - fifo_byte = byte - (reg - BMI160_FIFO_DATA); - - reg = bmi160_emul_access_reg(emul, reg, byte, true /* = read */); - - /* Stop on going command if required */ - if (regs[BMI160_CMD_REG] != BMI160_CMD_NOOP && - bmi_emul_is_cmd_end(emul)) { - bmi160_emul_end_cmd(regs, emul); - } - - /* Burst reads are not supported if all sensors are in suspend mode */ - if ((regs[BMI160_PMU_STATUS] & 0x3f) == 0 && byte > 0) { - LOG_ERR("Block reads are not supported in suspend mode"); - return -EIO; - } - - tag_time = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_TAG_TIME_EN; - header = regs[BMI160_FIFO_CONFIG_1] & BMI160_FIFO_HEADER_EN; - acc_off_en = regs[BMI160_OFFSET_EN_GYR98] & BMI160_OFFSET_ACC_EN; - gyr_off_en = regs[BMI160_OFFSET_EN_GYR98] & BMI160_OFFSET_GYRO_EN; - gyr_shift = bmi160_emul_gyr_range_to_shift(regs[BMI160_GYR_RANGE]); - acc_shift = bmi160_emul_acc_range_to_shift(regs[BMI160_ACC_RANGE]); - - switch (reg) { - case BMI160_GYR_X_L_G: - case BMI160_GYR_X_H_G: - case BMI160_GYR_Y_L_G: - case BMI160_GYR_Y_H_G: - case BMI160_GYR_Z_L_G: - case BMI160_GYR_Z_H_G: - case BMI160_ACC_X_L_G: - case BMI160_ACC_X_H_G: - case BMI160_ACC_Y_L_G: - case BMI160_ACC_Y_H_G: - case BMI160_ACC_Z_L_G: - case BMI160_ACC_Z_H_G: - case BMI160_SENSORTIME_0: - case BMI160_SENSORTIME_1: - case BMI160_SENSORTIME_2: - /* - * Snapshot of current emulator state is created on data read - * and shouldn't be changed until next I2C operation - */ - if (byte == 0) { - bmi_emul_state_to_reg(emul, acc_shift, gyr_shift, - BMI160_ACC_X_L_G, - BMI160_GYR_X_L_G, - BMI160_SENSORTIME_0, - acc_off_en, gyr_off_en); - } - break; - case BMI160_FIFO_LENGTH_0: - case BMI160_FIFO_LENGTH_1: - if (byte == 0) { - fifo_len = bmi_emul_fifo_len(emul, tag_time, header); - regs[BMI160_FIFO_LENGTH_0] = fifo_len & 0xff; - regs[BMI160_FIFO_LENGTH_1] = (fifo_len >> 8) & 0x7; - } - break; - case BMI160_FIFO_DATA: - regs[reg] = bmi_emul_get_fifo_data(emul, fifo_byte, tag_time, - header, acc_shift, - gyr_shift); - break; - } - - *buf = regs[reg]; - - return 0; -} - -/** Registers backed in NVM by BMI160 */ -const int bmi160_nvm_reg[] = {BMI160_NV_CONF, - BMI160_OFFSET_ACC70, - BMI160_OFFSET_ACC70 + 1, - BMI160_OFFSET_ACC70 + 2, - BMI160_OFFSET_GYR70, - BMI160_OFFSET_GYR70 + 1, - BMI160_OFFSET_GYR70 + 2, - BMI160_OFFSET_EN_GYR98}; - -/** Confguration of BMI160 */ -struct bmi_emul_type_data bmi160_emul = { - .sensortime_follow_config_frame = false, - .handle_write = bmi160_emul_handle_write, - .handle_read = bmi160_emul_handle_read, - .access_reg = bmi160_emul_access_reg, - .reset = bmi160_emul_reset, - .rsvd_mask = bmi_emul_160_rsvd_mask, - .nvm_reg = bmi160_nvm_reg, - .nvm_len = ARRAY_SIZE(bmi160_nvm_reg), - .gyr_off_reg = BMI160_OFFSET_GYR70, - .acc_off_reg = BMI160_OFFSET_ACC70, - .gyr98_off_reg = BMI160_OFFSET_EN_GYR98, -}; - -/** Check description in emul_bmi.h */ -const struct bmi_emul_type_data *get_bmi160_emul_type_data(void) -{ - return &bmi160_emul; -} diff --git a/zephyr/emul/emul_bmi260.c b/zephyr/emul/emul_bmi260.c deleted file mode 100644 index 235b1e219e..0000000000 --- a/zephyr/emul/emul_bmi260.c +++ /dev/null @@ -1,571 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_bmi - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_bmi260); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_bmi.h" - -#include "driver/accelgyro_bmi260.h" -#include "driver/accelgyro_bmi_common.h" - -/** Mask reserved bits in each register of BMI260 */ -static const uint8_t bmi_emul_260_rsvd_mask[] = { - [BMI260_CHIP_ID] = 0x00, - [0x01] = 0xff, /* Reserved */ - [BMI260_ERR_REG] = 0x20, - [BMI260_STATUS] = 0x0b, - [BMI260_AUX_X_L_G] = 0x00, - [BMI260_AUX_X_H_G] = 0x00, - [BMI260_AUX_Y_L_G] = 0x00, - [BMI260_AUX_Y_H_G] = 0x00, - [BMI260_AUX_Z_L_G] = 0x00, - [BMI260_AUX_Z_H_G] = 0x00, - [BMI260_AUX_R_L_G] = 0x00, - [BMI260_AUX_R_H_G] = 0x00, - [BMI260_ACC_X_L_G] = 0x00, - [BMI260_ACC_X_H_G] = 0x00, - [BMI260_ACC_Y_L_G] = 0x00, - [BMI260_ACC_Y_H_G] = 0x00, - [BMI260_ACC_Z_L_G] = 0x00, - [BMI260_ACC_Z_H_G] = 0x00, - [BMI260_GYR_X_L_G] = 0x00, - [BMI260_GYR_X_H_G] = 0x00, - [BMI260_GYR_Y_L_G] = 0x00, - [BMI260_GYR_Y_H_G] = 0x00, - [BMI260_GYR_Z_L_G] = 0x00, - [BMI260_GYR_Z_H_G] = 0x00, - [BMI260_SENSORTIME_0] = 0x00, - [BMI260_SENSORTIME_1] = 0x00, - [BMI260_SENSORTIME_2] = 0x00, - [BMI260_EVENT] = 0xe2, - [BMI260_INT_STATUS_0] = 0x00, - [BMI260_INT_STATUS_1] = 0x18, - [BMI260_SC_OUT_0] = 0x00, - [BMI260_SC_OUT_1] = 0x00, - [BMI260_ORIENT_ACT] = 0xe0, - [BMI260_INTERNAL_STATUS] = 0x00, - [BMI260_TEMPERATURE_0] = 0x00, - [BMI260_TEMPERATURE_1] = 0x00, - [BMI260_FIFO_LENGTH_0] = 0x00, - [BMI260_FIFO_LENGTH_1] = 0xc0, - [BMI160_FIFO_DATA] = 0x00, - [0x27 ... 0x2e] = 0xff, /* Reserved */ - [BMI260_FEAT_PAGE] = 0xf8, - [0x30 ... 0x3f] = 0x00, /* Features */ - [BMI260_ACC_CONF] = 0x00, - [BMI260_ACC_RANGE] = 0xfc, - [BMI260_GYR_CONF] = 0x00, - [BMI260_GYR_RANGE] = 0xf0, - [BMI260_AUX_CONF] = 0x00, - [BMI260_FIFO_DOWNS] = 0x00, - [BMI260_FIFO_WTM_0] = 0x00, - [BMI260_FIFO_WTM_1] = 0xe0, - [BMI260_FIFO_CONFIG_0] = 0xfc, - [BMI260_FIFO_CONFIG_1] = 0x00, - [BMI260_SATURATION] = 0xc0, - [BMI260_AUX_DEV_ID] = 0x01, - [BMI260_AUX_IF_CONF] = 0x30, - [BMI260_AUX_RD_ADDR] = 0x00, - [BMI260_AUX_WR_ADDR] = 0x00, - [BMI260_AUX_WR_DATA] = 0x00, - [0x50 ... 0x51] = 0xff, /* Reserved */ - [BMI260_ERR_REG_MSK] = 0x20, - [BMI260_INT1_IO_CTRL] = 0xe1, - [BMI260_INT2_IO_CTRL] = 0xe1, - [BMI260_INT_LATCH] = 0xfe, - [BMI260_INT1_MAP_FEAT] = 0x00, - [BMI260_INT2_MAP_FEAT] = 0x00, - [BMI260_INT_MAP_DATA] = 0x00, - [BMI260_INIT_CTRL] = 0x00, - [0x5a] = 0xff, /* Reserved */ - [BMI260_INIT_ADDR_0] = 0xf0, - [BMI260_INIT_ADDR_1] = 0x00, - [0x5d] = 0xff, /* Reserved */ - [BMI260_INIT_DATA] = 0x00, - [BMI260_INTERNAL_ERROR] = 0xe9, - [0x60 ... 0x67] = 0xff, /* Reserved */ - [BMI260_AUX_IF_TRIM] = 0xf8, - [BMI260_GYR_CRT_CONF] = 0xf2, - [BMI260_NVM_CONF] = 0xfd, - [BMI260_IF_CONF] = 0xcc, - [BMI260_DRV] = 0x00, - [BMI260_ACC_SELF_TEST] = 0xf2, - [BMI260_GYR_SELF_TEST_AXES] = 0xf0, - [0x6f] = 0xff, /* Reserved */ - [BMI260_NV_CONF] = 0xf0, - [BMI260_OFFSET_ACC70] = 0x00, - [BMI260_OFFSET_ACC70 + 1] = 0x00, - [BMI260_OFFSET_ACC70 + 2] = 0x00, - [BMI260_OFFSET_GYR70] = 0x00, - [BMI260_OFFSET_GYR70 + 1] = 0x00, - [BMI260_OFFSET_GYR70 + 2] = 0x00, - [BMI160_OFFSET_EN_GYR98] = 0x00, - [0x78 ... 0x7b] = 0xff, /* Reserved */ - [BMI260_PWR_CONF] = 0xf8, - [BMI260_PWR_CTRL] = 0xf0, - [BMI260_CMD_REG] = 0x00, -}; - -/** - * @brief Reset registers to default values and restore registers backed by NVM - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - */ -static void bmi260_emul_reset(uint8_t *regs, struct i2c_emul *emul) -{ - bool tag_time; - bool header; - - regs[BMI260_CHIP_ID] = 0x27; - regs[BMI260_ERR_REG] = 0x00; - regs[BMI260_STATUS] = 0x10; - regs[BMI260_AUX_X_L_G] = 0x00; - regs[BMI260_AUX_X_H_G] = 0x00; - regs[BMI260_AUX_Y_L_G] = 0x00; - regs[BMI260_AUX_Y_H_G] = 0x00; - regs[BMI260_AUX_Z_L_G] = 0x00; - regs[BMI260_AUX_Z_H_G] = 0x00; - regs[BMI260_AUX_R_L_G] = 0x00; - regs[BMI260_AUX_R_H_G] = 0x00; - regs[BMI260_ACC_X_L_G] = 0x00; - regs[BMI260_ACC_X_H_G] = 0x00; - regs[BMI260_ACC_Y_L_G] = 0x00; - regs[BMI260_ACC_Y_H_G] = 0x00; - regs[BMI260_ACC_Z_L_G] = 0x00; - regs[BMI260_ACC_Z_H_G] = 0x00; - regs[BMI260_GYR_X_L_G] = 0x00; - regs[BMI260_GYR_X_H_G] = 0x00; - regs[BMI260_GYR_Y_L_G] = 0x00; - regs[BMI260_GYR_Y_H_G] = 0x00; - regs[BMI260_GYR_Z_L_G] = 0x00; - regs[BMI260_GYR_Z_H_G] = 0x00; - regs[BMI260_SENSORTIME_0] = 0x00; - regs[BMI260_SENSORTIME_1] = 0x00; - regs[BMI260_SENSORTIME_2] = 0x00; - regs[BMI260_EVENT] = 0x01; - regs[BMI260_INT_STATUS_0] = 0x00; - regs[BMI260_INT_STATUS_1] = 0x00; - regs[BMI260_SC_OUT_0] = 0x00; - regs[BMI260_SC_OUT_1] = 0x00; - regs[BMI260_ORIENT_ACT] = 0x00; - regs[BMI260_INTERNAL_STATUS] = 0x00; - regs[BMI260_TEMPERATURE_0] = 0x00; - regs[BMI260_TEMPERATURE_1] = 0x80; - regs[BMI260_FIFO_LENGTH_0] = 0x00; - regs[BMI260_FIFO_LENGTH_1] = 0x00; - regs[BMI160_FIFO_DATA] = 0x00; - regs[BMI260_FEAT_PAGE] = 0x00; - regs[BMI260_ACC_CONF] = 0xa8; - regs[BMI260_ACC_RANGE] = 0x02; - regs[BMI260_GYR_CONF] = 0xa9; - regs[BMI260_GYR_RANGE] = 0x00; - regs[BMI260_AUX_CONF] = 0x46; - regs[BMI260_FIFO_DOWNS] = 0x88; - regs[BMI260_FIFO_WTM_0] = 0x00; - regs[BMI260_FIFO_WTM_1] = 0x02; - regs[BMI260_FIFO_CONFIG_0] = 0x02; - regs[BMI260_FIFO_CONFIG_1] = 0x10; - regs[BMI260_SATURATION] = 0x00; - regs[BMI260_AUX_DEV_ID] = 0x20; - regs[BMI260_AUX_IF_CONF] = 0x83; - regs[BMI260_AUX_RD_ADDR] = 0x42; - regs[BMI260_AUX_WR_ADDR] = 0x4c; - regs[BMI260_AUX_WR_DATA] = 0x02; - regs[BMI260_ERR_REG_MSK] = 0x00; - regs[BMI260_INT1_IO_CTRL] = 0x00; - regs[BMI260_INT2_IO_CTRL] = 0x00; - regs[BMI260_INT_LATCH] = 0x00; - regs[BMI260_INT1_MAP_FEAT] = 0x00; - regs[BMI260_INT2_MAP_FEAT] = 0x00; - regs[BMI260_INT_MAP_DATA] = 0x00; - regs[BMI260_INIT_CTRL] = 0x00; - regs[BMI260_INIT_ADDR_0] = 0x00; - regs[BMI260_INIT_ADDR_1] = 0x00; - regs[BMI260_INIT_DATA] = 0x00; - regs[BMI260_INTERNAL_ERROR] = 0x00; - regs[BMI260_AUX_IF_TRIM] = 0x01; - regs[BMI260_GYR_CRT_CONF] = 0x00; - regs[BMI260_NVM_CONF] = 0x00; - regs[BMI260_IF_CONF] = 0x00; - regs[BMI260_DRV] = 0xff; - regs[BMI260_ACC_SELF_TEST] = 0x00; - regs[BMI260_GYR_SELF_TEST_AXES] = 0x00; - regs[BMI260_PWR_CONF] = 0x03; - regs[BMI260_PWR_CTRL] = 0x00; - regs[BMI260_CMD_REG] = 0x00; - - /* Call generic reset */ - tag_time = regs[BMI260_FIFO_CONFIG_0] & BMI260_FIFO_TIME_EN; - header = regs[BMI260_FIFO_CONFIG_1] & BMI260_FIFO_HEADER_EN; - bmi_emul_reset_common(emul, tag_time, header); -} - -/** - * @brief Convert range in format of ACC_RANGE register to number of bits - * that should be shifted right to obtain 16 bit reported accelerometer - * value from internal 32 bit value - * - * @param range Value of ACC_RANGE register - * - * @return shift Number of LSB that should be ignored from internal - * accelerometer value - */ -static int bmi260_emul_acc_range_to_shift(uint8_t range) -{ - switch (range & 0xf) { - case BMI260_GSEL_2G: - return 0; - case BMI260_GSEL_4G: - return 1; - case BMI260_GSEL_8G: - return 2; - case BMI260_GSEL_16G: - return 3; - default: - return 0; - } -} - -/** - * @brief Convert range in format of GYR_RANGE register to number of bits - * that should be shifted right to obtain 16 bit reported gyroscope - * value from internal 32 bit value - * - * @param range Value of GYR_RANGE register - * - * @return shift Number of LSB that should be ignored from internal - * gyroscope value - */ -static int bmi260_emul_gyr_range_to_shift(uint8_t range) -{ - switch (range & 0x7) { - case BMI260_DPS_SEL_2000: - return 4; - case BMI260_DPS_SEL_1000: - return 3; - case BMI260_DPS_SEL_500: - return 2; - case BMI260_DPS_SEL_250: - return 1; - case BMI260_DPS_SEL_125: - return 0; - default: - return 0; - } -} - -/** - * @brief Execute first part of command. Emulate state of device which is - * during handling command (status bits etc). This function save time - * on which command should end. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param cmd Command that is starting - * - * @return 0 on success - * @return -EIO on failure - */ -static int bmi260_emul_start_cmd(uint8_t *regs, struct i2c_emul *emul, int cmd) -{ - int time; - - switch (cmd) { - case BMI260_CMD_SOFT_RESET: - time = 1; - break; - case BMI260_CMD_FIFO_FLUSH: - time = 0; - break; - default: - LOG_ERR("Unknown command 0x%x", cmd); - return -EIO; - } - - regs[BMI260_CMD_REG] = cmd; - bmi_emul_set_cmd_end_time(emul, time); - - return 0; -} - -/** - * @brief Emulate end of ongoing command. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - */ -static void bmi260_emul_end_cmd(uint8_t *regs, struct i2c_emul *emul) -{ - bool tag_time; - bool header; - int cmd; - - cmd = regs[BMI260_CMD_REG]; - regs[BMI260_CMD_REG] = 0; - tag_time = regs[BMI260_FIFO_CONFIG_0] & BMI260_FIFO_TIME_EN; - header = regs[BMI260_FIFO_CONFIG_1] & BMI260_FIFO_HEADER_EN; - - switch (cmd) { - case BMI160_CMD_SOFT_RESET: - bmi260_emul_reset(regs, emul); - break; - case BMI160_CMD_FIFO_FLUSH: - bmi_emul_flush_fifo(emul, tag_time, header); - break; - } -} - -/** - * @brief Get currently accessed register. It is first register plus number of - * handled bytes for all registers except BMI260_FIFO_DATA and - * BMI260_INIT_DATA for which address incrementation is disabled. - * - * @param emul Pointer to BMI emulator - * @param reg First byte of last write message - * @param bytes Number of bytes already handled from current message - * @param read If currently handled is read message - * - * @return Currently accessed register - */ -static int bmi260_emul_access_reg(struct i2c_emul *emul, int reg, int byte, - bool read) -{ - /* Ignore first byte which sets starting register */ - if (!read) { - byte -= 1; - } - - /* - * If register is FIFO data, then read data from FIFO. - * Init data is also block, but it is not implemented in emulator. - * Else block read access subsequent registers. - */ - if (reg <= BMI260_FIFO_DATA && reg + byte >= BMI260_FIFO_DATA) { - return BMI260_FIFO_DATA; - } else if (reg <= BMI260_INIT_DATA && - reg + byte >= BMI260_INIT_DATA) { - return BMI260_INIT_DATA; - } - - return reg + byte; -} - -/** - * @brief BMI260 specific write function. It handle block writes. Init data - * register is trap register, so after reaching it, register address - * is not increased on block writes. Check if read only register is not - * accessed. Before writing value, ongoing command is finished if - * possible. Write to CMD register is handled by BMI260 specific - * function. On changing of FIFO header/headerless mode or - * enabling/disabling sensor in headerless mode FIFO is flushed. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param reg Register address that is accessed - * @param byte Number of handled bytes in this write command - * @param val Value that is being written - * - * @return 0 on success - * @return BMI_EMUL_ACCESS_E on RO register access - * @return -EIO on error - */ -static int bmi260_emul_handle_write(uint8_t *regs, struct i2c_emul *emul, - int reg, int byte, uint8_t val) -{ - uint8_t mask; - bool tag_time; - bool header; - - reg = bmi260_emul_access_reg(emul, reg, byte, false /* = read */); - - if (reg <= BMI260_FIFO_DATA || reg == BMI260_GYR_SELF_TEST_AXES || - reg == BMI260_INTERNAL_ERROR || reg == BMI260_SATURATION) { - return BMI_EMUL_ACCESS_E; - } - - - /* Stop on going command if required */ - if (regs[BMI260_CMD_REG] != 0 && bmi_emul_is_cmd_end(emul)) { - bmi260_emul_end_cmd(regs, emul); - } - - tag_time = regs[BMI260_FIFO_CONFIG_0] & BMI260_FIFO_TIME_EN; - header = regs[BMI260_FIFO_CONFIG_1] & BMI260_FIFO_HEADER_EN; - - switch (reg) { - case BMI260_CMD_REG: - if (regs[BMI260_CMD_REG] != 0) { - LOG_ERR("Issued command before previous end"); - return -EIO; - } - - return bmi260_emul_start_cmd(regs, emul, val); - case BMI260_FIFO_CONFIG_1: - /* - * Clear FIFO on transition between headerless and - * header mode - */ - if (!!(val & BMI260_FIFO_HEADER_EN) != header) { - bmi_emul_flush_fifo(emul, tag_time, header); - } - break; - case BMI260_PWR_CTRL: - /* - * Clear FIFO on enabling/disabling sensors in headerless - * mode - */ - mask = BMI260_AUX_EN & BMI260_GYR_EN & BMI260_ACC_EN; - if ((val & mask) != (regs[BMI260_PWR_CTRL] & mask) && !header) { - bmi_emul_flush_fifo(emul, tag_time, header); - } - break; - } - - return 0; -} - -/** - * @brief BMI260 specific read function. It handle block reads. FIFO data - * register and init data register are trap registers, so - * after reaching it, register address is not increased on block reads. - * Before reading value, ongoing command is finished if possible. - * Read of sensor data traps current emulator state in registers. - * Read of FIFO length and FIFO data triggers default BMI functions. - * - * @param regs Pointer to array of emulator's registers - * @param emul Pointer to BMI emulator - * @param reg Register address that is accessed - * @param byte Byte which is accessed during block read - * @param buf Pointer where read byte should be stored - * - * @return 0 on success - * @return BMI_EMUL_ACCESS_E on WO register access - * @return -EIO on other error - */ -static int bmi260_emul_handle_read(uint8_t *regs, struct i2c_emul *emul, - int reg, int byte, char *buf) -{ - uint16_t fifo_len; - bool acc_off_en; - bool gyr_off_en; - bool tag_time; - bool header; - int gyr_shift; - int acc_shift; - int fifo_byte; - - /* Get number of bytes readed from FIFO */ - fifo_byte = byte - (reg - BMI260_FIFO_DATA); - - reg = bmi260_emul_access_reg(emul, reg, byte, true /* = read */); - - if (reg == BMI260_CMD_REG) { - *buf = 0; - - return BMI_EMUL_ACCESS_E; - } - - /* Stop on going command if required */ - if (regs[BMI260_CMD_REG] != 0 && bmi_emul_is_cmd_end(emul)) { - bmi260_emul_end_cmd(regs, emul); - } - - tag_time = regs[BMI260_FIFO_CONFIG_0] & BMI260_FIFO_TIME_EN; - header = regs[BMI260_FIFO_CONFIG_1] & BMI260_FIFO_HEADER_EN; - acc_off_en = regs[BMI260_NV_CONF] & BMI260_ACC_OFFSET_EN; - gyr_off_en = regs[BMI260_OFFSET_EN_GYR98] & BMI260_OFFSET_GYRO_EN; - gyr_shift = bmi260_emul_gyr_range_to_shift(regs[BMI260_GYR_RANGE]); - acc_shift = bmi260_emul_acc_range_to_shift(regs[BMI260_ACC_RANGE]); - - switch (reg) { - case BMI260_GYR_X_L_G: - case BMI260_GYR_X_H_G: - case BMI260_GYR_Y_L_G: - case BMI260_GYR_Y_H_G: - case BMI260_GYR_Z_L_G: - case BMI260_GYR_Z_H_G: - case BMI260_ACC_X_L_G: - case BMI260_ACC_X_H_G: - case BMI260_ACC_Y_L_G: - case BMI260_ACC_Y_H_G: - case BMI260_ACC_Z_L_G: - case BMI260_ACC_Z_H_G: - case BMI260_SENSORTIME_0: - case BMI260_SENSORTIME_1: - case BMI260_SENSORTIME_2: - /* - * Snapshot of current emulator state is created on data read - * and shouldn't be changed until next I2C operation - */ - if (byte == 0) { - bmi_emul_state_to_reg(emul, acc_shift, gyr_shift, - BMI260_ACC_X_L_G, - BMI260_GYR_X_L_G, - BMI260_SENSORTIME_0, - acc_off_en, gyr_off_en); - } - break; - case BMI260_FIFO_LENGTH_0: - case BMI260_FIFO_LENGTH_1: - if (byte == 0) { - fifo_len = bmi_emul_fifo_len(emul, tag_time, header); - regs[BMI260_FIFO_LENGTH_0] = fifo_len & 0xff; - regs[BMI260_FIFO_LENGTH_1] = (fifo_len >> 8) & 0x7; - } - break; - case BMI260_FIFO_DATA: - regs[reg] = bmi_emul_get_fifo_data(emul, fifo_byte, tag_time, - header, acc_shift, - gyr_shift); - break; - } - - *buf = regs[reg]; - - return 0; -} - -/** Registers backed in NVM by BMI260 */ -const int bmi260_nvm_reg[] = {BMI260_AUX_IF_TRIM, - BMI260_NV_CONF, - BMI260_DRV, - BMI260_OFFSET_ACC70, - BMI260_OFFSET_ACC70 + 1, - BMI260_OFFSET_ACC70 + 2, - BMI260_OFFSET_GYR70, - BMI260_OFFSET_GYR70 + 1, - BMI260_OFFSET_GYR70 + 2, - BMI260_OFFSET_EN_GYR98}; - -/** Confguration of BMI260 */ -struct bmi_emul_type_data bmi260_emul = { - .sensortime_follow_config_frame = true, - .handle_write = bmi260_emul_handle_write, - .handle_read = bmi260_emul_handle_read, - .access_reg = bmi260_emul_access_reg, - .reset = bmi260_emul_reset, - .rsvd_mask = bmi_emul_260_rsvd_mask, - .nvm_reg = bmi260_nvm_reg, - .nvm_len = ARRAY_SIZE(bmi260_nvm_reg), - .gyr_off_reg = BMI260_OFFSET_GYR70, - .acc_off_reg = BMI260_OFFSET_ACC70, - .gyr98_off_reg = BMI260_OFFSET_EN_GYR98, -}; - -/** Check description in emul_bmi.h */ -const struct bmi_emul_type_data *get_bmi260_emul_type_data(void) -{ - return &bmi260_emul; -} diff --git a/zephyr/emul/emul_common_i2c.c b/zephyr/emul/emul_common_i2c.c deleted file mode 100644 index bd811f1424..0000000000 --- a/zephyr/emul/emul_common_i2c.c +++ /dev/null @@ -1,432 +0,0 @@ -/* 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. - */ - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_common_i2c); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" - -/** Check description in emul_common_i2c.h */ -int i2c_common_emul_lock_data(struct i2c_emul *emul, k_timeout_t timeout) -{ - struct i2c_common_emul_data *data; - - data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - - return k_mutex_lock(&data->data_mtx, timeout); -} - -/** Check description in emul_common_i2c.h */ -int i2c_common_emul_unlock_data(struct i2c_emul *emul) -{ - struct i2c_common_emul_data *data; - - data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - - return k_mutex_unlock(&data->data_mtx); -} - -/** Check description in emul_common_i2c.h */ -void i2c_common_emul_set_write_func(struct i2c_emul *emul, - i2c_common_emul_write_func func, void *data) -{ - struct i2c_common_emul_data *emul_data; - - emul_data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - emul_data->write_func = func; - emul_data->write_func_data = data; -} - -/** Check description in emul_common_i2c.h */ -void i2c_common_emul_set_read_func(struct i2c_emul *emul, - i2c_common_emul_read_func func, void *data) -{ - struct i2c_common_emul_data *emul_data; - - emul_data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - emul_data->read_func = func; - emul_data->read_func_data = data; -} - -/** Check description in emul_common_i2c.h */ -void i2c_common_emul_set_read_fail_reg(struct i2c_emul *emul, int reg) -{ - struct i2c_common_emul_data *data; - - data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - data->read_fail_reg = reg; -} - -/** Check description in emul_common_i2c.h */ -void i2c_common_emul_set_write_fail_reg(struct i2c_emul *emul, int reg) -{ - struct i2c_common_emul_data *data; - - data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - data->write_fail_reg = reg; -} - -/** - * @brief Call start_write emulator callback if set. It handles first byte - * of I2C write message. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * - * @retval start_write emulator callback return code - */ -static int i2c_common_emul_start_write(struct i2c_emul *emul, - struct i2c_common_emul_data *data) -{ - int ret = 0; - - data->msg_byte = 0; - - if (data->start_write) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->start_write(emul, data->cur_reg); - k_mutex_unlock(&data->data_mtx); - } - - return ret; -} - -/** - * @brief Call finish_write emulator callback if set. It is called after last - * byte of I2C write message. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * - * @retval finish_write emulator callback return code - */ -static int i2c_common_emul_finish_write(struct i2c_emul *emul, - struct i2c_common_emul_data *data) -{ - int ret = 0; - - if (data->finish_write) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->finish_write(emul, data->cur_reg, data->msg_byte); - k_mutex_unlock(&data->data_mtx); - } - - return ret; -} - -/** - * @brief Call start_read emulator callback if set. It prepares emulator at - * the beginning of I2C read message. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * - * @retval start_read emulator callback return code - */ -static int i2c_common_emul_start_read(struct i2c_emul *emul, - struct i2c_common_emul_data *data) -{ - int ret = 0; - - data->msg_byte = 0; - - if (data->start_read) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->start_read(emul, data->cur_reg); - k_mutex_unlock(&data->data_mtx); - } - - return ret; -} - -/** - * @brief Call finish_read emulator callback if set. It is called after last - * byte of I2C read message. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * - * @retval finish_read emulator callback return code - */ -static int i2c_common_emul_finish_read(struct i2c_emul *emul, - struct i2c_common_emul_data *data) -{ - int ret = 0; - - if (data->finish_read) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->finish_read(emul, data->cur_reg, data->msg_byte); - k_mutex_unlock(&data->data_mtx); - } - - return ret; -} - -/** - * @brief Handle byte from I2C write message. First custom user handler is - * called (if set). Next accessed register is compared with selected - * by user fail register. Lastly, specific I2C device emulator handler - * is called. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * @param val Value of current byte - * - * @retval 0 If successful - * @retval -EIO General input / output error - */ -static int i2c_common_emul_write_byte(struct i2c_emul *emul, - struct i2c_common_emul_data *data, - uint8_t val) -{ - int reg, ret; - - /* Custom user handler */ - if (data->write_func) { - ret = data->write_func(emul, data->cur_reg, val, data->msg_byte, - data->write_func_data); - if (ret < 0) { - return -EIO; - } else if (ret == 0) { - return 0; - } - } - /* Check if user wants to fail on accessed register */ - if (data->access_reg) { - reg = data->access_reg(emul, data->cur_reg, data->msg_byte, - false /* = read */); - } else { - /* Ignore first (register address) byte */ - reg = data->cur_reg + data->msg_byte - 1; - } - - if (data->write_fail_reg == reg || - data->write_fail_reg == I2C_COMMON_EMUL_FAIL_ALL_REG) { - return -EIO; - } - /* Emulator handler */ - if (data->write_byte) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->write_byte(emul, data->cur_reg, val, - data->msg_byte); - k_mutex_unlock(&data->data_mtx); - if (ret) { - return -EIO; - } - } - - return 0; -} - -/** - * @brief Handle byte from I2C read message. First custom user handler is - * called (if set). Next accessed register is compared with selected - * by user fail register. Lastly, specific I2C device emulator handler - * is called. - * - * @param emul Pointer to emulator - * @param data Pointer to emulator data - * @param val Pointer to buffer where current response byte should be stored - * - * @retval 0 If successful - * @retval -EIO General input / output error - */ -static int i2c_common_emul_read_byte(struct i2c_emul *emul, - struct i2c_common_emul_data *data, - uint8_t *val) -{ - int reg, ret; - - /* Custom user handler */ - if (data->read_func) { - ret = data->read_func(emul, data->cur_reg, val, data->msg_byte, - data->read_func_data); - if (ret < 0) { - return -EIO; - } else if (ret == 0) { - return 0; - } - } - /* Check if user wants to fail on accessed register */ - if (data->access_reg) { - reg = data->access_reg(emul, data->cur_reg, data->msg_byte, - true /* = read */); - } else { - reg = data->cur_reg + data->msg_byte; - } - - if (data->read_fail_reg == reg || - data->read_fail_reg == I2C_COMMON_EMUL_FAIL_ALL_REG) { - return -EIO; - } - /* Emulator handler */ - if (data->read_byte) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = data->read_byte(emul, data->cur_reg, val, data->msg_byte); - k_mutex_unlock(&data->data_mtx); - if (ret) { - return -EIO; - } - } - - return 0; -} - -/** Check description in emul_common_i2c.h */ -int i2c_common_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs, - int num_msgs, int addr) -{ - const struct i2c_common_emul_cfg *cfg; - struct i2c_common_emul_data *data; - bool read, stop; - int ret, i; - - data = CONTAINER_OF(emul, struct i2c_common_emul_data, emul); - cfg = data->cfg; - - if (cfg->addr != addr) { - LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr, - addr); - return -EIO; - } - - i2c_dump_msgs(cfg->dev_label, msgs, num_msgs, addr); - - for (; num_msgs > 0; num_msgs--, msgs++) { - read = msgs->flags & I2C_MSG_READ; - stop = msgs->flags & I2C_MSG_STOP; - - switch (data->msg_state) { - case I2C_COMMON_EMUL_IN_WRITE: - if (read) { - data->msg_state = I2C_COMMON_EMUL_NONE_MSG; - ret = i2c_common_emul_finish_write(emul, data); - if (ret) { - return ret; - } - ret = i2c_common_emul_start_read(emul, data); - if (ret) { - return ret; - } - } - break; - case I2C_COMMON_EMUL_IN_READ: - if (!read) { - data->msg_state = I2C_COMMON_EMUL_NONE_MSG; - ret = i2c_common_emul_finish_read(emul, data); - if (ret) { - return ret; - } - /* Wait for write message with acctual data */ - if (msgs->len == 0) { - continue; - } - /* Dispatch command/register address */ - data->cur_reg = msgs->buf[0]; - ret = i2c_common_emul_start_write(emul, data); - if (ret) { - return ret; - } - } - break; - case I2C_COMMON_EMUL_NONE_MSG: - if (read) { - ret = i2c_common_emul_start_read(emul, data); - if (ret) { - return ret; - } - } else { - /* Wait for write message with acctual data */ - if (msgs->len == 0) { - continue; - } - /* Dispatch command/register address */ - data->cur_reg = msgs->buf[0]; - ret = i2c_common_emul_start_write(emul, data); - if (ret) { - return ret; - } - } - } - - data->msg_state = read ? I2C_COMMON_EMUL_IN_READ - : I2C_COMMON_EMUL_IN_WRITE; - - if (stop) { - data->msg_state = I2C_COMMON_EMUL_NONE_MSG; - } - - if (!read) { - /* - * All current emulators use first byte of write message - * as command/register address for following write bytes - * or read message. Skip first byte which was dispatched - * already. - */ - if (data->msg_byte == 0) { - data->msg_byte = 1; - i = 1; - } else { - i = 0; - } - /* Dispatch write command */ - for (; i < msgs->len; i++, data->msg_byte++) { - ret = i2c_common_emul_write_byte(emul, data, - msgs->buf[i]); - if (ret) { - return ret; - } - } - /* Finish write command */ - if (stop) { - ret = i2c_common_emul_finish_write(emul, data); - if (ret) { - return ret; - } - } - } else { - /* Dispatch read command */ - for (i = 0; i < msgs->len; i++, data->msg_byte++) { - ret = i2c_common_emul_read_byte(emul, data, - &(msgs->buf[i])); - if (ret) { - return ret; - } - } - - /* Finish read command */ - if (stop) { - ret = i2c_common_emul_finish_read(emul, data); - if (ret) { - return ret; - } - } - } - } - - return 0; -} - -/** Check description in emul_common_i2c.h */ -void i2c_common_emul_init(struct i2c_common_emul_data *data) -{ - data->msg_state = I2C_COMMON_EMUL_NONE_MSG; - data->msg_byte = 0; - data->cur_reg = 0; - - data->write_func = NULL; - data->read_func = NULL; - - data->write_fail_reg = I2C_COMMON_EMUL_NO_FAIL_REG; - data->read_fail_reg = I2C_COMMON_EMUL_NO_FAIL_REG; - - k_mutex_init(&data->data_mtx); -} diff --git a/zephyr/emul/emul_lis2dw12.c b/zephyr/emul/emul_lis2dw12.c deleted file mode 100644 index 6fa8b31cc9..0000000000 --- a/zephyr/emul/emul_lis2dw12.c +++ /dev/null @@ -1,161 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT cros_lis2dw12_emul - -#include <device.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> -#include <emul.h> -#include <errno.h> -#include <sys/__assert.h> - -#include "driver/accel_lis2dw12.h" -#include "emul/emul_common_i2c.h" -#include "emul/emul_lis2dw12.h" -#include "i2c.h" - -#include <logging/log.h> -LOG_MODULE_REGISTER(lis2dw12_emul, CONFIG_LIS2DW12_EMUL_LOG_LEVEL); - -#define LIS2DW12_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct lis2dw12_emul_data, common) - -struct lis2dw12_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - /** Emulated who-am-i register */ - uint8_t who_am_i_reg; - /** Emulated ctrl2 register */ - uint8_t ctrl2_reg; - /** Soft reset count */ - uint32_t soft_reset_count; -}; - -struct lis2dw12_emul_cfg { - /** Common I2C config */ - struct i2c_common_emul_cfg common; -}; - -struct i2c_emul *lis2dw12_emul_to_i2c_emul(const struct emul *emul) -{ - struct lis2dw12_emul_data *data = emul->data; - - return &(data->common.emul); -} - -void lis2dw12_emul_reset(const struct emul *emul) -{ - struct lis2dw12_emul_data *data = emul->data; - struct i2c_emul *i2c_emul = lis2dw12_emul_to_i2c_emul(emul); - - 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); - i2c_common_emul_set_read_func(i2c_emul, NULL, NULL); - i2c_common_emul_set_write_func(i2c_emul, NULL, NULL); - data->who_am_i_reg = LIS2DW12_WHO_AM_I; - data->ctrl2_reg = 0; - data->soft_reset_count = 0; -} - -void lis2dw12_emul_set_who_am_i(const struct emul *emul, uint8_t who_am_i) -{ - struct lis2dw12_emul_data *data = emul->data; - - data->who_am_i_reg = who_am_i; -} - -uint32_t lis2dw12_emul_get_soft_reset_count(const struct emul *emul) -{ - struct lis2dw12_emul_data *data = emul->data; - - return data->soft_reset_count; -} - -static int lis2dw12_emul_read_byte(struct i2c_emul *emul, int reg, uint8_t *val, - int bytes) -{ - struct lis2dw12_emul_data *data = LIS2DW12_DATA_FROM_I2C_EMUL(emul); - - switch (reg) { - case LIS2DW12_WHO_AM_I_REG: - __ASSERT_NO_MSG(bytes == 0); - *val = data->who_am_i_reg; - break; - case LIS2DW12_CTRL2_ADDR: - __ASSERT_NO_MSG(bytes == 0); - *val = data->ctrl2_reg; - break; - default: - return -EINVAL; - } - return 0; -} - -static int lis2dw12_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct lis2dw12_emul_data *data = LIS2DW12_DATA_FROM_I2C_EMUL(emul); - - switch (reg) { - case LIS2DW12_WHO_AM_I_REG: - LOG_ERR("Can't write to who-am-i register"); - return -EINVAL; - case LIS2DW12_CTRL2_ADDR: - __ASSERT_NO_MSG(bytes == 1); - if ((val & LIS2DW12_SOFT_RESET_MASK) != 0) { - /* Soft reset */ - data->soft_reset_count++; - } - data->ctrl2_reg = val & ~LIS2DW12_SOFT_RESET_MASK; - break; - default: - return -EINVAL; - } - return 0; -} - -static struct i2c_emul_api lis2dw12_emul_api_i2c = { - .transfer = i2c_common_emul_transfer, -}; - -static int emul_lis2dw12_init(const struct emul *emul, - const struct device *parent) -{ - const struct lis2dw12_emul_cfg *lis2dw12_cfg = emul->cfg; - const struct i2c_common_emul_cfg *cfg = &(lis2dw12_cfg->common); - struct lis2dw12_emul_data *data = emul->data; - - data->common.emul.api = &lis2dw12_emul_api_i2c; - data->common.emul.addr = cfg->addr; - data->common.emul.parent = emul; - data->common.i2c = parent; - data->common.cfg = cfg; - i2c_common_emul_init(&data->common); - - return i2c_emul_register(parent, emul->dev_label, &data->common.emul); -} - -#define INIT_LIS2DW12(n) \ - static struct lis2dw12_emul_data lis2dw12_emul_data_##n = { \ - .common = { \ - .write_byte = lis2dw12_emul_write_byte, \ - .read_byte = lis2dw12_emul_read_byte, \ - }, \ - }; \ - static const struct lis2dw12_emul_cfg lis2dw12_emul_cfg_##n = { \ - .common = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .addr = DT_INST_REG_ADDR(n), \ - }, \ - }; \ - EMUL_DEFINE(emul_lis2dw12_init, DT_DRV_INST(n), \ - &lis2dw12_emul_cfg_##n, &lis2dw12_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(INIT_LIS2DW12) diff --git a/zephyr/emul/emul_ln9310.c b/zephyr/emul/emul_ln9310.c deleted file mode 100644 index d4eaa8e38d..0000000000 --- a/zephyr/emul/emul_ln9310.c +++ /dev/null @@ -1,388 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT cros_ln9310_emul - -#include <device.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> -#include <emul.h> -#include <errno.h> -#include <sys/__assert.h> - -#include "driver/ln9310.h" -#include "emul/emul_common_i2c.h" -#include "emul/emul_ln9310.h" -#include "i2c.h" - -#include <logging/log.h> -LOG_MODULE_REGISTER(ln9310_emul, CONFIG_LN9310_EMUL_LOG_LEVEL); - -#define LN9310_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct ln9310_emul_data, common) - -struct ln9310_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - /** The current emulated battery cell type */ - enum battery_cell_type battery_cell_type; - /** Emulated INT1 MSK register */ - uint8_t int1_msk_reg; - /** Emulated Lion control register */ - uint8_t lion_ctrl_reg; - /** Emulated startup control register */ - uint8_t startup_ctrl_reg; - /** Emulated BC STST B register */ - uint8_t bc_sts_b_reg; - /** Emulated BC STST C register */ - uint8_t bc_sts_c_reg; - /** Emulated cfg 0 register */ - uint8_t cfg_0_reg; - /** Emulated cfg 4 register */ - uint8_t cfg_4_reg; - /** Emulated cfg 5 register */ - uint8_t cfg_5_reg; - /** Emulated power control register */ - uint8_t power_ctrl_reg; - /** Emulated timer control register */ - uint8_t timer_ctrl_reg; - /** Emulated lower bound (LB) control register */ - uint8_t lower_bound_ctrl_reg; - /** Emulated spare 0 register */ - uint8_t spare_0_reg; - /** Emulated swap control 0 register */ - uint8_t swap_ctrl_0_reg; - /** Emulated swap control 1 register */ - uint8_t swap_ctrl_1_reg; - /** Emulated swap control 2 register */ - uint8_t swap_ctrl_2_reg; - /** Emulated swap control 3 register */ - uint8_t swap_ctrl_3_reg; - /** Emulated track control register */ - uint8_t track_ctrl_reg; - /** Emulated mode change register */ - uint8_t mode_change_reg; - /** Emulated system control register */ - uint8_t sys_ctrl_reg; -}; - -static const struct emul *singleton; - -void ln9310_emul_set_context(const struct emul *emulator) -{ - singleton = emulator; -} - -void ln9310_emul_reset(const struct emul *emulator) -{ - struct ln9310_emul_data *data = emulator->data; - - data->lion_ctrl_reg = 0; - data->startup_ctrl_reg = 0; - data->bc_sts_b_reg = 0; - data->cfg_0_reg = 0; - data->cfg_4_reg = 0; - data->cfg_5_reg = 0; - data->power_ctrl_reg = 0; - data->timer_ctrl_reg = 0; - data->lower_bound_ctrl_reg = 0; - data->spare_0_reg = 0; - data->swap_ctrl_0_reg = 0; - data->swap_ctrl_1_reg = 0; - data->swap_ctrl_2_reg = 0; - data->swap_ctrl_3_reg = 0; - data->track_ctrl_reg = 0; - data->mode_change_reg = 0; - data->sys_ctrl_reg = 0; -} - -void ln9310_emul_set_battery_cell_type(const struct emul *emulator, - enum battery_cell_type type) -{ - struct ln9310_emul_data *data = emulator->data; - - data->battery_cell_type = type; -} - -void ln9310_emul_set_version(const struct emul *emulator, int version) -{ - struct ln9310_emul_data *data = emulator->data; - - data->bc_sts_c_reg |= version & LN9310_BC_STS_C_CHIP_REV_MASK; -} - -void ln9310_emul_set_vin_gt_10v(const struct emul *emulator, bool is_gt_10v) -{ - struct ln9310_emul_data *data = emulator->data; - - if (is_gt_10v) - data->bc_sts_b_reg |= LN9310_BC_STS_B_INFET_OUT_SWITCH_OK; - else - data->bc_sts_b_reg &= ~LN9310_BC_STS_B_INFET_OUT_SWITCH_OK; -} - -bool ln9310_emul_is_init(const struct emul *emulator) -{ - struct ln9310_emul_data *data = emulator->data; - - return (data->int1_msk_reg & LN9310_INT1_MODE) == 0; -} - -enum battery_cell_type board_get_battery_cell_type(void) -{ - struct ln9310_emul_data *data = singleton->data; - - return data->battery_cell_type; -} - -static struct i2c_emul_api ln9310_emul_api_i2c = { - .transfer = i2c_common_emul_transfer, -}; - -static int ln9310_emul_start_write(struct i2c_emul *emul, int reg) -{ - return 0; -} - -static int ln9310_emul_finish_write(struct i2c_emul *emul, int reg, int bytes) -{ - return 0; -} - -static int ln9310_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct ln9310_emul_data *data = LN9310_DATA_FROM_I2C_EMUL(emul); - - switch (reg) { - case LN9310_REG_INT1_MSK: - __ASSERT_NO_MSG(bytes == 1); - data->int1_msk_reg = val; - break; - case LN9310_REG_STARTUP_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->startup_ctrl_reg = val; - break; - case LN9310_REG_LION_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->lion_ctrl_reg = val; - break; - case LN9310_REG_BC_STS_B: - __ASSERT_NO_MSG(bytes == 1); - data->bc_sts_b_reg = val; - break; - case LN9310_REG_BC_STS_C: - LOG_ERR("Can't write to BC STS C register"); - return -EINVAL; - case LN9310_REG_CFG_0: - __ASSERT_NO_MSG(bytes == 1); - data->cfg_0_reg = val; - break; - case LN9310_REG_CFG_4: - __ASSERT_NO_MSG(bytes == 1); - data->cfg_4_reg = val; - break; - case LN9310_REG_CFG_5: - __ASSERT_NO_MSG(bytes == 1); - data->cfg_5_reg = val; - break; - case LN9310_REG_PWR_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->power_ctrl_reg = val; - break; - case LN9310_REG_TIMER_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->timer_ctrl_reg = val; - break; - case LN9310_REG_LB_CTRL: - __ASSERT_NO_MSG(bytes = 1); - data->lower_bound_ctrl_reg = val; - break; - case LN9310_REG_SPARE_0: - __ASSERT_NO_MSG(bytes == 1); - data->spare_0_reg = val; - break; - case LN9310_REG_SWAP_CTRL_0: - __ASSERT_NO_MSG(bytes == 1); - data->swap_ctrl_0_reg = val; - break; - case LN9310_REG_SWAP_CTRL_1: - __ASSERT_NO_MSG(bytes == 1); - data->swap_ctrl_1_reg = val; - break; - case LN9310_REG_SWAP_CTRL_2: - __ASSERT_NO_MSG(bytes == 1); - data->swap_ctrl_2_reg = val; - break; - case LN9310_REG_SWAP_CTRL_3: - __ASSERT_NO_MSG(bytes == 1); - data->swap_ctrl_3_reg = val; - break; - case LN9310_REG_TRACK_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->track_ctrl_reg = val; - break; - case LN9310_REG_MODE_CHANGE_CFG: - __ASSERT_NO_MSG(bytes == 1); - data->mode_change_reg = val; - break; - case LN9310_REG_SYS_CTRL: - __ASSERT_NO_MSG(bytes == 1); - data->sys_ctrl_reg = val; - break; - default: - return -EINVAL; - } - return 0; -} - -static int ln9310_emul_start_read(struct i2c_emul *emul, int reg) -{ - return 0; -} - -static int ln9310_emul_finish_read(struct i2c_emul *emul, int reg, int bytes) -{ - return 0; -} - -static int ln9310_emul_read_byte(struct i2c_emul *emul, int reg, uint8_t *val, - int bytes) -{ - struct ln9310_emul_data *data = LN9310_DATA_FROM_I2C_EMUL(emul); - - switch (reg) { - case LN9310_REG_INT1_MSK: - __ASSERT_NO_MSG(bytes == 0); - *val = data->int1_msk_reg; - break; - case LN9310_REG_STARTUP_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->startup_ctrl_reg; - break; - case LN9310_REG_LION_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->lion_ctrl_reg; - break; - case LN9310_REG_BC_STS_B: - __ASSERT_NO_MSG(bytes == 0); - *val = data->bc_sts_b_reg; - break; - case LN9310_REG_BC_STS_C: - __ASSERT_NO_MSG(bytes == 0); - *val = data->bc_sts_c_reg; - break; - case LN9310_REG_CFG_0: - __ASSERT_NO_MSG(bytes == 0); - *val = data->cfg_0_reg; - break; - case LN9310_REG_CFG_4: - __ASSERT_NO_MSG(bytes == 0); - *val = data->cfg_4_reg; - break; - case LN9310_REG_CFG_5: - __ASSERT_NO_MSG(bytes == 0); - *val = data->cfg_5_reg; - break; - case LN9310_REG_PWR_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->power_ctrl_reg; - break; - case LN9310_REG_TIMER_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->timer_ctrl_reg; - break; - case LN9310_REG_LB_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->lower_bound_ctrl_reg; - break; - case LN9310_REG_SPARE_0: - __ASSERT_NO_MSG(bytes == 0); - *val = data->spare_0_reg; - break; - case LN9310_REG_SWAP_CTRL_0: - __ASSERT_NO_MSG(bytes == 0); - *val = data->swap_ctrl_0_reg; - break; - case LN9310_REG_SWAP_CTRL_1: - __ASSERT_NO_MSG(bytes == 0); - *val = data->swap_ctrl_1_reg; - break; - case LN9310_REG_SWAP_CTRL_2: - __ASSERT_NO_MSG(bytes == 0); - *val = data->swap_ctrl_2_reg; - break; - case LN9310_REG_SWAP_CTRL_3: - __ASSERT_NO_MSG(bytes == 0); - *val = data->swap_ctrl_3_reg; - break; - case LN9310_REG_TRACK_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->track_ctrl_reg; - break; - case LN9310_REG_MODE_CHANGE_CFG: - __ASSERT_NO_MSG(bytes == 0); - *val = data->mode_change_reg; - break; - case LN9310_REG_SYS_CTRL: - __ASSERT_NO_MSG(bytes == 0); - *val = data->sys_ctrl_reg; - break; - default: - return -EINVAL; - } - return 0; -} - -static int ln9310_emul_access_reg(struct i2c_emul *emul, int reg, int bytes, - bool read) -{ - return 0; -} - -static int emul_ln9310_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct ln9310_emul_data *data = emul->data; - - data->common.emul.api = &ln9310_emul_api_i2c; - data->common.emul.addr = cfg->addr; - data->common.emul.parent = emul; - data->common.i2c = parent; - data->common.cfg = cfg; - i2c_common_emul_init(&data->common); - - singleton = emul; - - return i2c_emul_register(parent, emul->dev_label, &data->common.emul); -} - -#define INIT_LN9310(n) \ - const struct ln9310_config_t ln9310_config = { \ - .i2c_port = NAMED_I2C(power), \ - .i2c_addr_flags = DT_INST_REG_ADDR(n), \ - }; \ - static struct ln9310_emul_data ln9310_emul_data_##n = { \ - .common = { \ - .start_write = ln9310_emul_start_write, \ - .write_byte = ln9310_emul_write_byte, \ - .finish_write = ln9310_emul_finish_write, \ - .start_read = ln9310_emul_start_read, \ - .read_byte = ln9310_emul_read_byte, \ - .finish_read = ln9310_emul_finish_read, \ - .access_reg = ln9310_emul_access_reg, \ - }, \ - }; \ - static const struct i2c_common_emul_cfg ln9310_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(emul_ln9310_init, DT_DRV_INST(n), &ln9310_emul_cfg_##n, \ - &ln9310_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(INIT_LN9310) diff --git a/zephyr/emul/emul_pi3usb9201.c b/zephyr/emul/emul_pi3usb9201.c deleted file mode 100644 index babef58c75..0000000000 --- a/zephyr/emul/emul_pi3usb9201.c +++ /dev/null @@ -1,195 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_pi3usb9201_emul - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_pi3usb9201.h" - -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_pi3usb9201, LOG_LEVEL_DBG); - -#define EMUL_REG_COUNT (PI3USB9201_REG_HOST_STS + 1) -#define EMUL_REG_IS_VALID(reg) (reg >= 0 && reg < EMUL_REG_COUNT) - -/** Run-time data used by the emulator */ -struct pi3usb9201_emul_data { - /** I2C emulator detail */ - struct i2c_emul emul; - /** pi3usb9201 device being emulated */ - const struct device *i2c; - /** Configuration information */ - const struct pi3usb9201_emul_cfg *cfg; - /** Current state of all emulated pi3usb9201 registers */ - uint8_t reg[EMUL_REG_COUNT]; -}; - -/** Static configuration for the emulator */ -struct pi3usb9201_emul_cfg { - /** Label of the I2C bus this emulator connects to */ - const char *i2c_label; - /** Pointer to run-time data */ - struct pi3usb9201_emul_data *data; - /** Address of pi3usb9201 on i2c bus */ - uint16_t addr; -}; - -int pi3usb9201_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) -{ - struct pi3usb9201_emul_data *data; - - if (!EMUL_REG_IS_VALID(reg)) - return -EIO; - - data = CONTAINER_OF(emul, struct pi3usb9201_emul_data, emul); - data->reg[reg] = val; - - return 0; -} - -int pi3usb9201_emul_get_reg(struct i2c_emul *emul, int reg, uint8_t *val) -{ - struct pi3usb9201_emul_data *data; - - if (!EMUL_REG_IS_VALID(reg)) - return -EIO; - - data = CONTAINER_OF(emul, struct pi3usb9201_emul_data, emul); - *val = data->reg[reg]; - - return 0; -} - -static void pi3usb9201_emul_reset(struct i2c_emul *emul) -{ - struct pi3usb9201_emul_data *data; - - data = CONTAINER_OF(emul, struct pi3usb9201_emul_data, emul); - - data->reg[PI3USB9201_REG_CTRL_1] = 0; - data->reg[PI3USB9201_REG_CTRL_2] = 0; - data->reg[PI3USB9201_REG_CLIENT_STS] = 0; - data->reg[PI3USB9201_REG_HOST_STS] = 0; -} - -/** - * Emulate an I2C transfer to a pi3usb9201 - * - * This handles simple reads and writes - * - * @param emul I2C emulation information - * @param msgs List of messages to process - * @param num_msgs Number of messages to process - * @param addr Address of the I2C target device - * - * @retval 0 If successful - * @retval -EIO General input / output error - */ -static int pi3usb9201_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs, - int num_msgs, int addr) -{ - const struct pi3usb9201_emul_cfg *cfg; - struct pi3usb9201_emul_data *data; - - data = CONTAINER_OF(emul, struct pi3usb9201_emul_data, emul); - cfg = data->cfg; - - if (cfg->addr != addr) { - LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr, - addr); - return -EIO; - } - - i2c_dump_msgs("emul", msgs, num_msgs, addr); - - if (num_msgs == 1) { - if (!(((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) - && (msgs[0].len == 2))) { - LOG_ERR("Unexpected write msgs"); - return -EIO; - } - return pi3usb9201_emul_set_reg(emul, msgs[0].buf[0], - msgs[0].buf[1]); - } else if (num_msgs == 2) { - if (!(((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) - && (msgs[0].len == 1) - && ((msgs[1].flags & I2C_MSG_RW_MASK) == I2C_MSG_READ) - && (msgs[1].len == 1))) { - LOG_ERR("Unexpected read msgs"); - return -EIO; - } - return pi3usb9201_emul_get_reg(emul, msgs[0].buf[0], - &(msgs[1].buf[0])); - } else { - LOG_ERR("Unexpected num_msgs"); - return -EIO; - } - -} - -/* Device instantiation */ - -static struct i2c_emul_api pi3usb9201_emul_api = { - .transfer = pi3usb9201_emul_transfer, -}; - -/** - * @brief Set up a new pi3usb9201 emulator - * - * This should be called for each pi3usb9201 device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int pi3usb9201_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct pi3usb9201_emul_cfg *cfg = emul->cfg; - struct pi3usb9201_emul_data *data = cfg->data; - int ret; - - data->emul.api = &pi3usb9201_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - pi3usb9201_emul_reset(&data->emul); - - return ret; -} - -#define PI3USB9201_EMUL(n) \ - static struct pi3usb9201_emul_data pi3usb9201_emul_data_##n = {}; \ - static const struct pi3usb9201_emul_cfg pi3usb9201_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .data = &pi3usb9201_emul_data_##n, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(pi3usb9201_emul_init, DT_DRV_INST(n), \ - &pi3usb9201_emul_cfg_##n, &pi3usb9201_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(PI3USB9201_EMUL) - -#define PI3USB9201_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &pi3usb9201_emul_data_##n.emul; - -struct i2c_emul *pi3usb9201_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(PI3USB9201_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_smart_battery.c b/zephyr/emul/emul_smart_battery.c deleted file mode 100644 index 4b1d87336e..0000000000 --- a/zephyr/emul/emul_smart_battery.c +++ /dev/null @@ -1,893 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_smart_battery - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(smart_battery); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" -#include "emul/emul_smart_battery.h" - -#include "crc8.h" -#include "battery_smart.h" - -#define SBAT_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct sbat_emul_data, common) - -/** Run-time data used by the emulator */ -struct sbat_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Data required to simulate battery */ - struct sbat_emul_bat_data bat; - /** Command that should be handled next */ - int cur_cmd; - /** Message buffer which is used to handle smb transactions */ - uint8_t msg_buf[MSG_BUF_LEN]; - /** Total bytes that were generated in response to smb read operation */ - int num_to_read; -}; - -/** Check description in emul_smart_battery.h */ -struct sbat_emul_bat_data *sbat_emul_get_bat_data(struct i2c_emul *emul) -{ - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - - return &data->bat; -} - -/** Check description in emul_smart_battery.h */ -uint16_t sbat_emul_date_to_word(unsigned int day, unsigned int month, - unsigned int year) -{ - year -= MANUFACTURE_DATE_YEAR_OFFSET; - year <<= MANUFACTURE_DATE_YEAR_SHIFT; - year &= MANUFACTURE_DATE_YEAR_MASK; - month <<= MANUFACTURE_DATE_MONTH_SHIFT; - month &= MANUFACTURE_DATE_MONTH_MASK; - day <<= MANUFACTURE_DATE_DAY_SHIFT; - day &= MANUFACTURE_DATE_DAY_MASK; - - return day | month | year; -} - -/** - * @brief Compute CRC from the beginning of the message - * - * @param addr Smart battery address on SMBus - * @param read If message for which CRC is computed is read. For read message - * byte command and repeated address is added to CRC - * @param cmd Command used in read message - * - * @return pec CRC from first bytes of message - */ -static uint8_t sbat_emul_pec_head(uint8_t addr, int read, uint8_t cmd) -{ - uint8_t pec; - - addr <<= 1; - - pec = cros_crc8(&addr, 1); - if (!read) { - return pec; - } - - pec = cros_crc8_arg(&cmd, 1, pec); - addr |= I2C_MSG_READ; - pec = cros_crc8_arg(&addr, 1, pec); - - return pec; -} - -/** - * @brief Convert from 10mW power units to mA current under given mV voltage - * - * @param mw Power in 10mW units - * @param mv Voltage in mV units - * - * @return Current in mA units - */ -static uint16_t sbat_emul_10mw_to_ma(int mw, int mv) -{ - /* Smart battery use 10mW units, convert to mW */ - mw *= 10; - /* Multiple by 1000 to get mA instead of A */ - return 1000 * mw/mv; -} - -/** - * @brief Convert from mA current to 10mW power under given mV voltage - * - * @param ma Current in mA units - * @param mv Voltage in mV units - * - * @return Power in 10mW units - */ -static uint16_t sbat_emul_ma_to_10mw(int ma, int mv) -{ - int mw; - /* Divide by 1000 to get mW instead of uW */ - mw = ma * mv / 1000; - /* Smart battery use 10mW units, convert to 10mW */ - return mw / 10; -} - -/** - * @brief Get time in minutes how long it will take to get given amount of - * charge at given current flow - * - * @param bat Pointer to battery data to set error code in case of - * over/under flow in time calculation - * @param rate Rate of current in mAh - * @param cap Required amount of charge in mA - * @param time Pointer to memory where calculated time will be stored - * - * @return 0 on success - * @return -EINVAL when over or under flow occurred - */ -static int sbat_emul_get_time_to_complete(struct sbat_emul_bat_data *bat, - int rate, int cap, uint16_t *ret_time) -{ - int time; - - /* At negative rate process never ends, return maximum value */ - if (rate <= 0) { - *ret_time = UINT16_MAX; - - return 0; - } - /* Convert capacity from mAh to mAmin */ - time = cap * 60 / rate; - /* Check overflow */ - if (time >= UINT16_MAX) { - *ret_time = UINT16_MAX; - bat->error_code = STATUS_CODE_OVERUNDERFLOW; - - return -EINVAL; - } - /* Check underflow */ - if (time < 0) { - *ret_time = 0; - bat->error_code = STATUS_CODE_OVERUNDERFLOW; - - return -EINVAL; - } - - *ret_time = time; - - return 0; -} - -/** - * @brief Get time in minutes how long it will take to charge battery - * - * @param bat Pointer to battery data - * @param rate Rate of charging current in mAh - * @param time Pointer to memory where calculated time will be stored - * - * @return 0 on success - * @return -EINVAL when over or under flow occurred - */ -static int sbat_emul_time_to_full(struct sbat_emul_bat_data *bat, int rate, - uint16_t *time) -{ - int cap; - - cap = bat->full_cap - bat->cap; - return sbat_emul_get_time_to_complete(bat, rate, cap, time); -} - -/** - * @brief Get time in minutes how long it will take to discharge battery. Note, - * that rate should be negative to indicate discharging. - * - * @param bat Pointer to battery data - * @param rate Rate of charging current in mAh - * @param time Pointer to memory where calculated time will be stored - * - * @return 0 on success - * @return -EINVAL when over or under flow occurred - */ -static int sbat_emul_time_to_empty(struct sbat_emul_bat_data *bat, int rate, - uint16_t *time) -{ - int cap; - - /* Reverse to have discharging rate instead of charging rate */ - rate = -rate; - cap = bat->cap; - return sbat_emul_get_time_to_complete(bat, rate, cap, time); -} - -/** - * @brief Check if battery can supply for 10 seconds additional power/current - * set in at_rate register. - * - * @param bat Pointer to battery data - * @param rate Rate of charging current in mAh - * @param ok Pointer to memory where 0 is written if battery is able to supply - * additional power/curent or 1 is written if battery is unable - * to do so. - * - * @return 0 on success - */ -static int sbat_emul_read_at_rate_ok(struct sbat_emul_bat_data *bat, - uint16_t *ok) -{ - int rem_time_s; - int rate; - - rate = bat->at_rate; - if (bat->mode & MODE_CAPACITY) { - rate = sbat_emul_10mw_to_ma(rate, bat->design_mv); - } - - /* Add current battery usage */ - rate += bat->cur; - if (rate >= 0) { - /* Battery will be charged */ - *ok = 1; - - return 0; - } - /* Reverse to have discharging rate instead of charging rate */ - rate = -rate; - - rem_time_s = bat->cap * 3600 / rate; - if (rem_time_s > 10) { - /* - * Battery can support 10 seconds of additional at_rate - * current/power - */ - *ok = 1; - } else { - *ok = 0; - } - - return 0; -} - -/** - * @brief Get battery status. This function use emulated status register and - * set or clear some of the flags based on other properties of emulated - * smart battery. Discharge bit, capacity alarm, time alarm, fully - * discharged bit and error code are controlled by battery properties. - * Terminate charge/discharge/overcharge alarms are set only if they are - * set in emulated status register and battery is charging/discharging, - * so they are partialy controlled by emulated status register. - * Other bits are controlled by emulated status register - * - * @param emul Pointer to smart battery emulator - * - * @return value which equals to computed status register - */ -static uint16_t sbat_emul_read_status(struct i2c_emul *emul) -{ - uint16_t status, cap, rem_time, charge_percent; - struct sbat_emul_bat_data *bat; - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - bat = &data->bat; - - status = bat->status; - - /* - * Over charged and terminate charger alarm cannot appear when battery - * is not charged - */ - if (bat->cur <= 0) { - status &= ~(STATUS_TERMINATE_CHARGE_ALARM | - STATUS_OVERCHARGED_ALARM); - status |= STATUS_DISCHARGING; - } - /* Terminate discharge alarm cannot appear when battery is charged */ - if (bat->cur >= 0) { - status &= ~(STATUS_TERMINATE_DISCHARGE_ALARM | - STATUS_DISCHARGING); - } - - sbat_emul_get_word_val(emul, SB_REMAINING_CAPACITY, &cap); - if (bat->cap_alarm && cap < bat->cap_alarm) { - status |= STATUS_REMAINING_CAPACITY_ALARM; - } else { - status &= ~STATUS_REMAINING_CAPACITY_ALARM; - } - - sbat_emul_get_word_val(emul, SB_AVERAGE_TIME_TO_EMPTY, &rem_time); - if (bat->time_alarm && rem_time < bat->time_alarm) { - status |= STATUS_REMAINING_TIME_ALARM; - } else { - status &= ~STATUS_REMAINING_TIME_ALARM; - } - - /* Unset fully discharged bit when charge is grater than 20% */ - sbat_emul_get_word_val(emul, SB_RELATIVE_STATE_OF_CHARGE, - &charge_percent); - if (charge_percent > 20) { - status &= ~STATUS_FULLY_DISCHARGED; - } else { - status |= STATUS_FULLY_DISCHARGED; - } - - status |= bat->error_code & STATUS_ERR_CODE_MASK; - - return status; -} - -/** Check description in emul_smart_battery.h */ -int sbat_emul_get_word_val(struct i2c_emul *emul, int cmd, uint16_t *val) -{ - struct sbat_emul_bat_data *bat; - struct sbat_emul_data *data; - int mode_mw; - int rate; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - bat = &data->bat; - mode_mw = bat->mode & MODE_CAPACITY; - - switch (cmd) { - case SB_MANUFACTURER_ACCESS: - *val = bat->mf_access; - return 0; - case SB_REMAINING_CAPACITY_ALARM: - *val = bat->cap_alarm; - return 0; - case SB_REMAINING_TIME_ALARM: - *val = bat->time_alarm; - return 0; - case SB_BATTERY_MODE: - *val = bat->mode; - return 0; - case SB_AT_RATE: - *val = bat->at_rate; - return 0; - case SB_AT_RATE_TIME_TO_FULL: - /* Support for reporting time to full in mW mode is optional */ - if (mode_mw && !bat->at_rate_full_mw_support) { - bat->error_code = STATUS_CODE_OVERUNDERFLOW; - *val = UINT16_MAX; - - return -EINVAL; - } - - rate = bat->at_rate; - if (mode_mw) { - rate = sbat_emul_10mw_to_ma(rate, bat->design_mv); - } - return sbat_emul_time_to_full(bat, rate, val); - - case SB_AT_RATE_TIME_TO_EMPTY: - rate = bat->at_rate; - if (mode_mw) { - rate = sbat_emul_10mw_to_ma(rate, bat->design_mv); - } - return sbat_emul_time_to_empty(bat, rate, val); - - case SB_AT_RATE_OK: - return sbat_emul_read_at_rate_ok(bat, val); - case SB_TEMPERATURE: - *val = bat->temp; - return 0; - case SB_VOLTAGE: - *val = bat->volt; - return 0; - case SB_CURRENT: - *val = bat->cur; - return 0; - case SB_AVERAGE_CURRENT: - *val = bat->avg_cur; - return 0; - case SB_MAX_ERROR: - *val = bat->max_error; - return 0; - case SB_RELATIVE_STATE_OF_CHARGE: - /* Percent of charge according to full capacity */ - *val = 100 * bat->cap / bat->full_cap; - return 0; - case SB_ABSOLUTE_STATE_OF_CHARGE: - /* Percent of charge according to design capacity */ - *val = 100 * bat->cap / bat->design_cap; - return 0; - case SB_REMAINING_CAPACITY: - if (mode_mw) { - *val = sbat_emul_ma_to_10mw(bat->cap, bat->design_mv); - } else { - *val = bat->cap; - } - return 0; - case SB_FULL_CHARGE_CAPACITY: - if (mode_mw) { - *val = sbat_emul_ma_to_10mw(bat->full_cap, - bat->design_mv); - } else { - *val = bat->full_cap; - } - return 0; - case SB_RUN_TIME_TO_EMPTY: - rate = bat->cur; - return sbat_emul_time_to_empty(bat, rate, val); - case SB_AVERAGE_TIME_TO_EMPTY: - rate = bat->avg_cur; - return sbat_emul_time_to_empty(bat, rate, val); - case SB_AVERAGE_TIME_TO_FULL: - rate = bat->avg_cur; - return sbat_emul_time_to_full(bat, rate, val); - case SB_CHARGING_CURRENT: - *val = bat->desired_charg_cur; - return 0; - case SB_CHARGING_VOLTAGE: - *val = bat->desired_charg_volt; - return 0; - case SB_BATTERY_STATUS: - *val = sbat_emul_read_status(emul); - return 0; - case SB_CYCLE_COUNT: - *val = bat->cycle_count; - return 0; - case SB_DESIGN_CAPACITY: - if (mode_mw) { - *val = sbat_emul_ma_to_10mw(bat->design_cap, - bat->design_mv); - } else { - *val = bat->design_cap; - } - return 0; - case SB_DESIGN_VOLTAGE: - *val = bat->design_mv; - return 0; - case SB_SPECIFICATION_INFO: - *val = bat->spec_info; - return 0; - case SB_MANUFACTURE_DATE: - *val = bat->mf_date; - return 0; - case SB_SERIAL_NUMBER: - *val = bat->sn; - return 0; - default: - /* Unknown command or return value is not word */ - return 1; - } -} - -/** Check description in emul_smart_battery.h */ -int sbat_emul_get_block_data(struct i2c_emul *emul, int cmd, uint8_t **blk, - int *len) -{ - struct sbat_emul_bat_data *bat; - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - bat = &data->bat; - - switch (cmd) { - case SB_MANUFACTURER_NAME: - *blk = bat->mf_name; - *len = bat->mf_name_len; - return 0; - case SB_DEVICE_NAME: - *blk = bat->dev_name; - *len = bat->dev_name_len; - return 0; - case SB_DEVICE_CHEMISTRY: - *blk = bat->dev_chem; - *len = bat->dev_chem_len; - return 0; - case SB_MANUFACTURER_DATA: - *blk = bat->mf_data; - *len = bat->mf_data_len; - return 0; - default: - /* Unknown command or return value is not word */ - return 1; - } -} - -/** - * @brief Append PEC to read command response if battery support it - * - * @param data Pointer to smart battery emulator data - * @param cmd Command for which PEC is calculated - */ -static void sbat_emul_append_pec(struct sbat_emul_data *data, int cmd) -{ - uint8_t pec; - - if (BATTERY_SPEC_VERSION(data->bat.spec_info) == - BATTERY_SPEC_VER_1_1_WITH_PEC) { - pec = sbat_emul_pec_head(data->common.cfg->addr, 1, cmd); - pec = cros_crc8_arg(data->msg_buf, data->num_to_read, pec); - data->msg_buf[data->num_to_read] = pec; - data->num_to_read++; - } -} - -/** Check description in emul_smart_battery.h */ -void sbat_emul_set_response(struct i2c_emul *emul, int cmd, uint8_t *buf, - int len, bool fail) -{ - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - - if (fail) { - data->bat.error_code = STATUS_CODE_UNKNOWN_ERROR; - data->num_to_read = 0; - return; - } - - data->num_to_read = MIN(len, MSG_BUF_LEN - 1); - memcpy(data->msg_buf, buf, data->num_to_read); - data->bat.error_code = STATUS_CODE_OK; - sbat_emul_append_pec(data, cmd); -} - -/** - * @brief Function which handles read messages. It expects that data->cur_cmd - * is set to command number which should be handled. It guarantee that - * data->num_to_read is set to number of bytes in data->msg_buf on - * successful handling read request. On error, data->num_to_read is - * always set to 0. - * - * @param emul Pointer to smart battery emulator - * @param reg Command selected by last write message. If data->cur_cmd is - * different than SBAT_EMUL_NO_CMD, then reg should equal to - * data->cur_cmd - * - * @return 0 on success - * @return -EIO on error - */ -static int sbat_emul_handle_read_msg(struct i2c_emul *emul, int reg) -{ - struct sbat_emul_data *data; - uint16_t word; - uint8_t *blk; - int ret, len; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - - if (data->cur_cmd == SBAT_EMUL_NO_CMD) { - /* Unexpected read message without preceding command select */ - data->bat.error_code = STATUS_CODE_UNKNOWN_ERROR; - return -EIO; - } - data->cur_cmd = SBAT_EMUL_NO_CMD; - data->num_to_read = 0; - - /* Handle commands which return word */ - ret = sbat_emul_get_word_val(emul, reg, &word); - if (ret < 0) { - return -EIO; - } - if (ret == 0) { - data->num_to_read = 2; - data->msg_buf[0] = word & 0xff; - data->msg_buf[1] = (word >> 8) & 0xff; - data->bat.error_code = STATUS_CODE_OK; - sbat_emul_append_pec(data, reg); - - return 0; - } - - /* Handle commands which return block */ - ret = sbat_emul_get_block_data(emul, reg, &blk, &len); - if (ret != 0) { - if (ret == 1) { - data->bat.error_code = STATUS_CODE_UNSUPPORTED; - LOG_ERR("Unknown read command (0x%x)", reg); - } - - return -EIO; - } - - data->num_to_read = len + 1; - data->msg_buf[0] = len; - memcpy(&data->msg_buf[1], blk, len); - data->bat.error_code = STATUS_CODE_OK; - sbat_emul_append_pec(data, reg); - - return 0; -} - -/** - * @brief Function which finalize write messages. - * - * @param emul Pointer to smart battery emulator - * @param reg First byte of write message, usually selected command - * @param bytes Number of bytes received in data->msg_buf - * - * @return 0 on success - * @return -EIO on error - */ -static int sbat_emul_finalize_write_msg(struct i2c_emul *emul, int reg, - int bytes) -{ - struct sbat_emul_bat_data *bat; - struct sbat_emul_data *data; - uint16_t word; - uint8_t pec; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - bat = &data->bat; - - /* - * Fail if: - * - there are no bytes to handle - * - there are too many bytes - * - there is command byte and only one data byte - */ - if (bytes <= 0 || bytes > 4 || bytes == 2) { - data->bat.error_code = STATUS_CODE_BADSIZE; - LOG_ERR("wrong write message size (%d)", bytes); - - return -EIO; - } - - /* There is only command for read */ - if (bytes == 1) { - data->cur_cmd = reg; - return 0; - } - - /* Handle PEC */ - data->msg_buf[0] = reg; - if (bytes == 4) { - if (BATTERY_SPEC_VERSION(data->bat.spec_info) != - BATTERY_SPEC_VER_1_1_WITH_PEC) { - data->bat.error_code = STATUS_CODE_BADSIZE; - LOG_ERR("Unexpected PEC; No support in this version"); - - return -EIO; - } - pec = sbat_emul_pec_head(data->common.cfg->addr, 0, 0); - pec = cros_crc8_arg(data->msg_buf, 3, pec); - if (pec != data->msg_buf[3]) { - data->bat.error_code = STATUS_CODE_UNKNOWN_ERROR; - LOG_ERR("Wrong PEC 0x%x != 0x%x", - pec, data->msg_buf[3]); - - return -EIO; - } - } - - word = ((int)data->msg_buf[2] << 8) | data->msg_buf[1]; - - switch (data->msg_buf[0]) { - case SB_MANUFACTURER_ACCESS: - bat->mf_access = word; - break; - case SB_REMAINING_CAPACITY_ALARM: - bat->cap_alarm = word; - break; - case SB_REMAINING_TIME_ALARM: - bat->time_alarm = word; - break; - case SB_BATTERY_MODE: - /* Allow to set only upper byte */ - bat->mode &= 0xff; - bat->mode |= word & 0xff00; - break; - case SB_AT_RATE: - bat->at_rate = word; - break; - default: - data->bat.error_code = STATUS_CODE_ACCESS_DENIED; - LOG_ERR("Unknown write command (0x%x)", data->msg_buf[0]); - - return -EIO; - } - - data->bat.error_code = STATUS_CODE_OK; - - return 0; -} - -/** - * @brief Function called for each byte of write message which is saved in - * data->msg_buf - * - * @param emul Pointer to smart battery emulator - * @param reg First byte of write message, usually selected command - * @param val Received byte of write message - * @param bytes Number of bytes already received - * - * @return 0 on success - */ -static int sbat_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - - if (bytes < MSG_BUF_LEN) { - data->msg_buf[bytes] = val; - } - - return 0; -} - -/** - * @brief Function called for each byte of read message. Byte from data->msg_buf - * is copied to read message response. - * - * @param emul Pointer to smart battery emulator - * @param reg First byte of last write message, usually selected command - * @param val Pointer where byte to read should be stored - * @param bytes Number of bytes already readed - * - * @return 0 on success - */ -static int sbat_emul_read_byte(struct i2c_emul *emul, int reg, uint8_t *val, - int bytes) -{ - struct sbat_emul_data *data; - - data = SBAT_DATA_FROM_I2C_EMUL(emul); - - if (bytes < data->num_to_read) { - *val = data->msg_buf[bytes]; - } - - return 0; -} - -/** - * @brief Get currently accessed register, which always equals to selected - * command. - * - * @param emul Pointer to smart battery emulator - * @param reg First byte of last write message, usually selected command - * @param bytes Number of bytes already handled from current message - * @param read If currently handled is read message - * - * @return Currently accessed register - */ -static int sbat_emul_access_reg(struct i2c_emul *emul, int reg, int bytes, - bool read) -{ - return reg; -} - -/* Device instantiation */ - -static struct i2c_emul_api sbat_emul_api = { - .transfer = i2c_common_emul_transfer, -}; - -/** - * @brief Set up a new Smart Battery emulator - * - * This should be called for each Smart Battery device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int sbat_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = cfg->data; - int ret; - - data->emul.api = &sbat_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - return ret; -} - -#define SMART_BATTERY_EMUL(n) \ - static struct sbat_emul_data sbat_emul_data_##n = { \ - .bat = { \ - .mf_access = DT_INST_PROP(n, mf_access), \ - .at_rate_full_mw_support = DT_INST_PROP(n, \ - at_rate_full_mw_support), \ - .spec_info = ((DT_STRING_TOKEN(DT_DRV_INST(n), \ - version) << \ - BATTERY_SPEC_VERSION_SHIFT) & \ - BATTERY_SPEC_VERSION_MASK) | \ - ((DT_INST_PROP(n, vscale) << \ - BATTERY_SPEC_VSCALE_SHIFT) & \ - BATTERY_SPEC_VSCALE_MASK) | \ - ((DT_INST_PROP(n, ipscale) << \ - BATTERY_SPEC_IPSCALE_SHIFT) & \ - BATTERY_SPEC_IPSCALE_MASK) | \ - BATTERY_SPEC_REVISION_1, \ - .mode = (DT_INST_PROP(n, \ - int_charge_controller) * \ - MODE_INTERNAL_CHARGE_CONTROLLER) | \ - (DT_INST_PROP(n, primary_battery) * \ - MODE_PRIMARY_BATTERY_SUPPORT), \ - .design_mv = DT_INST_PROP(n, design_mv), \ - .design_cap = DT_INST_PROP(n, design_cap), \ - .temp = DT_INST_PROP(n, temperature), \ - .volt = DT_INST_PROP(n, volt), \ - .cur = DT_INST_PROP(n, cur), \ - .avg_cur = DT_INST_PROP(n, avg_cur), \ - .max_error = DT_INST_PROP(n, max_error), \ - .cap = DT_INST_PROP(n, cap), \ - .full_cap = DT_INST_PROP(n, full_cap), \ - .desired_charg_cur = DT_INST_PROP(n, \ - desired_charg_cur), \ - .desired_charg_volt = DT_INST_PROP(n, \ - desired_charg_volt), \ - .cycle_count = DT_INST_PROP(n, cycle_count), \ - .sn = DT_INST_PROP(n, serial_number), \ - .mf_name = DT_INST_PROP(n, mf_name), \ - .mf_name_len = sizeof( \ - DT_INST_PROP(n, mf_name)) - 1, \ - .mf_data = DT_INST_PROP(n, mf_data), \ - .mf_data_len = sizeof( \ - DT_INST_PROP(n, mf_data)) - 1, \ - .dev_name = DT_INST_PROP(n, dev_name), \ - .dev_name_len = sizeof( \ - DT_INST_PROP(n, dev_name)) - 1, \ - .dev_chem = DT_INST_PROP(n, dev_chem), \ - .dev_chem_len = sizeof( \ - DT_INST_PROP(n, dev_chem)) - 1, \ - .mf_date = 0, \ - .cap_alarm = 0, \ - .time_alarm = 0, \ - .at_rate = 0, \ - .status = STATUS_INITIALIZED, \ - .error_code = STATUS_CODE_OK, \ - }, \ - .cur_cmd = SBAT_EMUL_NO_CMD, \ - .common = { \ - .start_write = NULL, \ - .write_byte = sbat_emul_write_byte, \ - .finish_write = sbat_emul_finalize_write_msg, \ - .start_read = sbat_emul_handle_read_msg, \ - .read_byte = sbat_emul_read_byte, \ - .finish_read = NULL, \ - .access_reg = sbat_emul_access_reg, \ - }, \ - }; \ - \ - static const struct i2c_common_emul_cfg sbat_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &sbat_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(sbat_emul_init, DT_DRV_INST(n), &sbat_emul_cfg_##n, \ - &sbat_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(SMART_BATTERY_EMUL) - -#define SMART_BATTERY_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &sbat_emul_data_##n.common.emul; - -/** Check description in emul_smart_battery.h */ -struct i2c_emul *sbat_emul_get_ptr(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(SMART_BATTERY_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_syv682x.c b/zephyr/emul/emul_syv682x.c deleted file mode 100644 index 3d76d10492..0000000000 --- a/zephyr/emul/emul_syv682x.c +++ /dev/null @@ -1,219 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_syv682x_emul - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(syv682x); -#include <stdint.h> -#include <string.h> - -#include "emul/emul_syv682x.h" - -#define EMUL_REG_COUNT (SYV682X_CONTROL_4_REG + 1) -#define EMUL_REG_IS_VALID(reg) (reg >= 0 && reg < EMUL_REG_COUNT) - -struct syv682x_emul_data { - /** I2C emulator detail */ - struct i2c_emul emul; - /** Smart battery device being emulated */ - const struct device *i2c; - /** Configuration information */ - const struct syv682x_emul_cfg *cfg; - /** Current state of all emulated SYV682x registers */ - uint8_t reg[EMUL_REG_COUNT]; - /** - * Current state of conditions affecting interrupt bits, as distinct - * from the current values of those bits stored in reg. - */ - uint8_t status_cond; - uint8_t control_4_cond; -}; - -/** Static configuration for the emulator */ -struct syv682x_emul_cfg { - /** Label of the I2C bus this emulator connects to */ - const char *i2c_label; - /** Address of smart battery on i2c bus */ - uint16_t addr; - /** Pointer to runtime data */ - struct syv682x_emul_data *data; -}; - -int syv682x_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) -{ - struct syv682x_emul_data *data; - - if (!EMUL_REG_IS_VALID(reg)) - return -EIO; - - data = CONTAINER_OF(emul, struct syv682x_emul_data, emul); - data->reg[reg] = val; - - return 0; -} - -void syv682x_emul_set_status(struct i2c_emul *emul, uint8_t val) -{ - struct syv682x_emul_data *data; - - data = CONTAINER_OF(emul, struct syv682x_emul_data, emul); - data->status_cond = val; - data->reg[SYV682X_STATUS_REG] |= val; -} - -int syv682x_emul_get_reg(struct i2c_emul *emul, int reg, uint8_t *val) -{ - struct syv682x_emul_data *data; - - if (!EMUL_REG_IS_VALID(reg)) - return -EIO; - - data = CONTAINER_OF(emul, struct syv682x_emul_data, emul); - *val = data->reg[reg]; - - return 0; -} - -/** - * Emulate an I2C transfer to an SYV682x. This handles simple reads and writes. - * - * @param emul I2C emulation information - * @param msgs List of messages to process. For 'read' messages, this function - * updates the 'buf' member with the data that was read - * @param num_msgs Number of messages to process - * @param addr Address of the I2C target device. - * - * @return 0 on success, -EIO on general input / output error - */ -static int syv682x_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs, - int num_msgs, int addr) -{ - const struct syv682x_emul_cfg *cfg; - struct syv682x_emul_data *data; - data = CONTAINER_OF(emul, struct syv682x_emul_data, emul); - cfg = data->cfg; - - if (cfg->addr != addr) { - LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr, - addr); - return -EIO; - } - - i2c_dump_msgs("emul", msgs, num_msgs, addr); - - if (num_msgs == 1) { - if (!((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE - && msgs[0].len == 2)) { - LOG_ERR("Unexpected write msgs"); - return -EIO; - } - return syv682x_emul_set_reg(emul, msgs[0].buf[0], - msgs[0].buf[1]); - } else if (num_msgs == 2) { - int ret; - int reg; - uint8_t *buf; - - if (!((msgs[0].flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE - && msgs[0].len == 1 - && (msgs[1].flags & I2C_MSG_RW_MASK) == - I2C_MSG_READ - && (msgs[1].len == 1))) { - LOG_ERR("Unexpected read msgs"); - return -EIO; - } - - reg = msgs[0].buf[0]; - buf = &msgs[1].buf[0]; - ret = syv682x_emul_get_reg(emul, reg, buf); - - switch (reg) { - /* - * These registers are clear-on-read (if the underlying - * condition has cleared). - */ - case SYV682X_STATUS_REG: - syv682x_emul_set_reg(emul, reg, data->status_cond); - break; - case SYV682X_CONTROL_4_REG: - syv682x_emul_set_reg(emul, reg, data->control_4_cond); - break; - default: - break; - } - - return ret; - } else { - LOG_ERR("Unexpected num_msgs"); - return -EIO; - } -} - -/* Device instantiation */ - -static struct i2c_emul_api syv682x_emul_api = { - .transfer = syv682x_emul_transfer, -}; - -/** - * @brief Set up a new SYV682x emulator - * - * This should be called for each SYV682x device that needs to be emulated. It - * registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int syv682x_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct syv682x_emul_cfg *cfg = emul->cfg; - struct syv682x_emul_data *data = cfg->data; - int ret; - - data->emul.api = &syv682x_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - memset(data->reg, 0, sizeof(data->reg)); - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - return ret; -} - -#define SYV682X_EMUL(n) \ - static struct syv682x_emul_data syv682x_emul_data_##n = {}; \ - static const struct syv682x_emul_cfg syv682x_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .data = &syv682x_emul_data_##n, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(syv682x_emul_init, DT_DRV_INST(n), &syv682x_emul_cfg_##n, \ - &syv682x_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(SYV682X_EMUL) - -#define SYV682X_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &syv682x_emul_data_##n.emul; - - -struct i2c_emul *syv682x_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(SYV682X_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/emul_tcs3400.c b/zephyr/emul/emul_tcs3400.c deleted file mode 100644 index 0fc432e9ff..0000000000 --- a/zephyr/emul/emul_tcs3400.c +++ /dev/null @@ -1,650 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT zephyr_tcs3400 - -#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL -#include <logging/log.h> -LOG_MODULE_REGISTER(emul_tcs); - -#include <device.h> -#include <emul.h> -#include <drivers/i2c.h> -#include <drivers/i2c_emul.h> - -#include "emul/emul_common_i2c.h" -#include "emul/emul_tcs3400.h" - -#include "driver/als_tcs3400.h" - -#define TCS_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct tcs_emul_data, common) - -/** Run-time data used by the emulator */ -struct tcs_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Value of data byte in ongoing write message */ - uint8_t write_byte; - - /** Current state of emulated TCS3400 registers */ - uint8_t reg[TCS_EMUL_REG_COUNT]; - /** Return IR value instead of clear */ - bool ir_select; - /** Internal values of light sensor registers */ - int red; - int green; - int blue; - int clear; - int ir; - - /** ID registers value */ - uint8_t revision; - uint8_t id; - - /** Return error when trying to write to RO register */ - bool error_on_ro_write; - /** Return error when trying to write 1 to reserved bit */ - bool error_on_rsvd_write; - /** Return error when trying to access MSB before LSB */ - bool error_on_msb_first; - /** - * Flag set when LSB register is accessed and cleared when MSB is - * accessed. Allows to track order of accessing data registers - */ - bool lsb_r_read; - bool lsb_g_read; - bool lsb_b_read; - bool lsb_c_ir_read; -}; - -/** Check description in emul_tcs3400.h */ -void tcs_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) -{ - struct tcs_emul_data *data; - - if (reg < TCS_EMUL_FIRST_REG || reg > TCS_EMUL_LAST_REG) { - return; - } - - reg -= TCS_EMUL_FIRST_REG; - data = TCS_DATA_FROM_I2C_EMUL(emul); - data->reg[reg] = val; -} - -/** Check description in emul_tcs3400.h */ -uint8_t tcs_emul_get_reg(struct i2c_emul *emul, int reg) -{ - struct tcs_emul_data *data; - - if (reg < TCS_EMUL_FIRST_REG || reg > TCS_EMUL_LAST_REG) { - return 0; - } - - data = TCS_DATA_FROM_I2C_EMUL(emul); - reg -= TCS_EMUL_FIRST_REG; - - return data->reg[reg]; -} - -/** Check description in emul_tcs3400.h */ -int tcs_emul_get_val(struct i2c_emul *emul, enum tcs_emul_axis axis) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case TCS_EMUL_R: - return data->red; - case TCS_EMUL_G: - return data->green; - case TCS_EMUL_B: - return data->blue; - case TCS_EMUL_C: - return data->clear; - case TCS_EMUL_IR: - return data->ir; - } - - return 0; -} - -/** Check description in emul_tcs3400.h */ -void tcs_emul_set_val(struct i2c_emul *emul, enum tcs_emul_axis axis, int val) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - switch (axis) { - case TCS_EMUL_R: - data->red = val; - break; - case TCS_EMUL_G: - data->green = val; - break; - case TCS_EMUL_B: - data->blue = val; - break; - case TCS_EMUL_C: - data->clear = val; - break; - case TCS_EMUL_IR: - data->ir = val; - break; - } -} - -/** Check description in emul_tcs3400.h */ -void tcs_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - data->error_on_ro_write = set; -} - -/** Check description in emul_tcs3400.h */ -void tcs_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - data->error_on_rsvd_write = set; -} - -/** Check description in emul_tcs3400.h */ -void tcs_emul_set_err_on_msb_first(struct i2c_emul *emul, bool set) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - data->error_on_msb_first = set; -} - -/** Mask reserved bits in registers of TCS3400 */ -static const uint8_t tcs_emul_rsvd_mask[] = { - [TCS_I2C_ENABLE - TCS_EMUL_FIRST_REG] = 0xa4, - [TCS_I2C_ATIME - TCS_EMUL_FIRST_REG] = 0x00, - [0x2] = 0xff, /* Reserved */ - [TCS_I2C_WTIME - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_AILTL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_AILTH - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_AIHTL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_AIHTH - TCS_EMUL_FIRST_REG] = 0x00, - [0x8 ... 0xb] = 0xff, /* Reserved */ - [TCS_I2C_PERS - TCS_EMUL_FIRST_REG] = 0xf0, - [TCS_I2C_CONFIG - TCS_EMUL_FIRST_REG] = 0x81, - [0xe] = 0xff, /* Reserved */ - [TCS_I2C_CONTROL - TCS_EMUL_FIRST_REG] = 0xfc, - [TCS_I2C_AUX - TCS_EMUL_FIRST_REG] = 0xdf, - [TCS_I2C_REVID - TCS_EMUL_FIRST_REG] = 0xf0, - [TCS_I2C_ID - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_STATUS - TCS_EMUL_FIRST_REG] = 0x6e, - [TCS_I2C_CDATAL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_CDATAH - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_RDATAL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_RDATAH - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_GDATAL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_GDATAH - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_BDATAL - TCS_EMUL_FIRST_REG] = 0x00, - [TCS_I2C_BDATAH - TCS_EMUL_FIRST_REG] = 0x00, -}; - -/** - * @brief Reset registers to default values - * - * @param emul Pointer to TCS3400 emulator - */ -static void tcs_emul_reset(struct i2c_emul *emul) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - data->reg[TCS_I2C_ENABLE - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_ATIME - TCS_EMUL_FIRST_REG] = 0xff; - data->reg[TCS_I2C_WTIME - TCS_EMUL_FIRST_REG] = 0xff; - data->reg[TCS_I2C_AILTL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_AILTH - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_AIHTL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_AIHTH - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_PERS - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_CONFIG - TCS_EMUL_FIRST_REG] = 0x40; - data->reg[TCS_I2C_CONTROL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_AUX - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_REVID - TCS_EMUL_FIRST_REG] = data->revision; - data->reg[TCS_I2C_ID - TCS_EMUL_FIRST_REG] = data->id; - data->reg[TCS_I2C_STATUS - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_CDATAL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_CDATAH - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_RDATAL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_RDATAH - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_GDATAL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_GDATAH - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_BDATAL - TCS_EMUL_FIRST_REG] = 0x00; - data->reg[TCS_I2C_BDATAH - TCS_EMUL_FIRST_REG] = 0x00; - - data->ir_select = false; -} - -/** - * @brief Convert gain in format of CONTROL register to multiplyer - * - * @param control Value of CONTROL register - * - * @return gain by which messured value should be multiplied - */ -static int tcs_emul_get_gain(uint8_t control) -{ - switch (control & TCS_I2C_CONTROL_MASK) { - case 0: - return 1; - case 1: - return 4; - case 2: - return 16; - case 3: - return 64; - default: - return -1; - } -} - -/** - * @brief Convert number of cycles in format of ATIME register - * - * @param atime Value of ATIME register - * - * @return cycles count that should be used to obtain light sensor values - */ -static int tcs_emul_get_cycles(uint8_t atime) -{ - return TCS_EMUL_MAX_CYCLES - (int)atime; -} - -/** - * @brief Clear all interrupt registers - * - * @param emul Pointer to TCS3400 emulator - */ -static void tcs_emul_clear_int(struct i2c_emul *emul) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - data->reg[TCS_I2C_STATUS - TCS_EMUL_FIRST_REG] = 0x00; -} - -/** - * @brief Handle I2C write message. It is checked if accessed register isn't RO - * and reserved bits are set to 0. Write set value of reg field of TCS - * emulator data ignoring reserved bits and write only bits. Some - * commands are handled specialy. - * - * @param emul Pointer to TCS3400 emulator - * @param reg Register which is written - * @param bytes Number of bytes received in this write message - * - * @return 0 on success - * @return -EIO on error - */ -static int tcs_emul_handle_write(struct i2c_emul *emul, int reg, int bytes) -{ - struct tcs_emul_data *data; - uint8_t val; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - /* This write only selected register for I2C read message */ - if (bytes < 2) { - return 0; - } - - val = data->write_byte; - - /* Register is in data->reg */ - if (reg >= TCS_EMUL_FIRST_REG && reg <= TCS_EMUL_LAST_REG) { - if (reg >= TCS_I2C_REVID && reg <= TCS_I2C_BDATAH) { - if (data->error_on_ro_write) { - LOG_ERR("Writing to reg 0x%x which is RO", reg); - return -EIO; - } - - return 0; - } - - if (reg == TCS_I2C_CONFIG && data->error_on_rsvd_write && - !(BIT(6) & val)) { - LOG_ERR("CONFIG reg bit 6 is write as 6 (writing 0x%x)", - val); - return -EIO; - } - - reg -= TCS_EMUL_FIRST_REG; - if (data->error_on_rsvd_write && - tcs_emul_rsvd_mask[reg] & val) { - LOG_ERR("Writing 0x%x to reg 0x%x with rsvd mask 0x%x", - val, reg + TCS_EMUL_FIRST_REG, - tcs_emul_rsvd_mask[reg]); - return -EIO; - } - - /* Ignore all reserved bits */ - val &= ~tcs_emul_rsvd_mask[reg]; - val |= data->reg[reg] & tcs_emul_rsvd_mask[reg]; - - data->reg[reg] = val; - - return 0; - } - - switch (reg) { - case TCS_I2C_IR: - if (data->error_on_rsvd_write && 0x7f & val) { - LOG_ERR("Writing 0x%x to reg 0x%x with rsvd mask 0x7f", - val, reg); - return -EIO; - } - data->ir_select = !!(val & BIT(7)); - break; - case TCS_I2C_IFORCE: - /* Interrupt generate is not supported */ - break; - case TCS_I2C_CICLEAR: - case TCS_I2C_AICLEAR: - tcs_emul_clear_int(emul); - break; - default: - /* Assume that other registers are RO */ - if (data->error_on_ro_write) { - LOG_ERR("Writing to reg 0x%x which is RO (unknown)", - reg); - return -EIO; - } - } - - return 0; -} - -/** - * @brief Get set light sensor value for given register using internal - * state @p val. In case of accessing MSB check if LSB was accessed first - * - * @param emul Pointer to TCS3400 emulator - * @param reg LSB or MSB register address. LSB has to be aligned to 2 - * @param lsb_read Pointer to variable which represent if last access to this - * accelerometer value was through LSB register - * @param lsb True if now accessing LSB, Flase if now accessing MSB - * @param val Internal value of accessed light sensor - * - * @return 0 on success - * @return -EIO when accessing MSB before LSB - */ -static int tcs_emul_get_reg_val(struct i2c_emul *emul, int reg, - bool *lsb_read, bool lsb, unsigned int val) -{ - struct tcs_emul_data *data; - uint64_t reg_val; - int msb_reg; - int lsb_reg; - int cycles; - int gain; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - if (lsb) { - *lsb_read = 1; - } else { - /* - * If error on first accessing MSB is set and LSB wasn't - * accessed before, then return error. - */ - if (data->error_on_msb_first && !(*lsb_read)) { - return -EIO; - } - *lsb_read = 0; - /* LSB read should set correct value */ - return 0; - } - - lsb_reg = (reg - TCS_EMUL_FIRST_REG) & ~(0x1); - msb_reg = (reg - TCS_EMUL_FIRST_REG) | 0x1; - - gain = tcs_emul_get_gain(data->reg[TCS_I2C_CONTROL - - TCS_EMUL_FIRST_REG]); - cycles = tcs_emul_get_cycles(data->reg[TCS_I2C_ATIME - - TCS_EMUL_FIRST_REG]); - /* - * Internal value is with 256 cycles and x64 gain, so divide it to get - * registers value - */ - reg_val = (uint64_t)val * cycles * gain / TCS_EMUL_MAX_CYCLES / - TCS_EMUL_MAX_GAIN; - - if (reg_val > UINT16_MAX) { - reg_val = UINT16_MAX; - } - - data->reg[lsb_reg] = reg_val & 0xff; - data->reg[msb_reg] = (reg_val >> 8) & 0xff; - - return 0; -} - -/** - * @brief Handle I2C read message. Response is obtained from reg field of TCS - * emul data. When accessing light sensor value, register data is first - * computed using internal emulator state. - * - * @param emul Pointer to TCS3400 emulator - * @param reg First register address that is accessed in this read message - * @param buf Pointer where result should be stored - * @param bytes Number of bytes already handled in this read message - * - * @return 0 on success - * @return -EIO on error - */ -static int tcs_emul_handle_read(struct i2c_emul *emul, int reg, uint8_t *buf, - int bytes) -{ - struct tcs_emul_data *data; - unsigned int c_ir; - int ret; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - reg += bytes; - - if ((reg < TCS_EMUL_FIRST_REG || reg > TCS_EMUL_LAST_REG) && - reg != TCS_I2C_IR) { - LOG_ERR("Accessing register 0x%x which cannot be read", reg); - return -EIO; - } - - switch (reg) { - case TCS_I2C_CDATAL: - /* Shouldn't fail for LSB */ - c_ir = data->ir_select ? data->ir : data->clear; - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_c_ir_read, - true, c_ir); - break; - case TCS_I2C_CDATAH: - c_ir = data->ir_select ? data->ir : data->clear; - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_c_ir_read, - false, c_ir); - if (ret) { - LOG_ERR("MSB C read before LSB C"); - return -EIO; - } - break; - case TCS_I2C_RDATAL: - /* Shouldn't fail for LSB */ - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_r_read, - true, data->red); - break; - case TCS_I2C_RDATAH: - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_r_read, - false, data->red); - if (ret) { - LOG_ERR("MSB R read before LSB R"); - return -EIO; - } - break; - case TCS_I2C_GDATAL: - /* Shouldn't fail for LSB */ - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_g_read, - true, data->green); - break; - case TCS_I2C_GDATAH: - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_g_read, - false, data->green); - if (ret) { - LOG_ERR("MSB G read before LSB G"); - return -EIO; - } - break; - case TCS_I2C_BDATAL: - /* Shouldn't fail for LSB */ - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_b_read, - true, data->blue); - break; - case TCS_I2C_BDATAH: - ret = tcs_emul_get_reg_val(emul, reg, &data->lsb_b_read, - false, data->blue); - if (ret) { - LOG_ERR("MSB B read before LSB B"); - return -EIO; - } - break; - case TCS_I2C_IR: - *buf = data->ir_select ? BIT(7) : 0; - - return 0; - } - - *buf = data->reg[reg - TCS_EMUL_FIRST_REG]; - - return 0; -} - -/** - * @brief Handle I2C write message. Check if message is not too long and saves - * data that will be stored in register - * - * @param emul Pointer to TCS3400 emulator - * @param reg Register address that is accessed - * @param val Data to write to the register - * @param bytes Number of bytes already handled in this read message - * - * @return 0 on success - * @return -EIO on error - */ -static int tcs_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, - int bytes) -{ - struct tcs_emul_data *data; - - data = TCS_DATA_FROM_I2C_EMUL(emul); - - if (bytes > 1) { - LOG_ERR("Too long write command"); - return -EIO; - } - - data->write_byte = val; - - return 0; -} - -/* Device instantiation */ - -static struct i2c_emul_api tcs_emul_api = { - .transfer = i2c_common_emul_transfer, -}; - -/** - * @brief Set up a new TCS3400 emulator - * - * This should be called for each TCS3400 device that needs to be - * emulated. It registers it with the I2C emulation controller. - * - * @param emul Emulation information - * @param parent Device to emulate - * - * @return 0 indicating success (always) - */ -static int tcs_emul_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = cfg->data; - int ret; - - data->emul.api = &tcs_emul_api; - data->emul.addr = cfg->addr; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - ret = i2c_emul_register(parent, emul->dev_label, &data->emul); - - tcs_emul_reset(&data->emul); - - return ret; -} - -#define TCS3400_EMUL(n) \ - static struct tcs_emul_data tcs_emul_data_##n = { \ - .revision = DT_INST_PROP(n, revision), \ - .id = DT_STRING_TOKEN(DT_DRV_INST(n), device_id), \ - .error_on_ro_write = DT_INST_PROP(n, error_on_ro_write),\ - .error_on_rsvd_write = DT_INST_PROP(n, \ - error_on_reserved_bit_write), \ - .error_on_msb_first = DT_INST_PROP(n, \ - error_on_msb_first_access), \ - .lsb_c_ir_read = 0, \ - .lsb_r_read = 0, \ - .lsb_g_read = 0, \ - .lsb_b_read = 0, \ - .common = { \ - .start_write = NULL, \ - .write_byte = tcs_emul_write_byte, \ - .finish_write = tcs_emul_handle_write, \ - .start_read = NULL, \ - .read_byte = tcs_emul_handle_read, \ - .finish_read = NULL, \ - .access_reg = NULL, \ - }, \ - }; \ - \ - static const struct i2c_common_emul_cfg tcs_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &tcs_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(tcs_emul_init, DT_DRV_INST(n), &tcs_emul_cfg_##n, \ - &tcs_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(TCS3400_EMUL) - -#define TCS3400_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &tcs_emul_data_##n.common.emul; - -/** Check description in emul_tcs3400.h */ -struct i2c_emul *tcs_emul_get(int ord) -{ - switch (ord) { - DT_INST_FOREACH_STATUS_OKAY(TCS3400_EMUL_CASE) - - default: - return NULL; - } -} diff --git a/zephyr/emul/i2c_mock.c b/zephyr/emul/i2c_mock.c deleted file mode 100644 index 7c3722ad2e..0000000000 --- a/zephyr/emul/i2c_mock.c +++ /dev/null @@ -1,70 +0,0 @@ -/* 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. - */ - -#define DT_DRV_COMPAT cros_i2c_mock - -#include <device.h> -#include "emul/emul_common_i2c.h" - -#include <logging/log.h> -LOG_MODULE_REGISTER(i2c_mock, CONFIG_I2C_MOCK_LOG_LEVEL); - -struct i2c_emul *i2c_mock_to_i2c_emul(const struct emul *emul) -{ - struct i2c_common_emul_data *data = emul->data; - - return &(data->emul); -} - -void i2c_mock_reset(const struct emul *emul) -{ - struct i2c_emul *i2c_emul = i2c_mock_to_i2c_emul(emul); - - 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); - i2c_common_emul_set_read_func(i2c_emul, NULL, NULL); - i2c_common_emul_set_write_func(i2c_emul, NULL, NULL); -} - -uint16_t i2c_mock_get_addr(const struct emul *emul) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - - return cfg->addr; -} - -static const struct i2c_emul_api i2c_mock_api = { - .transfer = i2c_common_emul_transfer, -}; - -static int i2c_mock_init(const struct emul *emul, - const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct i2c_common_emul_data *data = emul->data; - - data->emul.api = &i2c_mock_api; - data->emul.addr = cfg->addr; - data->emul.parent = emul; - data->i2c = parent; - data->cfg = cfg; - i2c_common_emul_init(data); - - return i2c_emul_register(parent, emul->dev_label, &data->emul); -} - -#define INIT_I2C_MOCK(n) \ - static const struct i2c_common_emul_cfg i2c_mock_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - static struct i2c_common_emul_data i2c_mock_data_##n; \ - EMUL_DEFINE(i2c_mock_init, DT_DRV_INST(n), &i2c_mock_cfg_##n, \ - &i2c_mock_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(INIT_I2C_MOCK) |