diff options
Diffstat (limited to 'zephyr/emul/tcpc/emul_tcpci.c')
-rw-r--r-- | zephyr/emul/tcpc/emul_tcpci.c | 965 |
1 files changed, 386 insertions, 579 deletions
diff --git a/zephyr/emul/tcpc/emul_tcpci.c b/zephyr/emul/tcpc/emul_tcpci.c index ac547be3c3..e19f7a2726 100644 --- a/zephyr/emul/tcpc/emul_tcpci.c +++ b/zephyr/emul/tcpc/emul_tcpci.c @@ -1,10 +1,8 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. +/* Copyright 2021 The ChromiumOS Authors * 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_tcpci_emul - #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(tcpci_emul, CONFIG_TCPCI_EMUL_LOG_LEVEL); @@ -13,59 +11,14 @@ LOG_MODULE_REGISTER(tcpci_emul, CONFIG_TCPCI_EMUL_LOG_LEVEL); #include <zephyr/drivers/i2c.h> #include <zephyr/drivers/i2c_emul.h> #include <zephyr/drivers/gpio/gpio_emul.h> -#include <ztest.h> +#include <zephyr/sys/byteorder.h> +#include <zephyr/ztest.h> #include "tcpm/tcpci.h" #include "emul/emul_common_i2c.h" #include "emul/tcpc/emul_tcpci.h" -#define TCPCI_DATA_FROM_I2C_EMUL(_emul) \ - CONTAINER_OF(CONTAINER_OF(_emul, struct i2c_common_emul_data, emul), \ - struct tcpci_emul_data, common) - -/** - * Number of emulated register. This include vendor registers defined in TCPCI - * specification - */ -#define TCPCI_EMUL_REG_COUNT 0x100 - - -/** Run-time data used by the emulator */ -struct tcpci_emul_data { - /** Common I2C data */ - struct i2c_common_emul_data common; - - /** Current state of all emulated TCPCI registers */ - uint8_t reg[TCPCI_EMUL_REG_COUNT]; - - /** Structures representing TX and RX buffers */ - struct tcpci_emul_msg *rx_msg; - struct tcpci_emul_msg *tx_msg; - - /** Data that should be written to register (except TX_BUFFER) */ - uint16_t write_data; - - /** 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; - - /** User function called when alert line could change */ - tcpci_emul_alert_state_func alert_callback; - /** Data passed to alert_callback */ - void *alert_callback_data; - - /** Callbacks for specific TCPCI device emulator */ - struct tcpci_emul_dev_ops *dev_ops; - /** Callbacks for TCPCI partner */ - const struct tcpci_emul_partner_ops *partner; - - /** Reference to Alert# GPIO emulator. */ - const struct device *alert_gpio_port; - gpio_pin_t alert_gpio_pin; -}; - /** * @brief Returns number of bytes in specific register * @@ -75,7 +28,6 @@ struct tcpci_emul_data { */ static int tcpci_emul_reg_bytes(int reg) { - switch (reg) { case TCPC_REG_VENDOR_ID: case TCPC_REG_PRODUCT_ID: @@ -101,10 +53,58 @@ static int tcpci_emul_reg_bytes(int reg) return 1; } +/** + * @brief Get value of given register of TCPCI + * + * @param ctx Pointer to TCPCI context + * @param reg Register address + * @param val Pointer where value should be stored + * + * @return 0 on success + * @return -EINVAL when register is out of range defined in TCPCI specification + * or val is NULL + */ +static int get_reg(const struct tcpci_ctx *ctx, int reg, uint16_t *val) +{ + int byte; + + if (reg < 0 || reg > TCPCI_EMUL_REG_COUNT || val == NULL) { + return -EINVAL; + } + + *val = 0; + + byte = tcpci_emul_reg_bytes(reg); + if (byte == 2) { + *val = sys_get_le16(&ctx->reg[reg]); + } else { + *val = ctx->reg[reg]; + } + + return 0; +} + /** Check description in emul_tcpci.h */ -int tcpci_emul_set_reg(const struct emul *emul, int reg, uint16_t val) +int tcpci_emul_get_reg(const struct emul *emul, int reg, uint16_t *val) +{ + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; + + return get_reg(ctx, reg, val); +} + +/** + * @brief Set value of given register of TCPCI + * + * @param ctx Pointer to TCPCI context + * @param reg Register address which value will be changed + * @param val New value of the register + * + * @return 0 on success + * @return -EINVAL when register is out of range defined in TCPCI specification + */ +static int set_reg(struct tcpci_ctx *ctx, int reg, uint16_t val) { - struct tcpci_emul_data *data = emul->data; uint16_t update_alert = 0; uint16_t alert; int byte; @@ -130,82 +130,70 @@ int tcpci_emul_set_reg(const struct emul *emul, int reg, uint16_t val) } if (update_alert != 0) { - tcpci_emul_get_reg(emul, TCPC_REG_ALERT, &alert); - tcpci_emul_set_reg(emul, TCPC_REG_ALERT, alert | update_alert); + get_reg(ctx, TCPC_REG_ALERT, &alert); + set_reg(ctx, TCPC_REG_ALERT, alert | update_alert); } - for (byte = tcpci_emul_reg_bytes(reg); byte > 0; byte--) { - data->reg[reg] = val & 0xff; - val >>= 8; - reg++; + byte = tcpci_emul_reg_bytes(reg); + if (byte == 2) { + sys_put_le16(val, &ctx->reg[reg]); + } else { + ctx->reg[reg] = val; } return 0; } /** Check description in emul_tcpci.h */ -int tcpci_emul_get_reg(const struct emul *emul, int reg, uint16_t *val) +int tcpci_emul_set_reg(const struct emul *emul, int reg, uint16_t val) { - struct tcpci_emul_data *data = emul->data; - int byte; - - if (reg < 0 || reg > TCPCI_EMUL_REG_COUNT || val == NULL) { - return -EINVAL; - } - - *val = 0; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; - byte = tcpci_emul_reg_bytes(reg); - for (byte -= 1; byte >= 0; byte--) { - *val <<= 8; - *val |= data->reg[reg + byte]; - } - - return 0; + return set_reg(ctx, reg, val); } /** * @brief Check if alert line should be active based on alert registers and * masks * - * @param emul Pointer to TCPCI emulator + * @param ctx Pointer to TCPCI context * * @return State of alert line */ -static bool tcpci_emul_check_int(const struct emul *emul) +static bool tcpci_emul_check_int(const struct tcpci_ctx *ctx) { - struct tcpci_emul_data *data = emul->data; uint16_t alert_mask; uint16_t alert; - tcpci_emul_get_reg(emul, TCPC_REG_ALERT, &alert); - tcpci_emul_get_reg(emul, TCPC_REG_ALERT_MASK, &alert_mask); + get_reg(ctx, TCPC_REG_ALERT, &alert); + get_reg(ctx, TCPC_REG_ALERT_MASK, &alert_mask); /* * For nested interrupts alert group bit and alert register bit has to * be unmasked */ if (alert & alert_mask & TCPC_REG_ALERT_ALERT_EXT && - data->reg[TCPC_REG_ALERT_EXT] & - data->reg[TCPC_REG_ALERT_EXTENDED_MASK]) { + ctx->reg[TCPC_REG_ALERT_EXT] & + ctx->reg[TCPC_REG_ALERT_EXTENDED_MASK]) { return true; } if (alert & alert_mask & TCPC_REG_ALERT_EXT_STATUS && - data->reg[TCPC_REG_EXT_STATUS] & - data->reg[TCPC_REG_EXT_STATUS_MASK]) { + ctx->reg[TCPC_REG_EXT_STATUS] & + ctx->reg[TCPC_REG_EXT_STATUS_MASK]) { return true; } if (alert & alert_mask & TCPC_REG_ALERT_FAULT && - data->reg[TCPC_REG_FAULT_STATUS] & - data->reg[TCPC_REG_FAULT_STATUS_MASK]) { + ctx->reg[TCPC_REG_FAULT_STATUS] & + ctx->reg[TCPC_REG_FAULT_STATUS_MASK]) { return true; } if (alert & alert_mask & TCPC_REG_ALERT_POWER_STATUS && - data->reg[TCPC_REG_POWER_STATUS] & - data->reg[TCPC_REG_POWER_STATUS_MASK]) { + ctx->reg[TCPC_REG_POWER_STATUS] & + ctx->reg[TCPC_REG_POWER_STATUS_MASK]) { return true; } @@ -222,34 +210,34 @@ static bool tcpci_emul_check_int(const struct emul *emul) /** * @brief If alert callback is provided, call it with current alert line state * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * * @return 0 for success, or non-0 for errors. */ static int tcpci_emul_alert_changed(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; int rc; - bool alert_is_active = tcpci_emul_check_int(emul); + bool alert_is_active = tcpci_emul_check_int(ctx); /** Trigger GPIO. */ - if (data->alert_gpio_port != NULL) { + if (ctx->alert_gpio_port != NULL) { /* Triggers on edge falling, so set to 0 when there is an alert. */ - rc = gpio_emul_input_set(data->alert_gpio_port, - data->alert_gpio_pin, + rc = gpio_emul_input_set(ctx->alert_gpio_port, + ctx->alert_gpio_pin, alert_is_active ? 0 : 1); if (rc != 0) return rc; } /* Nothing to do */ - if (data->alert_callback == NULL) { + if (ctx->alert_callback == NULL) { return 0; } - data->alert_callback(emul, alert_is_active, - data->alert_callback_data); + ctx->alert_callback(emul, alert_is_active, ctx->alert_callback_data); return 0; } @@ -257,31 +245,32 @@ static int tcpci_emul_alert_changed(const struct emul *emul) * @brief Load next rx message and inform partner which message was consumed * by TCPC * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * * @return 0 when there is no new message to load * @return 1 when new rx message is loaded */ static int tcpci_emul_get_next_rx_msg(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; struct tcpci_emul_msg *consumed_msg; - if (data->rx_msg == NULL) { + if (ctx->rx_msg == NULL) { return 0; } - consumed_msg = data->rx_msg; - data->rx_msg = consumed_msg->next; + consumed_msg = ctx->rx_msg; + ctx->rx_msg = consumed_msg->next; /* Inform partner */ - if (data->partner && data->partner->rx_consumed) { - data->partner->rx_consumed(emul, data->partner, consumed_msg); + if (ctx->partner && ctx->partner->rx_consumed) { + ctx->partner->rx_consumed(emul, ctx->partner, consumed_msg); } /* Prepare new loaded message */ - if (data->rx_msg) { - data->rx_msg->idx = 0; + if (ctx->rx_msg) { + ctx->rx_msg->idx = 0; return 1; } @@ -293,17 +282,15 @@ static int tcpci_emul_get_next_rx_msg(const struct emul *emul) * @brief Reset mask registers that are reset upon receiving or transmitting * Hard Reset message. * - * @param emul Pointer to TCPCI emulator + * @param ctx Pointer to TCPCI context */ -static void tcpci_emul_reset_mask_regs(const struct emul *emul) +static void tcpci_emul_reset_mask_regs(struct tcpci_ctx *ctx) { - struct tcpci_emul_data *data = emul->data; - - data->reg[TCPC_REG_ALERT_MASK] = 0xff; - data->reg[TCPC_REG_ALERT_MASK + 1] = 0x7f; - data->reg[TCPC_REG_POWER_STATUS_MASK] = 0xff; - data->reg[TCPC_REG_EXT_STATUS_MASK] = 0x01; - data->reg[TCPC_REG_ALERT_EXTENDED_MASK] = 0x07; + ctx->reg[TCPC_REG_ALERT_MASK] = 0xff; + ctx->reg[TCPC_REG_ALERT_MASK + 1] = 0x7f; + ctx->reg[TCPC_REG_POWER_STATUS_MASK] = 0xff; + ctx->reg[TCPC_REG_EXT_STATUS_MASK] = 0x01; + ctx->reg[TCPC_REG_ALERT_EXTENDED_MASK] = 0x07; } /** @@ -311,11 +298,14 @@ static void tcpci_emul_reset_mask_regs(const struct emul *emul) * delivery (clear RECEIVE_DETECT register and clear already received * messages in buffer) * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator */ static void tcpci_emul_disable_pd_msg_delivery(const struct emul *emul) { - tcpci_emul_set_reg(emul, TCPC_REG_RX_DETECT, 0); + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; + + set_reg(ctx, TCPC_REG_RX_DETECT, 0); /* Clear received messages */ while (tcpci_emul_get_next_rx_msg(emul)) ; @@ -325,7 +315,8 @@ static void tcpci_emul_disable_pd_msg_delivery(const struct emul *emul) int tcpci_emul_add_rx_msg(const struct emul *emul, struct tcpci_emul_msg *rx_msg, bool alert) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t rx_detect_mask; uint16_t rx_detect; uint16_t dev_cap_2; @@ -333,13 +324,13 @@ int tcpci_emul_add_rx_msg(const struct emul *emul, int rc; /* Acquire lock to prevent race conditions with TCPM accessing I2C */ - rc = i2c_common_emul_lock_data(&data->common.emul, K_FOREVER); + rc = i2c_common_emul_lock_data(&ctx->common, K_FOREVER); if (rc != 0) { LOG_ERR("Failed to acquire TCPCI lock"); return rc; } - switch (rx_msg->type) { + switch (rx_msg->sop_type) { case TCPCI_MSG_SOP: rx_detect_mask = TCPC_REG_RX_DETECT_SOP; break; @@ -362,65 +353,66 @@ int tcpci_emul_add_rx_msg(const struct emul *emul, rx_detect_mask = TCPC_REG_RX_DETECT_CABLE_RST; break; default: - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return -EINVAL; } - tcpci_emul_get_reg(emul, TCPC_REG_RX_DETECT, &rx_detect); + get_reg(ctx, TCPC_REG_RX_DETECT, &rx_detect); if (!(rx_detect & rx_detect_mask)) { /* * TCPCI will not respond with GoodCRC, so from partner emulator * point of view it failed to send message */ - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return TCPCI_EMUL_TX_FAILED; } - tcpci_emul_get_reg(emul, TCPC_REG_ALERT, &alert_reg); + get_reg(ctx, TCPC_REG_ALERT, &alert_reg); /* Handle HardReset */ - if (rx_msg->type == TCPCI_MSG_TX_HARD_RESET) { + if (rx_msg->sop_type == TCPCI_MSG_TX_HARD_RESET) { tcpci_emul_disable_pd_msg_delivery(emul); - tcpci_emul_reset_mask_regs(emul); + tcpci_emul_reset_mask_regs(ctx); alert_reg |= TCPC_REG_ALERT_RX_HARD_RST; - tcpci_emul_set_reg(emul, TCPC_REG_ALERT, alert_reg); + set_reg(ctx, TCPC_REG_ALERT, alert_reg); rc = tcpci_emul_alert_changed(emul); - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return rc; } /* Handle CableReset */ - if (rx_msg->type == TCPCI_MSG_CABLE_RESET) { + if (rx_msg->sop_type == TCPCI_MSG_CABLE_RESET) { tcpci_emul_disable_pd_msg_delivery(emul); /* Rest of CableReset handling is the same as SOP* message */ } - if (data->rx_msg == NULL) { - tcpci_emul_get_reg(emul, TCPC_REG_DEV_CAP_2, &dev_cap_2); + if (ctx->rx_msg == NULL) { + get_reg(ctx, TCPC_REG_DEV_CAP_2, &dev_cap_2); if ((!(dev_cap_2 & TCPC_REG_DEV_CAP_2_LONG_MSG) && - rx_msg->cnt > 31) || rx_msg->cnt > 265) { + rx_msg->cnt > 31) || + rx_msg->cnt > 265) { LOG_ERR("Too long first message (%d)", rx_msg->cnt); - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return -EINVAL; } - data->rx_msg = rx_msg; - } else if (data->rx_msg->next == NULL) { + ctx->rx_msg = rx_msg; + } else if (ctx->rx_msg->next == NULL) { if (rx_msg->cnt > 31) { LOG_ERR("Too long second message (%d)", rx_msg->cnt); - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return -EINVAL; } - data->rx_msg->next = rx_msg; + ctx->rx_msg->next = rx_msg; if (alert) { alert_reg |= TCPC_REG_ALERT_RX_BUF_OVF; } } else { LOG_ERR("Cannot setup third message"); - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return -EINVAL; } @@ -430,11 +422,11 @@ int tcpci_emul_add_rx_msg(const struct emul *emul, } alert_reg |= TCPC_REG_ALERT_RX_STATUS; - tcpci_emul_set_reg(emul, TCPC_REG_ALERT, alert_reg); + set_reg(ctx, TCPC_REG_ALERT, alert_reg); rc = tcpci_emul_alert_changed(emul); if (rc != 0) { - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return rc; } } @@ -442,16 +434,17 @@ int tcpci_emul_add_rx_msg(const struct emul *emul, rx_msg->next = NULL; rx_msg->idx = 0; - i2c_common_emul_unlock_data(&data->common.emul); + i2c_common_emul_unlock_data(&ctx->common); return TCPCI_EMUL_TX_SUCCESS; } /** Check description in emul_tcpci.h */ struct tcpci_emul_msg *tcpci_emul_get_tx_msg(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; - return data->tx_msg; + return ctx->tx_msg; } /** Check description in emul_tcpci.h */ @@ -461,43 +454,36 @@ void tcpci_emul_set_rev(const struct emul *emul, enum tcpci_emul_rev rev) case TCPCI_EMUL_REV1_0_VER1_0: tcpci_emul_set_reg(emul, TCPC_REG_PD_INT_REV, (TCPC_REG_PD_INT_REV_REV_1_0 << 8) | - TCPC_REG_PD_INT_REV_VER_1_0); + TCPC_REG_PD_INT_REV_VER_1_0); return; case TCPCI_EMUL_REV2_0_VER1_1: tcpci_emul_set_reg(emul, TCPC_REG_PD_INT_REV, (TCPC_REG_PD_INT_REV_REV_2_0 << 8) | - TCPC_REG_PD_INT_REV_VER_1_1); + TCPC_REG_PD_INT_REV_VER_1_1); return; } } /** Check description in emul_tcpci.h */ -void tcpci_emul_set_dev_ops(const struct emul *emul, - struct tcpci_emul_dev_ops *dev_ops) -{ - struct tcpci_emul_data *data = emul->data; - - data->dev_ops = dev_ops; -} - -/** Check description in emul_tcpci.h */ void tcpci_emul_set_alert_callback(const struct emul *emul, tcpci_emul_alert_state_func alert_callback, void *alert_callback_data) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; - data->alert_callback = alert_callback; - data->alert_callback_data = alert_callback_data; + ctx->alert_callback = alert_callback; + ctx->alert_callback_data = alert_callback_data; } /** Check description in emul_tcpci.h */ void tcpci_emul_set_partner_ops(const struct emul *emul, const struct tcpci_emul_partner_ops *partner) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; - data->partner = partner; + ctx->partner = partner; } /** @@ -508,9 +494,9 @@ void tcpci_emul_set_partner_ops(const struct emul *emul, * * @return Voltage visible at CC resistor side */ -static enum tcpc_cc_voltage_status tcpci_emul_detected_volt_for_res( - enum tcpc_cc_pull res, - enum tcpc_cc_voltage_status volt) +static enum tcpc_cc_voltage_status +tcpci_emul_detected_volt_for_res(enum tcpc_cc_pull res, + enum tcpc_cc_voltage_status volt) { switch (res) { case TYPEC_CC_RD: @@ -545,6 +531,8 @@ int tcpci_emul_connect_partner(const struct emul *emul, enum tcpc_cc_voltage_status partner_cc2, enum tcpc_cc_polarity polarity) { + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t cc_status, alert, role_ctrl, power_status; enum tcpc_cc_voltage_status cc1_v, cc2_v; enum tcpc_cc_pull cc1_r, cc2_r; @@ -557,7 +545,7 @@ int tcpci_emul_connect_partner(const struct emul *emul, cc2_v = partner_cc1; } - tcpci_emul_get_reg(emul, TCPC_REG_CC_STATUS, &cc_status); + get_reg(ctx, TCPC_REG_CC_STATUS, &cc_status); if (TCPC_REG_CC_STATUS_LOOK4CONNECTION(cc_status)) { /* Change resistors values in case of DRP toggling */ if (partner_power_role == PD_ROLE_SOURCE) { @@ -571,7 +559,7 @@ int tcpci_emul_connect_partner(const struct emul *emul, } } else { /* Use role control resistors values otherwise */ - tcpci_emul_get_reg(emul, TCPC_REG_ROLE_CTRL, &role_ctrl); + get_reg(ctx, TCPC_REG_ROLE_CTRL, &role_ctrl); cc1_r = TCPC_REG_ROLE_CTRL_CC1(role_ctrl); cc2_r = TCPC_REG_ROLE_CTRL_CC2(role_ctrl); } @@ -581,23 +569,20 @@ int tcpci_emul_connect_partner(const struct emul *emul, /* If CC status is TYPEC_CC_VOLT_RP_*, then BIT(2) is ignored */ cc_status = TCPC_REG_CC_STATUS_SET( - partner_power_role == PD_ROLE_SOURCE ? 1 : 0, - cc2_v, cc1_v); - tcpci_emul_set_reg(emul, TCPC_REG_CC_STATUS, cc_status); - tcpci_emul_get_reg(emul, TCPC_REG_ALERT, &alert); - tcpci_emul_set_reg(emul, TCPC_REG_ALERT, - alert | TCPC_REG_ALERT_CC_STATUS); + partner_power_role == PD_ROLE_SOURCE ? 1 : 0, cc2_v, cc1_v); + set_reg(ctx, TCPC_REG_CC_STATUS, cc_status); + get_reg(ctx, TCPC_REG_ALERT, &alert); + set_reg(ctx, TCPC_REG_ALERT, alert | TCPC_REG_ALERT_CC_STATUS); if (partner_power_role == PD_ROLE_SOURCE) { - tcpci_emul_get_reg(emul, TCPC_REG_POWER_STATUS, &power_status); + get_reg(ctx, TCPC_REG_POWER_STATUS, &power_status); if (power_status & TCPC_REG_POWER_STATUS_VBUS_DET) { /* * Set TCPCI emulator VBUS to present (connected, * above 4V) only if VBUS detection is enabled */ - tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS, - TCPC_REG_POWER_STATUS_VBUS_PRES | - power_status); + set_reg(ctx, TCPC_REG_POWER_STATUS, + TCPC_REG_POWER_STATUS_VBUS_PRES | power_status); } } @@ -609,32 +594,33 @@ int tcpci_emul_connect_partner(const struct emul *emul, /** Check description in emul_tcpci.h */ int tcpci_emul_disconnect_partner(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t power_status; uint16_t val; uint16_t term; int rc; tcpci_emul_disable_pd_msg_delivery(emul); - if (data->partner && data->partner->disconnect) { - data->partner->disconnect(emul, data->partner); + if (ctx->partner && ctx->partner->disconnect) { + ctx->partner->disconnect(emul, ctx->partner); } - data->partner = NULL; + ctx->partner = NULL; /* Set both CC lines to open to indicate disconnect. */ - rc = tcpci_emul_get_reg(emul, TCPC_REG_CC_STATUS, &val); + rc = get_reg(ctx, TCPC_REG_CC_STATUS, &val); if (rc != 0) return rc; term = TCPC_REG_CC_STATUS_TERM(val); - rc = tcpci_emul_set_reg(emul, TCPC_REG_CC_STATUS, - TCPC_REG_CC_STATUS_SET(term, TYPEC_CC_VOLT_OPEN, - TYPEC_CC_VOLT_OPEN)); + rc = set_reg(ctx, TCPC_REG_CC_STATUS, + TCPC_REG_CC_STATUS_SET(term, TYPEC_CC_VOLT_OPEN, + TYPEC_CC_VOLT_OPEN)); if (rc != 0) return rc; - data->reg[TCPC_REG_ALERT] |= TCPC_REG_ALERT_CC_STATUS; + ctx->reg[TCPC_REG_ALERT] |= TCPC_REG_ALERT_CC_STATUS; rc = tcpci_emul_alert_changed(emul); if (rc != 0) return rc; @@ -644,10 +630,10 @@ int tcpci_emul_disconnect_partner(const struct emul *emul) */ /* Clear VBUS present in case if source partner is disconnected */ - tcpci_emul_get_reg(emul, TCPC_REG_POWER_STATUS, &power_status); + get_reg(ctx, TCPC_REG_POWER_STATUS, &power_status); if (power_status & TCPC_REG_POWER_STATUS_VBUS_PRES) { power_status &= ~TCPC_REG_POWER_STATUS_VBUS_PRES; - tcpci_emul_set_reg(emul, TCPC_REG_POWER_STATUS, power_status); + set_reg(ctx, TCPC_REG_POWER_STATUS, power_status); } return 0; @@ -657,6 +643,8 @@ int tcpci_emul_disconnect_partner(const struct emul *emul) void tcpci_emul_partner_msg_status(const struct emul *emul, enum tcpci_emul_tx_status status) { + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t alert; uint16_t tx_status_alert; @@ -679,110 +667,108 @@ void tcpci_emul_partner_msg_status(const struct emul *emul, return; } - tcpci_emul_get_reg(emul, TCPC_REG_ALERT, &alert); - tcpci_emul_set_reg(emul, TCPC_REG_ALERT, alert | tx_status_alert); + get_reg(ctx, TCPC_REG_ALERT, &alert); + set_reg(ctx, TCPC_REG_ALERT, alert | tx_status_alert); tcpci_emul_alert_changed(emul); } /** Mask reserved bits in each register of TCPCI */ static const uint8_t tcpci_emul_rsvd_mask[] = { - [TCPC_REG_VENDOR_ID] = 0x00, - [TCPC_REG_VENDOR_ID + 1] = 0x00, - [TCPC_REG_PRODUCT_ID] = 0x00, - [TCPC_REG_PRODUCT_ID + 1] = 0x00, - [TCPC_REG_BCD_DEV] = 0x00, - [TCPC_REG_BCD_DEV + 1] = 0xff, - [TCPC_REG_TC_REV] = 0x00, - [TCPC_REG_TC_REV + 1] = 0x00, - [TCPC_REG_PD_REV] = 0x00, - [TCPC_REG_PD_REV + 1] = 0x00, - [TCPC_REG_PD_INT_REV] = 0x00, - [TCPC_REG_PD_INT_REV + 1] = 0x00, - [0x0c ... 0x0f] = 0xff, /* Reserved */ - [TCPC_REG_ALERT] = 0x00, - [TCPC_REG_ALERT + 1] = 0x00, - [TCPC_REG_ALERT_MASK] = 0x00, - [TCPC_REG_ALERT_MASK + 1] = 0x00, - [TCPC_REG_POWER_STATUS_MASK] = 0x00, - [TCPC_REG_FAULT_STATUS_MASK] = 0x00, - [TCPC_REG_EXT_STATUS_MASK] = 0xfe, - [TCPC_REG_ALERT_EXTENDED_MASK] = 0xf8, - [TCPC_REG_CONFIG_STD_OUTPUT] = 0x00, - [TCPC_REG_TCPC_CTRL] = 0x00, - [TCPC_REG_ROLE_CTRL] = 0x80, - [TCPC_REG_FAULT_CTRL] = 0x80, - [TCPC_REG_POWER_CTRL] = 0x00, - [TCPC_REG_CC_STATUS] = 0xc0, - [TCPC_REG_POWER_STATUS] = 0x00, - [TCPC_REG_FAULT_STATUS] = 0x00, - [TCPC_REG_EXT_STATUS] = 0xfe, - [TCPC_REG_ALERT_EXT] = 0xf8, - [0x22] = 0xff, /* Reserved */ - [TCPC_REG_COMMAND] = 0x00, - [TCPC_REG_DEV_CAP_1] = 0x00, - [TCPC_REG_DEV_CAP_1 + 1] = 0x00, - [TCPC_REG_DEV_CAP_2] = 0x80, - [TCPC_REG_DEV_CAP_2 + 1] = 0x00, - [TCPC_REG_STD_INPUT_CAP] = 0xe0, - [TCPC_REG_STD_OUTPUT_CAP] = 0x00, - [TCPC_REG_CONFIG_EXT_1] = 0xfc, - [0x2b] = 0xff, /* Reserved */ - [TCPC_REG_GENERIC_TIMER] = 0x00, - [TCPC_REG_GENERIC_TIMER + 1] = 0x00, - [TCPC_REG_MSG_HDR_INFO] = 0xe0, - [TCPC_REG_RX_DETECT] = 0x00, - [TCPC_REG_RX_BUFFER ... 0x4f] = 0x00, - [TCPC_REG_TRANSMIT ... 0x69] = 0x00, - [TCPC_REG_VBUS_VOLTAGE] = 0xf0, - [TCPC_REG_VBUS_VOLTAGE + 1] = 0x00, - [TCPC_REG_VBUS_SINK_DISCONNECT_THRESH] = 0x00, - [TCPC_REG_VBUS_SINK_DISCONNECT_THRESH + 1] = 0xfc, - [TCPC_REG_VBUS_STOP_DISCHARGE_THRESH] = 0x00, - [TCPC_REG_VBUS_STOP_DISCHARGE_THRESH + 1] = 0xfc, - [TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG] = 0x00, - [TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG + 1] = 0xfc, - [TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG] = 0x00, - [TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG + 1] = 0xfc, - [TCPC_REG_VBUS_NONDEFAULT_TARGET] = 0x00, - [TCPC_REG_VBUS_NONDEFAULT_TARGET + 1] = 0x00, - [0x7c ... 0x7f] = 0xff, /* Reserved */ - [0x80 ... TCPCI_EMUL_REG_COUNT - 1] = 0x00, + [TCPC_REG_VENDOR_ID] = 0x00, + [TCPC_REG_VENDOR_ID + 1] = 0x00, + [TCPC_REG_PRODUCT_ID] = 0x00, + [TCPC_REG_PRODUCT_ID + 1] = 0x00, + [TCPC_REG_BCD_DEV] = 0x00, + [TCPC_REG_BCD_DEV + 1] = 0xff, + [TCPC_REG_TC_REV] = 0x00, + [TCPC_REG_TC_REV + 1] = 0x00, + [TCPC_REG_PD_REV] = 0x00, + [TCPC_REG_PD_REV + 1] = 0x00, + [TCPC_REG_PD_INT_REV] = 0x00, + [TCPC_REG_PD_INT_REV + 1] = 0x00, + [0x0c ... 0x0f] = 0xff, /* Reserved */ + [TCPC_REG_ALERT] = 0x00, + [TCPC_REG_ALERT + 1] = 0x00, + [TCPC_REG_ALERT_MASK] = 0x00, + [TCPC_REG_ALERT_MASK + 1] = 0x00, + [TCPC_REG_POWER_STATUS_MASK] = 0x00, + [TCPC_REG_FAULT_STATUS_MASK] = 0x00, + [TCPC_REG_EXT_STATUS_MASK] = 0xfe, + [TCPC_REG_ALERT_EXTENDED_MASK] = 0xf8, + [TCPC_REG_CONFIG_STD_OUTPUT] = 0x00, + [TCPC_REG_TCPC_CTRL] = 0x00, + [TCPC_REG_ROLE_CTRL] = 0x80, + [TCPC_REG_FAULT_CTRL] = 0x80, + [TCPC_REG_POWER_CTRL] = 0x00, + [TCPC_REG_CC_STATUS] = 0xc0, + [TCPC_REG_POWER_STATUS] = 0x00, + [TCPC_REG_FAULT_STATUS] = 0x00, + [TCPC_REG_EXT_STATUS] = 0xfe, + [TCPC_REG_ALERT_EXT] = 0xf8, + [0x22] = 0xff, /* Reserved */ + [TCPC_REG_COMMAND] = 0x00, + [TCPC_REG_DEV_CAP_1] = 0x00, + [TCPC_REG_DEV_CAP_1 + 1] = 0x00, + [TCPC_REG_DEV_CAP_2] = 0x80, + [TCPC_REG_DEV_CAP_2 + 1] = 0x00, + [TCPC_REG_STD_INPUT_CAP] = 0xe0, + [TCPC_REG_STD_OUTPUT_CAP] = 0x00, + [TCPC_REG_CONFIG_EXT_1] = 0xfc, + [0x2b] = 0xff, /* Reserved */ + [TCPC_REG_GENERIC_TIMER] = 0x00, + [TCPC_REG_GENERIC_TIMER + 1] = 0x00, + [TCPC_REG_MSG_HDR_INFO] = 0xe0, + [TCPC_REG_RX_DETECT] = 0x00, + [TCPC_REG_RX_BUFFER... 0x4f] = 0x00, + [TCPC_REG_TRANSMIT... 0x69] = 0x00, + [TCPC_REG_VBUS_VOLTAGE] = 0xf0, + [TCPC_REG_VBUS_VOLTAGE + 1] = 0x00, + [TCPC_REG_VBUS_SINK_DISCONNECT_THRESH] = 0x00, + [TCPC_REG_VBUS_SINK_DISCONNECT_THRESH + 1] = 0xfc, + [TCPC_REG_VBUS_STOP_DISCHARGE_THRESH] = 0x00, + [TCPC_REG_VBUS_STOP_DISCHARGE_THRESH + 1] = 0xfc, + [TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG] = 0x00, + [TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG + 1] = 0xfc, + [TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG] = 0x00, + [TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG + 1] = 0xfc, + [TCPC_REG_VBUS_NONDEFAULT_TARGET] = 0x00, + [TCPC_REG_VBUS_NONDEFAULT_TARGET + 1] = 0x00, + [0x7c ... 0x7f] = 0xff, /* Reserved */ + [0x80 ... TCPCI_EMUL_REG_COUNT - 1] = 0x00, }; - /** * @brief Reset role control and header info registers to default values. * - * @param emul Pointer to TCPCI emulator + * @param ctx Pointer to TCPCI context */ -static void tcpci_emul_reset_role_ctrl(const struct emul *emul) +static void tcpci_emul_reset_role_ctrl(struct tcpci_ctx *ctx) { - struct tcpci_emul_data *data = emul->data; uint16_t dev_cap_1; - tcpci_emul_get_reg(emul, TCPC_REG_DEV_CAP_1, &dev_cap_1); + get_reg(ctx, TCPC_REG_DEV_CAP_1, &dev_cap_1); switch (dev_cap_1 & TCPC_REG_DEV_CAP_1_PWRROLE_MASK) { case TCPC_REG_DEV_CAP_1_PWRROLE_SRC_OR_SNK: case TCPC_REG_DEV_CAP_1_PWRROLE_SNK: case TCPC_REG_DEV_CAP_1_PWRROLE_SNK_ACC: - data->reg[TCPC_REG_ROLE_CTRL] = 0x0a; - data->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; + ctx->reg[TCPC_REG_ROLE_CTRL] = 0x0a; + ctx->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; break; case TCPC_REG_DEV_CAP_1_PWRROLE_SRC: /* Dead batter */ - data->reg[TCPC_REG_ROLE_CTRL] = 0x05; - data->reg[TCPC_REG_MSG_HDR_INFO] = 0x0d; + ctx->reg[TCPC_REG_ROLE_CTRL] = 0x05; + ctx->reg[TCPC_REG_MSG_HDR_INFO] = 0x0d; break; case TCPC_REG_DEV_CAP_1_PWRROLE_DRP: /* Dead batter and dbg acc ind */ - data->reg[TCPC_REG_ROLE_CTRL] = 0x4a; - data->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; + ctx->reg[TCPC_REG_ROLE_CTRL] = 0x4a; + ctx->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; break; case TCPC_REG_DEV_CAP_1_PWRROLE_SRC_SNK_DRP_ADPT_CBL: case TCPC_REG_DEV_CAP_1_PWRROLE_SRC_SNK_DRP: /* Dead batter and dbg acc ind */ - data->reg[TCPC_REG_ROLE_CTRL] = 0x4a; - data->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; + ctx->reg[TCPC_REG_ROLE_CTRL] = 0x4a; + ctx->reg[TCPC_REG_MSG_HDR_INFO] = 0x04; break; } } @@ -794,46 +780,43 @@ static void tcpci_emul_reset_role_ctrl(const struct emul *emul) * @param emul Pointer to TCPCI emulator * @return 0 if successful */ -static int tcpci_emul_reset(const struct emul *emul) +int tcpci_emul_reset(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; - - data->reg[TCPC_REG_ALERT] = 0x00; - data->reg[TCPC_REG_ALERT + 1] = 0x00; - data->reg[TCPC_REG_FAULT_STATUS_MASK] = 0xff; - data->reg[TCPC_REG_CONFIG_STD_OUTPUT] = 0x60; - data->reg[TCPC_REG_TCPC_CTRL] = 0x00; - data->reg[TCPC_REG_FAULT_CTRL] = 0x00; - data->reg[TCPC_REG_POWER_CTRL] = 0x60; - data->reg[TCPC_REG_CC_STATUS] = 0x00; - data->reg[TCPC_REG_POWER_STATUS] = 0x08; - data->reg[TCPC_REG_FAULT_STATUS] = 0x80; - data->reg[TCPC_REG_EXT_STATUS] = 0x00; - data->reg[TCPC_REG_ALERT_EXT] = 0x00; - data->reg[TCPC_REG_COMMAND] = 0x00; - data->reg[TCPC_REG_CONFIG_EXT_1] = 0x00; - data->reg[TCPC_REG_GENERIC_TIMER] = 0x00; - data->reg[TCPC_REG_GENERIC_TIMER + 1] = 0x00; - data->reg[TCPC_REG_RX_DETECT] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE + 1] = 0x00; - data->reg[TCPC_REG_VBUS_SINK_DISCONNECT_THRESH] = 0x8c; - data->reg[TCPC_REG_VBUS_SINK_DISCONNECT_THRESH + 1] = 0x00; - data->reg[TCPC_REG_VBUS_STOP_DISCHARGE_THRESH] = 0x20; - data->reg[TCPC_REG_VBUS_STOP_DISCHARGE_THRESH + 1] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG + 1] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG] = 0x00; - data->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG + 1] = 0x00; - data->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET] = 0x00; - data->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET + 1] = 0x00; - - tcpci_emul_reset_mask_regs(emul); - tcpci_emul_reset_role_ctrl(emul); - - if (data->dev_ops && data->dev_ops->reset) { - data->dev_ops->reset(emul, data->dev_ops); - } + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; + + ctx->reg[TCPC_REG_ALERT] = 0x00; + ctx->reg[TCPC_REG_ALERT + 1] = 0x00; + ctx->reg[TCPC_REG_FAULT_STATUS_MASK] = 0xff; + ctx->reg[TCPC_REG_CONFIG_STD_OUTPUT] = 0x60; + ctx->reg[TCPC_REG_TCPC_CTRL] = 0x00; + ctx->reg[TCPC_REG_FAULT_CTRL] = 0x00; + ctx->reg[TCPC_REG_POWER_CTRL] = 0x60; + ctx->reg[TCPC_REG_CC_STATUS] = 0x00; + ctx->reg[TCPC_REG_POWER_STATUS] = 0x08; + ctx->reg[TCPC_REG_FAULT_STATUS] = 0x80; + ctx->reg[TCPC_REG_EXT_STATUS] = 0x00; + ctx->reg[TCPC_REG_ALERT_EXT] = 0x00; + ctx->reg[TCPC_REG_COMMAND] = 0x00; + ctx->reg[TCPC_REG_CONFIG_EXT_1] = 0x00; + ctx->reg[TCPC_REG_GENERIC_TIMER] = 0x00; + ctx->reg[TCPC_REG_GENERIC_TIMER + 1] = 0x00; + ctx->reg[TCPC_REG_RX_DETECT] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE + 1] = 0x00; + ctx->reg[TCPC_REG_VBUS_SINK_DISCONNECT_THRESH] = 0x8c; + ctx->reg[TCPC_REG_VBUS_SINK_DISCONNECT_THRESH + 1] = 0x00; + ctx->reg[TCPC_REG_VBUS_STOP_DISCHARGE_THRESH] = 0x20; + ctx->reg[TCPC_REG_VBUS_STOP_DISCHARGE_THRESH + 1] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG + 1] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG] = 0x00; + ctx->reg[TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG + 1] = 0x00; + ctx->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET] = 0x00; + ctx->reg[TCPC_REG_VBUS_NONDEFAULT_TARGET + 1] = 0x00; + + tcpci_emul_reset_mask_regs(ctx); + tcpci_emul_reset_role_ctrl(ctx); return tcpci_emul_alert_changed(emul); } @@ -841,16 +824,18 @@ static int tcpci_emul_reset(const struct emul *emul) /** * @brief Set alert and fault registers to indicate i2c interface fault * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * @return 0 if successful */ static int tcpci_emul_set_i2c_interface_err(const struct emul *emul) { + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t fault_status; - tcpci_emul_get_reg(emul, TCPC_REG_FAULT_STATUS, &fault_status); + get_reg(ctx, TCPC_REG_FAULT_STATUS, &fault_status); fault_status |= TCPC_REG_FAULT_STATUS_I2C_INTERFACE_ERR; - tcpci_emul_set_reg(emul, TCPC_REG_FAULT_STATUS, fault_status); + set_reg(ctx, TCPC_REG_FAULT_STATUS, fault_status); return tcpci_emul_alert_changed(emul); } @@ -858,7 +843,7 @@ static int tcpci_emul_set_i2c_interface_err(const struct emul *emul) /** * @brief Handle read from RX buffer registers for TCPCI rev 1.0 and rev 2.0 * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * @param reg First byte of last i2c write message * @param val Pointer where byte to read should be stored * @param bytes Number of bytes already readded @@ -869,10 +854,11 @@ static int tcpci_emul_set_i2c_interface_err(const struct emul *emul) static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, uint8_t *val, int bytes) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; int is_rev1; - is_rev1 = data->reg[TCPC_REG_PD_INT_REV] == TCPC_REG_PD_INT_REV_REV_1_0; + is_rev1 = ctx->reg[TCPC_REG_PD_INT_REV] == TCPC_REG_PD_INT_REV_REV_1_0; if (!is_rev1 && reg != TCPC_REG_RX_BUFFER) { LOG_ERR("Register 0x%x defined only for revision 1.0", reg); @@ -882,7 +868,7 @@ static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, switch (reg) { case TCPC_REG_RX_BUFFER: - if (data->rx_msg == NULL) { + if (ctx->rx_msg == NULL) { if (bytes < 2) { *val = 0; } else { @@ -894,16 +880,16 @@ static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, } if (bytes == 0) { /* TCPCI message size count include type byte */ - *val = data->rx_msg->cnt + 1; + *val = ctx->rx_msg->cnt + 1; } else if (is_rev1) { LOG_ERR("Revision 1.0 has only byte count at 0x30"); tcpci_emul_set_i2c_interface_err(emul); return -EIO; } else if (bytes == 1) { - *val = data->rx_msg->type; - } else if (data->rx_msg->idx < data->rx_msg->cnt) { - *val = data->rx_msg->buf[data->rx_msg->idx]; - data->rx_msg->idx++; + *val = ctx->rx_msg->sop_type; + } else if (ctx->rx_msg->idx < ctx->rx_msg->cnt) { + *val = ctx->rx_msg->buf[ctx->rx_msg->idx]; + ctx->rx_msg->idx++; } else { LOG_ERR("Reading past RX buffer"); tcpci_emul_set_i2c_interface_err(emul); @@ -918,10 +904,10 @@ static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - if (data->rx_msg == NULL) { + if (ctx->rx_msg == NULL) { *val = 0; } else { - *val = data->rx_msg->type; + *val = ctx->rx_msg->sop_type; } break; @@ -932,24 +918,24 @@ static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - if (data->rx_msg == NULL) { + if (ctx->rx_msg == NULL) { LOG_ERR("Accessing RX buffer with no msg"); tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - *val = data->rx_msg->buf[bytes]; + *val = ctx->rx_msg->buf[bytes]; break; case TCPC_REG_RX_DATA: - if (data->rx_msg == NULL) { + if (ctx->rx_msg == NULL) { LOG_ERR("Accessing RX buffer with no msg"); tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - if (bytes < data->rx_msg->cnt - 2) { + if (bytes < ctx->rx_msg->cnt - 2) { /* rx_msg cnt include two bytes of header */ - *val = data->rx_msg->buf[bytes + 2]; - data->rx_msg->idx++; + *val = ctx->rx_msg->buf[bytes + 2]; + ctx->rx_msg->idx++; } else { LOG_ERR("Reading past RX buffer"); tcpci_emul_set_i2c_interface_err(emul); @@ -961,39 +947,12 @@ static int tcpci_emul_handle_rx_buf(const struct emul *emul, int reg, return 0; } -/** - * @brief Function called for each byte of read message - * - * @param i2c_emul Pointer to TCPCI 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 readded - * - * @return 0 on success - */ -static int tcpci_emul_read_byte(struct i2c_emul *i2c_emul, int reg, - uint8_t *val, int bytes) +/** Check description in emul_tcpci.h */ +int tcpci_emul_read_byte(const struct emul *emul, int reg, uint8_t *val, + int bytes) { - struct tcpci_emul_data *data; - const struct emul *emul; - - emul = i2c_emul->parent; - data = TCPCI_DATA_FROM_I2C_EMUL(i2c_emul); - - LOG_DBG("TCPCI 0x%x: read reg 0x%x", i2c_emul->addr, reg); - - if (data->dev_ops && data->dev_ops->read_byte) { - switch (data->dev_ops->read_byte(emul, data->dev_ops, reg, val, - bytes)) { - case TCPCI_EMUL_CONTINUE: - break; - case TCPCI_EMUL_DONE: - return 0; - case TCPCI_EMUL_ERROR: - default: - return -EIO; - } - } + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; switch (reg) { /* 16 bits values */ @@ -1019,7 +978,7 @@ static int tcpci_emul_read_byte(struct i2c_emul *i2c_emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - *val = data->reg[reg + bytes]; + *val = ctx->reg[reg + bytes]; break; /* 8 bits values */ @@ -1048,7 +1007,7 @@ static int tcpci_emul_read_byte(struct i2c_emul *i2c_emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - *val = data->reg[reg]; + *val = ctx->reg[reg]; break; case TCPC_REG_RX_BUFFER: @@ -1066,43 +1025,15 @@ static int tcpci_emul_read_byte(struct i2c_emul *i2c_emul, int reg, return 0; } -/** - * @brief Function called for each byte of write message. Data are stored - * in write_data field of tcpci_emul_data or in tx_msg in case of - * writing to TX buffer. - * - * @param i2c_emul Pointer to TCPCI 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 - * @return -EIO on invalid write to TX buffer - */ -static int tcpci_emul_write_byte(struct i2c_emul *i2c_emul, int reg, - uint8_t val, int bytes) +/** Check description in emul_tcpci.h */ +int tcpci_emul_write_byte(const struct emul *emul, int reg, uint8_t val, + int bytes) { - struct tcpci_emul_data *data; - const struct emul *emul; int is_rev1; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; - emul = i2c_emul->parent; - data = TCPCI_DATA_FROM_I2C_EMUL(i2c_emul); - - if (data->dev_ops && data->dev_ops->write_byte) { - switch (data->dev_ops->write_byte(emul, data->dev_ops, reg, val, - bytes)) { - case TCPCI_EMUL_CONTINUE: - break; - case TCPCI_EMUL_DONE: - return 0; - case TCPCI_EMUL_ERROR: - default: - return -EIO; - } - } - - is_rev1 = data->reg[TCPC_REG_PD_INT_REV] == TCPC_REG_PD_INT_REV_REV_1_0; + is_rev1 = ctx->reg[TCPC_REG_PD_INT_REV] == TCPC_REG_PD_INT_REV_REV_1_0; switch (reg) { case TCPC_REG_TX_BUFFER: if (is_rev1) { @@ -1111,16 +1042,16 @@ static int tcpci_emul_write_byte(struct i2c_emul *i2c_emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - data->tx_msg->idx = val; + ctx->tx_msg->idx = val; } if (bytes == 1) { - data->tx_msg->cnt = val; + ctx->tx_msg->cnt = val; } else { - if (data->tx_msg->cnt > 0) { - data->tx_msg->cnt--; - data->tx_msg->buf[data->tx_msg->idx] = val; - data->tx_msg->idx++; + if (ctx->tx_msg->cnt > 0) { + ctx->tx_msg->cnt--; + ctx->tx_msg->buf[ctx->tx_msg->idx] = val; + ctx->tx_msg->idx++; } else { LOG_ERR("Writing past TX buffer"); tcpci_emul_set_i2c_interface_err(emul); @@ -1146,7 +1077,7 @@ static int tcpci_emul_write_byte(struct i2c_emul *i2c_emul, int reg, tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - data->tx_msg->buf[bytes] = val; + ctx->tx_msg->buf[bytes] = val; return 0; case TCPC_REG_TX_HDR: @@ -1162,18 +1093,18 @@ static int tcpci_emul_write_byte(struct i2c_emul *i2c_emul, int reg, if (bytes > 1) { LOG_ERR("Writing byte %d to 2 byte register 0x%x", - bytes, reg); + bytes, reg); tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - data->tx_msg->buf[bytes] = val; + ctx->tx_msg->buf[bytes] = val; return 0; } if (bytes == 1) { - data->write_data = val; + ctx->write_data = val; } else if (bytes == 2) { - data->write_data |= (uint16_t)val << 8; + ctx->write_data |= (uint16_t)val << 8; } return 0; @@ -1182,43 +1113,44 @@ static int tcpci_emul_write_byte(struct i2c_emul *i2c_emul, int reg, /** * @brief Handle writes to command register * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * * @return 0 on success * @return -EIO on unknown command value */ static int tcpci_emul_handle_command(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t role_ctrl; uint16_t pwr_ctrl; - switch (data->write_data & 0xff) { + switch (ctx->write_data & 0xff) { case TCPC_REG_COMMAND_RESET_TRANSMIT_BUF: - data->tx_msg->idx = 0; + ctx->tx_msg->idx = 0; break; case TCPC_REG_COMMAND_RESET_RECEIVE_BUF: - if (data->rx_msg) { - data->rx_msg->idx = 0; + if (ctx->rx_msg) { + ctx->rx_msg->idx = 0; } break; case TCPC_REG_COMMAND_LOOK4CONNECTION: - tcpci_emul_get_reg(emul, TCPC_REG_ROLE_CTRL, &role_ctrl); - tcpci_emul_get_reg(emul, TCPC_REG_POWER_CTRL, &pwr_ctrl); + get_reg(ctx, TCPC_REG_ROLE_CTRL, &role_ctrl); + get_reg(ctx, TCPC_REG_POWER_CTRL, &pwr_ctrl); /* * Start DRP toggling only if auto discharge is disabled, * DRP is enabled and CC1/2 are both Rp or Rd */ - if (!(pwr_ctrl & TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT) - && TCPC_REG_ROLE_CTRL_DRP(role_ctrl) && + if (!(pwr_ctrl & + TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT) && + TCPC_REG_ROLE_CTRL_DRP(role_ctrl) && (TCPC_REG_ROLE_CTRL_CC1(role_ctrl) == TCPC_REG_ROLE_CTRL_CC2(role_ctrl)) && (TCPC_REG_ROLE_CTRL_CC1(role_ctrl) == TYPEC_CC_RP || TCPC_REG_ROLE_CTRL_CC1(role_ctrl) == TYPEC_CC_RD)) { /* Set Look4Connection and clear CC1/2 state */ - tcpci_emul_set_reg( - emul, TCPC_REG_CC_STATUS, + set_reg(ctx, TCPC_REG_CC_STATUS, TCPC_REG_CC_STATUS_LOOK4CONNECTION_MASK); } break; @@ -1238,45 +1170,47 @@ static int tcpci_emul_handle_command(const struct emul *emul) * Set command register to allow easier inspection of last * command sent */ - tcpci_emul_set_reg(emul, TCPC_REG_COMMAND, data->write_data & 0xff); + set_reg(ctx, TCPC_REG_COMMAND, ctx->write_data & 0xff); return 0; } /** * @brief Handle write to transmit register * - * @param emul Pointer to TCPCI emulator + * @param emul Pointer to TCPC emulator * * @return 0 on success * @return -EIO when sending SOP message with less than 2 bytes in TX buffer */ static int tcpci_emul_handle_transmit(const struct emul *emul) { - struct tcpci_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; enum tcpci_msg_type type; - data->tx_msg->cnt = data->tx_msg->idx; - data->tx_msg->type = TCPC_REG_TRANSMIT_TYPE(data->write_data); - data->tx_msg->idx = 0; + ctx->tx_msg->cnt = ctx->tx_msg->idx; + ctx->tx_msg->sop_type = TCPC_REG_TRANSMIT_TYPE(ctx->write_data); + ctx->tx_msg->idx = 0; - type = TCPC_REG_TRANSMIT_TYPE(data->write_data); + type = TCPC_REG_TRANSMIT_TYPE(ctx->write_data); - if (type < NUM_SOP_STAR_TYPES && data->tx_msg->cnt < 2) { + if (type < NUM_SOP_STAR_TYPES && ctx->tx_msg->cnt < 2) { LOG_ERR("Transmitting too short message (%d)", - data->tx_msg->cnt); + ctx->tx_msg->cnt); tcpci_emul_set_i2c_interface_err(emul); return -EIO; } - if (data->partner && data->partner->transmit) { - data->partner->transmit(emul, data->partner, data->tx_msg, type, - TCPC_REG_TRANSMIT_RETRY(data->write_data)); + if (ctx->partner && ctx->partner->transmit) { + ctx->partner->transmit( + emul, ctx->partner, ctx->tx_msg, type, + TCPC_REG_TRANSMIT_RETRY(ctx->write_data)); } switch (type) { case TCPCI_MSG_TX_HARD_RESET: tcpci_emul_disable_pd_msg_delivery(emul); - tcpci_emul_reset_mask_regs(emul); + tcpci_emul_reset_mask_regs(ctx); /* fallthrough */ case TCPCI_MSG_CABLE_RESET: /* @@ -1293,22 +1227,11 @@ static int tcpci_emul_handle_transmit(const struct emul *emul) return 0; } -/** - * @brief Handle I2C write message. It is checked if accessed register isn't RO - * and reserved bits are set to 0. - * - * @param i2c_emul Pointer to TCPCI 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 tcpci_emul_handle_write(struct i2c_emul *i2c_emul, int reg, - int msg_len) +/** Check description in emul_tcpci.h */ +int tcpci_emul_handle_write(const struct emul *emul, int reg, int msg_len) { - struct tcpci_emul_data *data; - const struct emul *emul; + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; uint16_t rsvd_mask = 0; uint16_t alert_val; bool inform_partner = false; @@ -1324,43 +1247,24 @@ static int tcpci_emul_handle_write(struct i2c_emul *i2c_emul, int reg, /* Exclude register address byte from message length */ msg_len--; - emul = i2c_emul->parent; - data = TCPCI_DATA_FROM_I2C_EMUL(i2c_emul); - - LOG_DBG("TCPCI 0x%x: write reg 0x%x val 0x%x", i2c_emul->addr, reg, - data->write_data); - - if (data->dev_ops && data->dev_ops->handle_write) { - switch (data->dev_ops->handle_write(emul, data->dev_ops, reg, - msg_len)) { - case TCPCI_EMUL_CONTINUE: - break; - case TCPCI_EMUL_DONE: - return 0; - case TCPCI_EMUL_ERROR: - default: - return -EIO; - } - } - switch (reg) { /* Alert registers */ case TCPC_REG_ALERT: /* Overflow is cleared by Receive SOP message status */ - data->write_data &= ~TCPC_REG_ALERT_RX_BUF_OVF; - if (data->write_data & TCPC_REG_ALERT_RX_STATUS) { - data->write_data |= TCPC_REG_ALERT_RX_BUF_OVF; + ctx->write_data &= ~TCPC_REG_ALERT_RX_BUF_OVF; + if (ctx->write_data & TCPC_REG_ALERT_RX_STATUS) { + ctx->write_data |= TCPC_REG_ALERT_RX_BUF_OVF; /* Do not clear RX status if there is new message */ if (tcpci_emul_get_next_rx_msg(emul)) { - data->write_data &= ~TCPC_REG_ALERT_RX_STATUS; + ctx->write_data &= ~TCPC_REG_ALERT_RX_STATUS; } } /* fallthrough */ case TCPC_REG_FAULT_STATUS: case TCPC_REG_ALERT_EXT: /* Clear bits where TCPM set 1 */ - tcpci_emul_get_reg(emul, reg, &alert_val); - data->write_data = alert_val & (~data->write_data); + get_reg(ctx, reg, &alert_val); + ctx->write_data = alert_val & (~ctx->write_data); /* fallthrough */ case TCPC_REG_ALERT_MASK: case TCPC_REG_POWER_STATUS_MASK: @@ -1390,11 +1294,11 @@ static int tcpci_emul_handle_write(struct i2c_emul *i2c_emul, int reg, break; case TCPC_REG_CONFIG_EXT_1: - if (data->write_data & TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR && - ((data->reg[TCPC_REG_STD_INPUT_CAP] & + if (ctx->write_data & TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR && + ((ctx->reg[TCPC_REG_STD_INPUT_CAP] & TCPC_REG_STD_INPUT_CAP_SRC_FR_SWAP) == BIT(4)) && - data->reg[TCPC_REG_STD_OUTPUT_CAP] & - TCPC_REG_STD_OUTPUT_CAP_SNK_DISC_DET) { + ctx->reg[TCPC_REG_STD_OUTPUT_CAP] & + TCPC_REG_STD_OUTPUT_CAP_SNK_DISC_DET) { tcpci_emul_set_i2c_interface_err(emul); return 0; } @@ -1447,23 +1351,23 @@ static int tcpci_emul_handle_write(struct i2c_emul *i2c_emul, int reg, } /* Check reserved bits */ - if (data->error_on_rsvd_write && rsvd_mask & data->write_data) { + if (ctx->error_on_rsvd_write && rsvd_mask & ctx->write_data) { tcpci_emul_set_i2c_interface_err(emul); LOG_ERR("Writing 0x%x to reg 0x%x with rsvd bits mask 0x%x", - data->write_data, reg, rsvd_mask); + ctx->write_data, reg, rsvd_mask); return -EIO; } /* Check if I2C write message has correct length */ if (msg_len != reg_bytes) { tcpci_emul_set_i2c_interface_err(emul); - LOG_ERR("Writing byte %d to %d byte register 0x%x", - msg_len, reg_bytes, reg); + LOG_ERR("Writing byte %d to %d byte register 0x%x", msg_len, + reg_bytes, reg); return -EIO; } /* Set new value of register */ - tcpci_emul_set_reg(emul, reg, data->write_data); + set_reg(ctx, reg, ctx->write_data); if (alert_changed) { rc = tcpci_emul_alert_changed(emul); @@ -1471,119 +1375,22 @@ static int tcpci_emul_handle_write(struct i2c_emul *i2c_emul, int reg, return rc; } - if (inform_partner && data->partner && data->partner->control_change) { - data->partner->control_change(emul, data->partner); + if (inform_partner && ctx->partner && ctx->partner->control_change) { + ctx->partner->control_change(emul, ctx->partner); } return 0; } -/** - * @brief Get currently accessed register, which always equals to selected - * register. - * - * @param i2c_emul Pointer to TCPCI 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 tcpci_emul_access_reg(struct i2c_emul *i2c_emul, int reg, int bytes, - bool read) -{ - return reg; -} - -/* Device instantiation */ - /** Check description in emul_tcpci.h */ -struct i2c_emul *tcpci_emul_get_i2c_emul(const struct emul *emul) +void tcpci_emul_i2c_init(const struct emul *emul, const struct device *i2c_dev) { - struct tcpci_emul_data *data = emul->data; - - return &data->common.emul; -} + struct tcpc_emul_data *tcpc_data = emul->data; + struct tcpci_ctx *ctx = tcpc_data->tcpci_ctx; -/** - * @brief Set up a new TCPCI emulator - * - * This should be called for each TCPCI 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 tcpci_emul_init(const struct emul *emul, const struct device *parent) -{ - const struct i2c_common_emul_cfg *cfg = emul->cfg; - struct tcpci_emul_data *data = emul->data; - int ret; - - data->common.emul.api = &i2c_common_emul_api; - 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); - - ret = i2c_emul_register(parent, emul->dev_label, &data->common.emul); - if (ret != 0) - return ret; - - return tcpci_emul_reset(emul); -} + ctx->common.emul.addr = tcpc_data->i2c_cfg.addr; + ctx->common.i2c = i2c_dev; + ctx->common.cfg = &tcpc_data->i2c_cfg; -#define TCPCI_EMUL(n) \ - uint8_t tcpci_emul_tx_buf_##n[128]; \ - static struct tcpci_emul_msg tcpci_emul_tx_msg_##n = { \ - .buf = tcpci_emul_tx_buf_##n, \ - }; \ - \ - static struct tcpci_emul_data tcpci_emul_data_##n = { \ - .tx_msg = &tcpci_emul_tx_msg_##n, \ - .error_on_ro_write = true, \ - .error_on_rsvd_write = true, \ - .common = { \ - .write_byte = tcpci_emul_write_byte, \ - .finish_write = tcpci_emul_handle_write, \ - .read_byte = tcpci_emul_read_byte, \ - .access_reg = tcpci_emul_access_reg, \ - }, \ - .alert_gpio_port = COND_CODE_1( \ - DT_INST_NODE_HAS_PROP(n, alert_gpio), \ - (DEVICE_DT_GET(DT_GPIO_CTLR( \ - DT_INST_PROP(n, alert_gpio), gpios))), \ - (NULL)), \ - .alert_gpio_pin = COND_CODE_1( \ - DT_INST_NODE_HAS_PROP(n, alert_gpio), \ - (DT_GPIO_PIN(DT_INST_PROP(n, alert_gpio), \ - gpios)), \ - (0)), \ - }; \ - \ - static const struct i2c_common_emul_cfg tcpci_emul_cfg_##n = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ - .data = &tcpci_emul_data_##n.common, \ - .addr = DT_INST_REG_ADDR(n), \ - }; \ - EMUL_DEFINE(tcpci_emul_init, DT_DRV_INST(n), \ - &tcpci_emul_cfg_##n, &tcpci_emul_data_##n) - -DT_INST_FOREACH_STATUS_OKAY(TCPCI_EMUL) - -#ifdef CONFIG_ZTEST_NEW_API -#define TCPCI_EMUL_RESET_RULE_BEFORE(n) \ - tcpci_emul_reset(&EMUL_REG_NAME(DT_DRV_INST(n))); -static void tcpci_emul_reset_rule_before(const struct ztest_unit_test *test, - void *data) -{ - ARG_UNUSED(test); - ARG_UNUSED(data); - DT_INST_FOREACH_STATUS_OKAY(TCPCI_EMUL_RESET_RULE_BEFORE); + i2c_common_emul_init(&ctx->common); } -ZTEST_RULE(tcpci_emul_reset, tcpci_emul_reset_rule_before, NULL); -#endif /* CONFIG_ZTEST_NEW_API */ |