diff options
Diffstat (limited to 'zephyr/emul/emul_bma255.c')
-rw-r--r-- | zephyr/emul/emul_bma255.c | 385 |
1 files changed, 94 insertions, 291 deletions
diff --git a/zephyr/emul/emul_bma255.c b/zephyr/emul/emul_bma255.c index 073e196df8..9b6c401d0d 100644 --- a/zephyr/emul/emul_bma255.c +++ b/zephyr/emul/emul_bma255.c @@ -14,29 +14,22 @@ LOG_MODULE_REGISTER(emul_bma255); #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" -/** - * Describe if there is no ongoing I2C message or if there is message handled - * at the moment (last message doesn't ended with stop or write is not followed - * by read). - */ -enum bma_emul_msg_state { - BMA_EMUL_NONE_MSG, - BMA_EMUL_IN_WRITE, - BMA_EMUL_IN_READ -}; +#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 { - /** I2C emulator detail */ - struct i2c_emul emul; - /** BMA255 device being emulated */ - const struct device *i2c; - /** Configuration information */ - const struct bma_emul_cfg *cfg; + /** 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]; @@ -78,87 +71,9 @@ struct bma_emul_data { bool lsb_x_read; bool lsb_y_read; bool lsb_z_read; - - /** Current state of I2C bus (if emulator is handling message) */ - enum bma_emul_msg_state msg_state; - /** Number of already handled bytes in ongoing message */ - int msg_byte; - /** Register selected in last write command */ - uint8_t cur_reg; - /** Value of data byte in ongoing write message */ - uint8_t write_byte; - - /** Custom write function called on I2C write opperation */ - bma_emul_write_func write_func; - /** Data passed to custom write function */ - void *write_func_data; - /** Custom read function called on I2C read opperation */ - bma_emul_read_func read_func; - /** Data passed to custom read function */ - void *read_func_data; - - /** Control if read should fail on given register */ - int read_fail_reg; - /** Control if write should fail on given register */ - int write_fail_reg; - - /** Mutex used to control access to emulator data */ - struct k_mutex data_mtx; -}; - -/** Static configuration for the emulator */ -struct bma_emul_cfg { - /** Label of the I2C bus this emulator connects to */ - const char *i2c_label; - /** Pointer to run-time data */ - struct bma_emul_data *data; - /** Address of BMA255 on i2c bus */ - uint16_t addr; }; /** Check description in emul_bma255.h */ -int bma_emul_lock_data(struct i2c_emul *emul, k_timeout_t timeout) -{ - struct bma_emul_data *data; - - data = CONTAINER_OF(emul, struct bma_emul_data, emul); - - return k_mutex_lock(&data->data_mtx, timeout); -} - -/** Check description in emul_bma255.h */ -int bma_emul_unlock_data(struct i2c_emul *emul) -{ - struct bma_emul_data *data; - - data = CONTAINER_OF(emul, struct bma_emul_data, emul); - - return k_mutex_unlock(&data->data_mtx); -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_write_func(struct i2c_emul *emul, - bma_emul_write_func func, void *data) -{ - struct bma_emul_data *emul_data; - - emul_data = CONTAINER_OF(emul, struct bma_emul_data, emul); - emul_data->write_func = func; - emul_data->write_func_data = data; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_read_func(struct i2c_emul *emul, - bma_emul_read_func func, void *data) -{ - struct bma_emul_data *emul_data; - - emul_data = CONTAINER_OF(emul, struct bma_emul_data, emul); - emul_data->read_func = func; - emul_data->read_func_data = data; -} - -/** 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; @@ -167,7 +82,7 @@ void bma_emul_set_reg(struct i2c_emul *emul, int reg, uint8_t val) return; } - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->reg[reg] = val; } @@ -180,29 +95,11 @@ uint8_t bma_emul_get_reg(struct i2c_emul *emul, int reg) return 0; } - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); return data->reg[reg]; } -/** Check description in emul_bma255.h */ -void bma_emul_set_read_fail_reg(struct i2c_emul *emul, int reg) -{ - struct bma_emul_data *data; - - data = CONTAINER_OF(emul, struct bma_emul_data, emul); - data->read_fail_reg = reg; -} - -/** Check description in emul_bma255.h */ -void bma_emul_set_write_fail_reg(struct i2c_emul *emul, int reg) -{ - struct bma_emul_data *data; - - data = CONTAINER_OF(emul, struct bma_emul_data, emul); - data->write_fail_reg = reg; -} - /** * @brief Convert @p val to two's complement representation. It makes sure that * bit representation is correct even on platforms which represent @@ -289,7 +186,7 @@ int16_t bma_emul_get_off(struct i2c_emul *emul, int axis) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); switch (axis) { case BMA_EMUL_AXIS_X: @@ -308,7 +205,7 @@ void bma_emul_set_off(struct i2c_emul *emul, int axis, int16_t val) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); switch (axis) { case BMA_EMUL_AXIS_X: @@ -334,7 +231,7 @@ int16_t bma_emul_get_acc(struct i2c_emul *emul, int axis) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); switch (axis) { case BMA_EMUL_AXIS_X: @@ -353,7 +250,7 @@ void bma_emul_set_acc(struct i2c_emul *emul, int axis, int16_t val) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); switch (axis) { case BMA_EMUL_AXIS_X: @@ -373,7 +270,7 @@ void bma_emul_set_err_on_cal_nrdy(struct i2c_emul *emul, bool set) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->error_on_cal_trg_nrdy = set; } @@ -382,7 +279,7 @@ void bma_emul_set_err_on_cal_bad_range(struct i2c_emul *emul, bool set) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->error_on_cal_trg_bad_range = set; } @@ -391,7 +288,7 @@ void bma_emul_set_err_on_ro_write(struct i2c_emul *emul, bool set) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->error_on_ro_write = set; } @@ -400,7 +297,7 @@ void bma_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->error_on_rsvd_write = set; } @@ -409,7 +306,7 @@ void bma_emul_set_err_on_msb_first(struct i2c_emul *emul, bool set) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->error_on_msb_first = set; } @@ -491,7 +388,7 @@ static void bma_emul_restore_nvm(struct i2c_emul *emul) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); /* Restore registers values */ data->reg[BMA2x2_OFFSET_X_AXIS_ADDR] = data->nvm_x; @@ -515,7 +412,7 @@ static void bma_emul_reset(struct i2c_emul *emul) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->reg[BMA2x2_CHIP_ID_ADDR] = 0xfa; data->reg[0x01] = 0x00; /* Reserved */ @@ -622,7 +519,7 @@ static int bma_emul_handle_nvm_write(struct i2c_emul *emul, uint8_t val) struct bma_emul_data *data; uint8_t writes_rem; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); /* NVM not ready, ignore write/load requests */ if (!(data->reg[BMA2x2_EEPROM_CTRL_ADDR] & BMA2x2_EEPROM_RDY)) { @@ -665,7 +562,7 @@ static void bma_emul_clear_int(struct i2c_emul *emul) { struct bma_emul_data *data; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); data->reg[BMA2x2_STAT1_ADDR] = 0x00; data->reg[BMA2x2_STAT2_ADDR] = 0x00; @@ -687,7 +584,7 @@ static int16_t bma_emul_get_target(struct i2c_emul *emul, int axis) struct bma_emul_data *data; uint8_t target; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); target = data->reg[BMA2x2_OFC_SETTING_ADDR] >> BMA2x2_OFC_TARGET_AXIS(axis); @@ -723,7 +620,7 @@ static int bma_emul_handle_off_comp(struct i2c_emul *emul, uint8_t val) uint8_t trigger; int16_t target; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); if (val & BMA2x2_OFFSET_RESET) { data->off_x = 0; @@ -775,37 +672,35 @@ static int bma_emul_handle_off_comp(struct i2c_emul *emul, uint8_t val) * @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. Before any handling, custom function - * is called if provided. + * commands are handled specialy. * * @param emul Pointer to BMA255 emulator * @param reg Register which is written - * @param val Value being written to @p reg + * @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, uint8_t val) +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 = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); - if (data->write_func) { - ret = data->write_func(emul, reg, val, data->write_func_data); - if (ret < 0) { - return -EIO; - } else if (ret == 0) { - return 0; - } - } + val = data->write_byte; - if (data->write_fail_reg == reg || - data->write_fail_reg == BMA_EMUL_FAIL_ALL_REG) { + 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) { @@ -907,7 +802,7 @@ static int bma_emul_get_acc_val(struct i2c_emul *emul, int lsb_reg, int msb_reg; int shift; - data = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); if (lsb) { *lsb_read = 1; @@ -941,46 +836,47 @@ static int bma_emul_get_acc_val(struct i2c_emul *emul, int lsb_reg, 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. Before default handler, custom - * user read function is called if provided. + * computed using internal emulator state. * * @param emul Pointer to BMA255 emulator * @param reg Register address to read - * @param buf Pointer where resultat should be stored + * @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, char *buf) +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 = CONTAINER_OF(emul, struct bma_emul_data, emul); + data = BMA_DATA_FROM_I2C_EMUL(emul); - if (reg > BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - reg = BMA2x2_FIFO_DATA_OUTPUT_ADDR; - } - - if (data->read_func) { - ret = data->read_func(emul, reg, data->read_func_data); - if (ret < 0) { - return -EIO; - } else if (ret == 0) { - /* Immediately return value set by custom function */ - *buf = data->reg[reg]; - - return 0; - } - } - - if (data->read_fail_reg == reg || - data->read_fail_reg == BMA_EMUL_FAIL_ALL_REG) { - return -EIO; - } + reg = bma_emul_access_reg(emul, reg, bytes, true /* = read */); switch (reg) { case BMA2x2_X_AXIS_LSB_ADDR: @@ -1024,126 +920,30 @@ static int bma_emul_handle_read(struct i2c_emul *emul, int reg, char *buf) break; } - *buf = data->reg[reg]; + *val = data->reg[reg]; return 0; } /** - * @biref Emulate an I2C transfer to a BMA255 accelerometer - * - * This handles simple reads and writes + * @brief Handle I2C write message. Saves data that will be stored in register. * - * @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 + * @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 * - * @retval 0 If successful - * @retval -EIO General input / output error + * @return 0 on success + * @return -EIO on error */ -static int bma_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs, - int num_msgs, int addr) +static int bma_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val, + int bytes) { - const struct bma_emul_cfg *cfg; struct bma_emul_data *data; - int ret, i, reg; - bool read; - - data = CONTAINER_OF(emul, struct bma_emul_data, emul); - cfg = data->cfg; - if (cfg->addr != addr) { - LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr, - addr); - return -EIO; - } + data = BMA_DATA_FROM_I2C_EMUL(emul); - i2c_dump_msgs("emul", msgs, num_msgs, addr); - - for (; num_msgs > 0; num_msgs--, msgs++) { - read = msgs->flags & I2C_MSG_READ; - - switch (data->msg_state) { - case BMA_EMUL_NONE_MSG: - data->msg_byte = 0; - break; - case BMA_EMUL_IN_WRITE: - if (read) { - /* Finish write command */ - if (data->msg_byte == 2) { - k_mutex_lock(&data->data_mtx, - K_FOREVER); - ret = bma_emul_handle_write(emul, - data->cur_reg, - data->write_byte); - k_mutex_unlock(&data->data_mtx); - if (ret) { - return -EIO; - } - } - data->msg_byte = 0; - } - break; - case BMA_EMUL_IN_READ: - if (!read) { - data->msg_byte = 0; - } - break; - } - data->msg_state = read ? BMA_EMUL_IN_READ : BMA_EMUL_IN_WRITE; - - if (msgs->flags & I2C_MSG_STOP) { - data->msg_state = BMA_EMUL_NONE_MSG; - } - - if (!read) { - /* Dispatch wrtie command */ - for (i = 0; i < msgs->len; i++) { - switch (data->msg_byte) { - case 0: - data->cur_reg = msgs->buf[i]; - break; - case 1: - data->write_byte = msgs->buf[i]; - break; - default: - data->msg_state = BMA_EMUL_NONE_MSG; - LOG_ERR("Too long write command"); - return -EIO; - } - data->msg_byte++; - } - - /* Execute write command */ - if (msgs->flags & I2C_MSG_STOP && data->msg_byte == 2) { - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = bma_emul_handle_write(emul, data->cur_reg, - data->write_byte); - k_mutex_unlock(&data->data_mtx); - if (ret) { - return -EIO; - } - } - } else { - /* Dispatch read command */ - for (i = 0; i < msgs->len; i++) { - reg = data->cur_reg + data->msg_byte; - if (reg > BMA2x2_FIFO_DATA_OUTPUT_ADDR) { - reg = BMA2x2_FIFO_DATA_OUTPUT_ADDR; - } else { - data->msg_byte++; - } - k_mutex_lock(&data->data_mtx, K_FOREVER); - ret = bma_emul_handle_read(emul, reg, - &(msgs->buf[i])); - k_mutex_unlock(&data->data_mtx); - if (ret) { - return -EIO; - } - } - } - } + data->write_byte = val; return 0; } @@ -1151,7 +951,7 @@ static int bma_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs, /* Device instantiation */ static struct i2c_emul_api bma_emul_api = { - .transfer = bma_emul_transfer, + .transfer = i2c_common_emul_transfer, }; /** @@ -1168,15 +968,15 @@ static struct i2c_emul_api bma_emul_api = { static int bma_emul_init(const struct emul *emul, const struct device *parent) { - const struct bma_emul_cfg *cfg = emul->cfg; - struct bma_emul_data *data = cfg->data; + 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; - k_mutex_init(&data->data_mtx); + i2c_common_emul_init(data); ret = i2c_emul_register(parent, emul->dev_label, &data->emul); @@ -1205,17 +1005,20 @@ static int bma_emul_init(const struct emul *emul, .lsb_x_read = 0, \ .lsb_y_read = 0, \ .lsb_z_read = 0, \ - .msg_state = BMA_EMUL_NONE_MSG, \ - .cur_reg = 0, \ - .write_func = NULL, \ - .read_func = NULL, \ - .write_fail_reg = BMA_EMUL_NO_FAIL_REG, \ - .read_fail_reg = BMA_EMUL_NO_FAIL_REG, \ + .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 bma_emul_cfg bma_emul_cfg_##n = { \ + static const struct i2c_common_emul_cfg bma_emul_cfg_##n = { \ .i2c_label = DT_INST_BUS_LABEL(n), \ - .data = &bma_emul_data_##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) @@ -1223,7 +1026,7 @@ static int bma_emul_init(const struct emul *emul, DT_INST_FOREACH_STATUS_OKAY(BMA255_EMUL) #define BMA255_EMUL_CASE(n) \ - case DT_INST_DEP_ORD(n): return &bma_emul_data_##n.emul; + 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) |