summaryrefslogtreecommitdiff
path: root/zephyr/emul/emul_bb_retimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/emul/emul_bb_retimer.c')
-rw-r--r--zephyr/emul/emul_bb_retimer.c386
1 files changed, 97 insertions, 289 deletions
diff --git a/zephyr/emul/emul_bb_retimer.c b/zephyr/emul/emul_bb_retimer.c
index e016cf709e..51e60948c8 100644
--- a/zephyr/emul/emul_bb_retimer.c
+++ b/zephyr/emul/emul_bb_retimer.c
@@ -14,29 +14,19 @@ LOG_MODULE_REGISTER(emul_bb_retimer);
#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"
-/**
- * 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 bb_emul_msg_state {
- BB_EMUL_NONE_MSG,
- BB_EMUL_IN_WRITE,
- BB_EMUL_IN_READ
-};
+#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 {
- /** I2C emulator detail */
- struct i2c_emul emul;
- /** BB retimer device being emulated */
- const struct device *i2c;
- /** Configuration information */
- const struct bb_emul_cfg *cfg;
+ /** Common I2C data */
+ struct i2c_common_emul_data common;
/** Current state of all emulated BB retimer registers */
uint32_t reg[BB_RETIMER_REG_COUNT];
@@ -49,86 +39,11 @@ struct bb_emul_data {
/** Return error when trying to write 1 to reserved bit */
bool error_on_rsvd_write;
- /** Current state of I2C bus (if emulator is handling message) */
- enum bb_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 dword in ongoing i2c message */
uint32_t data_dword;
-
- /** Custom write function called on I2C write opperation */
- bb_emul_write_func write_func;
- /** Data passed to custom write function */
- void *write_func_data;
- /** Custom read function called on I2C read opperation */
- bb_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 bb_emul_cfg {
- /** Label of the I2C bus this emulator connects to */
- const char *i2c_label;
- /** Pointer to run-time data */
- struct bb_emul_data *data;
- /** Address of BB retimer on i2c bus */
- uint16_t addr;
};
/** Check description in emul_bb_retimer.h */
-int bb_emul_lock_data(struct i2c_emul *emul, k_timeout_t timeout)
-{
- struct bb_emul_data *data;
-
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
-
- return k_mutex_lock(&data->data_mtx, timeout);
-}
-
-/** Check description in emul_bb_retimer.h */
-int bb_emul_unlock_data(struct i2c_emul *emul)
-{
- struct bb_emul_data *data;
-
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
-
- return k_mutex_unlock(&data->data_mtx);
-}
-
-/** Check description in emul_bb_retimer.h */
-void bb_emul_set_write_func(struct i2c_emul *emul,
- bb_emul_write_func func, void *data)
-{
- struct bb_emul_data *emul_data;
-
- emul_data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- emul_data->write_func = func;
- emul_data->write_func_data = data;
-}
-
-/** Check description in emul_bb_retimer.h */
-void bb_emul_set_read_func(struct i2c_emul *emul,
- bb_emul_read_func func, void *data)
-{
- struct bb_emul_data *emul_data;
-
- emul_data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- emul_data->read_func = func;
- emul_data->read_func_data = data;
-}
-
-/** 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;
@@ -137,7 +52,7 @@ void bb_emul_set_reg(struct i2c_emul *emul, int reg, uint32_t val)
return;
}
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data = BB_DATA_FROM_I2C_EMUL(emul);
data->reg[reg] = val;
}
@@ -150,35 +65,17 @@ uint32_t bb_emul_get_reg(struct i2c_emul *emul, int reg)
return 0;
}
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data = BB_DATA_FROM_I2C_EMUL(emul);
return data->reg[reg];
}
/** Check description in emul_bb_retimer.h */
-void bb_emul_set_read_fail_reg(struct i2c_emul *emul, int reg)
-{
- struct bb_emul_data *data;
-
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- data->read_fail_reg = reg;
-}
-
-/** Check description in emul_bb_retimer.h */
-void bb_emul_set_write_fail_reg(struct i2c_emul *emul, int reg)
-{
- struct bb_emul_data *data;
-
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- data->write_fail_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 = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data = BB_DATA_FROM_I2C_EMUL(emul);
data->error_on_ro_write = set;
}
@@ -187,7 +84,7 @@ void bb_emul_set_err_on_rsvd_write(struct i2c_emul *emul, bool set)
{
struct bb_emul_data *data;
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ data = BB_DATA_FROM_I2C_EMUL(emul);
data->error_on_rsvd_write = set;
}
@@ -212,7 +109,7 @@ static void bb_emul_reset(struct i2c_emul *emul)
{
struct bb_emul_data *data;
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ 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;
@@ -227,25 +124,28 @@ static void bb_emul_reset(struct i2c_emul *emul)
/**
* @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. Some
- * commands are handled specialy. Before any handling, custom function
- * is called if provided.
+ * retimer emulator data ignoring reserved bits and write only bits.
*
* @param emul Pointer to BB retimer emulator
* @param reg Register which is written
- * @param val Value being written to @p reg
* @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, uint32_t val,
- int msg_len)
+static int bb_emul_handle_write(struct i2c_emul *emul, int reg, int msg_len)
{
struct bb_emul_data *data;
- int ret;
+ 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;
+ }
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
+ val = data->data_dword;
/*
* BB retimer ignores data bytes above 4 and use zeros if there is less
@@ -255,20 +155,6 @@ static int bb_emul_handle_write(struct i2c_emul *emul, int reg, uint32_t val,
LOG_WRN("Got %d bytes of WR data, expected 4", msg_len - 2);
}
- 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;
- }
- }
-
- if (data->write_fail_reg == reg ||
- data->write_fail_reg == BB_EMUL_FAIL_ALL_REG) {
- return -EIO;
- }
-
if (reg <= BB_RETIMER_REG_DEVICE_ID ||
reg >= BB_RETIMER_REG_COUNT ||
reg == BB_RETIMER_REG_TBT_CONTROL) {
@@ -297,40 +183,19 @@ static int bb_emul_handle_write(struct i2c_emul *emul, int reg, uint32_t val,
/**
* @brief Handle I2C read message. Response is obtained from reg field of bb
- * 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.
+ * emul data.
*
* @param emul Pointer to BB retimer emulator
* @param reg Register address to read
- * @param buf Pointer where result should be stored
*
* @return 0 on success
* @return -EIO on error
*/
-static int bb_emul_handle_read(struct i2c_emul *emul, int reg, uint32_t *buf)
+static int bb_emul_handle_read(struct i2c_emul *emul, int reg)
{
struct bb_emul_data *data;
- int ret;
-
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- 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 == BB_EMUL_FAIL_ALL_REG) {
- return -EIO;
- }
+ data = BB_DATA_FROM_I2C_EMUL(emul);
if (reg >= BB_RETIMER_REG_COUNT) {
LOG_ERR("Read unknown register 0x%x", reg);
@@ -338,146 +203,86 @@ static int bb_emul_handle_read(struct i2c_emul *emul, int reg, uint32_t *buf)
return -EIO;
}
- *buf = data->reg[reg];
+ data->data_dword = data->reg[reg];
return 0;
}
/**
- * @biref Emulate an I2C transfer to a BB retimer
+ * @brief Function called for each byte of write message. Data are stored
+ * in data_dword field of bb_emul_data
*
- * 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
+ * @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
*
- * @retval 0 If successful
- * @retval -EIO General input / output error
+ * @return 0 on success
*/
-static int bb_emul_transfer(struct i2c_emul *emul, struct i2c_msg *msgs,
- int num_msgs, int addr)
+static int bb_emul_write_byte(struct i2c_emul *emul, int reg, uint8_t val,
+ int bytes)
{
- const struct bb_emul_cfg *cfg;
struct bb_emul_data *data;
- int ret, i;
- bool read;
- data = CONTAINER_OF(emul, struct bb_emul_data, emul);
- cfg = data->cfg;
+ data = BB_DATA_FROM_I2C_EMUL(emul);
- if (cfg->addr != addr) {
- LOG_ERR("Address mismatch, expected %02x, got %02x", cfg->addr,
- addr);
- return -EIO;
+ 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));
}
- 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 BB_EMUL_NONE_MSG:
- data->data_dword = 0;
- data->msg_byte = 0;
- break;
- case BB_EMUL_IN_WRITE:
- if (read) {
- /* Finish write command */
- if (data->msg_byte >= 2) {
- k_mutex_lock(&data->data_mtx,
- K_FOREVER);
- ret = bb_emul_handle_write(emul,
- data->cur_reg,
- data->data_dword,
- data->msg_byte);
- k_mutex_unlock(&data->data_mtx);
- if (ret) {
- return -EIO;
- }
- }
- data->data_dword = 0;
- data->msg_byte = 0;
- }
- break;
- case BB_EMUL_IN_READ:
- if (!read) {
- data->data_dword = 0;
- data->msg_byte = 0;
- }
- break;
- }
- data->msg_state = read ? BB_EMUL_IN_READ : BB_EMUL_IN_WRITE;
+ return 0;
+}
- if (msgs->flags & I2C_MSG_STOP) {
- data->msg_state = BB_EMUL_NONE_MSG;
- }
+/**
+ * @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;
- 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:
- /*
- * BB retimer ignores size, but it
- * should be 4, so emulator check this.
- */
- if (msgs->buf[i] != 4) {
- LOG_WRN("Invalid write size");
- }
- break;
- default:
- data->data_dword |=
- (msgs->buf[i] & 0xff) <<
- (8 * (data->msg_byte - 2));
- }
- 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 = bb_emul_handle_write(emul, data->cur_reg,
- data->data_dword,
- data->msg_byte);
- k_mutex_unlock(&data->data_mtx);
- if (ret) {
- return -EIO;
- }
- }
- } else {
- /* Prepare response */
- if (data->msg_byte == 0) {
- k_mutex_lock(&data->data_mtx, K_FOREVER);
- ret = bb_emul_handle_read(emul, data->cur_reg,
- &data->data_dword);
- k_mutex_unlock(&data->data_mtx);
- if (ret) {
- return -EIO;
- }
- }
-
- for (i = 0; i < msgs->len; i++) {
- msgs->buf[i] = data->data_dword & 0xff;
- data->data_dword >>= 8;
-
- data->msg_byte++;
- }
- }
- }
+ data = BB_DATA_FROM_I2C_EMUL(emul);
+
+ *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 = bb_emul_transfer,
+ .transfer = i2c_common_emul_transfer,
};
/**
@@ -494,15 +299,15 @@ static struct i2c_emul_api bb_emul_api = {
static int bb_emul_init(const struct emul *emul,
const struct device *parent)
{
- const struct bb_emul_cfg *cfg = emul->cfg;
- struct bb_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 = &bb_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);
@@ -517,17 +322,20 @@ static int bb_emul_init(const struct emul *emul,
.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), \
- .msg_state = BB_EMUL_NONE_MSG, \
- .cur_reg = 0, \
- .write_func = NULL, \
- .read_func = NULL, \
- .write_fail_reg = BB_EMUL_NO_FAIL_REG, \
- .read_fail_reg = BB_EMUL_NO_FAIL_REG, \
+ .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 bb_emul_cfg bb_emul_cfg_##n = { \
+ static const struct i2c_common_emul_cfg bb_emul_cfg_##n = { \
.i2c_label = DT_INST_BUS_LABEL(n), \
- .data = &bb_emul_data_##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)
@@ -535,7 +343,7 @@ static int bb_emul_init(const struct emul *emul,
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.emul;
+ 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)