diff options
Diffstat (limited to 'zephyr/emul/tcpc/emul_ps8xxx.c')
-rw-r--r-- | zephyr/emul/tcpc/emul_ps8xxx.c | 429 |
1 files changed, 254 insertions, 175 deletions
diff --git a/zephyr/emul/tcpc/emul_ps8xxx.c b/zephyr/emul/tcpc/emul_ps8xxx.c index 2fc372c9a7..467a487802 100644 --- a/zephyr/emul/tcpc/emul_ps8xxx.c +++ b/zephyr/emul/tcpc/emul_ps8xxx.c @@ -1,4 +1,4 @@ -/* 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. */ @@ -12,16 +12,18 @@ LOG_MODULE_REGISTER(ps8xxx_emul, CONFIG_TCPCI_EMUL_LOG_LEVEL); #include <zephyr/drivers/emul.h> #include <zephyr/drivers/i2c.h> #include <zephyr/drivers/i2c_emul.h> +#include <zephyr/ztest.h> #include "tcpm/tcpci.h" #include "emul/emul_common_i2c.h" #include "emul/tcpc/emul_ps8xxx.h" #include "emul/tcpc/emul_tcpci.h" +#include "emul/emul_stub_device.h" #include "driver/tcpm/ps8xxx.h" -#define PS8XXX_REG_MUX_IN_HPD_ASSERTION MUX_IN_HPD_ASSERTION_REG +#define PS8XXX_REG_MUX_IN_HPD_ASSERTION MUX_IN_HPD_ASSERTION_REG /** Run-time data used by the emulator */ struct ps8xxx_emul_data { @@ -32,8 +34,6 @@ struct ps8xxx_emul_data { /** Product ID of emulated device */ int prod_id; - /** Pointer to TCPCI emulator that is base for this emulator */ - const struct emul *tcpci_emul; /** Chip revision used by PS8805 */ uint8_t chip_rev; @@ -47,9 +47,6 @@ struct ps8xxx_emul_data { /** Constant configuration of the emulator */ struct ps8xxx_emul_cfg { - /** Phandle (name) of TCPCI emulator that is base for this emulator */ - const char *tcpci_emul; - /** Common I2C configuration used by "hidden" ports */ const struct i2c_common_emul_cfg p0_cfg; const struct i2c_common_emul_cfg p1_cfg; @@ -59,7 +56,8 @@ struct ps8xxx_emul_cfg { /** Check description in emul_ps8xxx.h */ void ps8xxx_emul_set_chip_rev(const struct emul *emul, uint8_t chip_rev) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; data->chip_rev = chip_rev; } @@ -67,7 +65,8 @@ void ps8xxx_emul_set_chip_rev(const struct emul *emul, uint8_t chip_rev) /** Check description in emul_ps8xxx.h */ void ps8xxx_emul_set_hw_rev(const struct emul *emul, uint16_t hw_rev) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; data->hw_rev = hw_rev; } @@ -75,7 +74,8 @@ void ps8xxx_emul_set_hw_rev(const struct emul *emul, uint16_t hw_rev) /** Check description in emul_ps8xxx.h */ void ps8xxx_emul_set_gpio_ctrl(const struct emul *emul, uint8_t gpio_ctrl) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; data->gpio_ctrl = gpio_ctrl; } @@ -83,7 +83,8 @@ void ps8xxx_emul_set_gpio_ctrl(const struct emul *emul, uint8_t gpio_ctrl) /** Check description in emul_ps8xxx.h */ uint8_t ps8xxx_emul_get_gpio_ctrl(const struct emul *emul) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; return data->gpio_ctrl; } @@ -91,7 +92,8 @@ uint8_t ps8xxx_emul_get_gpio_ctrl(const struct emul *emul) /** Check description in emul_ps8xxx.h */ uint8_t ps8xxx_emul_get_dci_cfg(const struct emul *emul) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; return data->dci_cfg; } @@ -99,7 +101,8 @@ uint8_t ps8xxx_emul_get_dci_cfg(const struct emul *emul) /** Check description in emul_ps8xxx.h */ int ps8xxx_emul_set_product_id(const struct emul *emul, uint16_t product_id) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; if (product_id != PS8805_PRODUCT_ID && product_id != PS8815_PRODUCT_ID) { @@ -108,7 +111,7 @@ int ps8xxx_emul_set_product_id(const struct emul *emul, uint16_t product_id) } data->prod_id = product_id; - tcpci_emul_set_reg(data->tcpci_emul, TCPC_REG_PRODUCT_ID, product_id); + tcpci_emul_set_reg(emul, TCPC_REG_PRODUCT_ID, product_id); return 0; } @@ -116,33 +119,29 @@ int ps8xxx_emul_set_product_id(const struct emul *emul, uint16_t product_id) /** Check description in emul_ps8xxx.h */ uint16_t ps8xxx_emul_get_product_id(const struct emul *emul) { - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; return data->prod_id; } -const struct emul *ps8xxx_emul_get_tcpci(const struct emul *emul) -{ - struct ps8xxx_emul_data *data = emul->data; - - return data->tcpci_emul; -} - /** Check description in emul_ps8xxx.h */ -struct i2c_emul *ps8xxx_emul_get_i2c_emul(const struct emul *emul, - enum ps8xxx_emul_port port) +struct i2c_common_emul_data * +ps8xxx_emul_get_i2c_common_data(const struct emul *emul, + enum ps8xxx_emul_port port) { const struct ps8xxx_emul_cfg *cfg = emul->cfg; - struct ps8xxx_emul_data *data = emul->data; + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; switch (port) { case PS8XXX_EMUL_PORT_0: - return &data->p0_data.emul; + return &data->p0_data; case PS8XXX_EMUL_PORT_1: - return &data->p1_data.emul; + return &data->p1_data; case PS8XXX_EMUL_PORT_GPIO: if (cfg->gpio_cfg.addr != 0) { - return &data->gpio_data.emul; + return &data->gpio_data; } else { return NULL; } @@ -152,24 +151,23 @@ struct i2c_emul *ps8xxx_emul_get_i2c_emul(const struct emul *emul, } /** - * @brief Function called for each byte of read message + * @brief Function called for each byte of read message from TCPC chip * - * @param emul Pointer to TCPCI emulator - * @param ops Pointer to device operations structure + * @param i2c_emul Pointer to PS8xxx 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 + * @param bytes Number of bytes already read * - * @return TCPCI_EMUL_CONTINUE to continue with default handler - * @return TCPCI_EMUL_DONE to immedietly return success - * @return TCPCI_EMUL_ERROR to immedietly return error + * @return 0 on success + * @return -EIO on invalid read request */ -static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_read_byte( - const struct emul *emul, - const struct tcpci_emul_dev_ops *ops, - int reg, uint8_t *val, int bytes) +static int ps8xxx_emul_tcpc_read_byte(const struct emul *emul, int reg, + uint8_t *val, int bytes) { uint16_t reg_val; + const struct i2c_emul *i2c_emul = emul->bus.i2c; + + LOG_DBG("PS8XXX TCPC 0x%x: read reg 0x%x", i2c_emul->addr, reg); switch (reg) { case PS8XXX_REG_FW_REV: @@ -182,36 +180,37 @@ static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_read_byte( if (bytes != 0) { LOG_ERR("Reading byte %d from 1 byte register 0x%x", bytes, reg); - return TCPCI_EMUL_ERROR; + return -EIO; } tcpci_emul_get_reg(emul, reg, ®_val); *val = reg_val & 0xff; - return TCPCI_EMUL_DONE; + return 0; default: - return TCPCI_EMUL_CONTINUE; + break; } + + return tcpci_emul_read_byte(emul, reg, val, bytes); } /** - * @brief Function called for each byte of write message + * @brief Function called for each byte of write message to TCPC chip * - * @param emul Pointer to TCPCI emulator - * @param ops Pointer to device operations structure + * @param emul Pointer to PS8xxx emulator * @param reg First byte of write message * @param val Received byte of write message * @param bytes Number of bytes already received * - * @return TCPCI_EMUL_CONTINUE to continue with default handler - * @return TCPCI_EMUL_DONE to immedietly return success - * @return TCPCI_EMUL_ERROR to immedietly return error + * @return 0 on success + * @return -EIO on invalid write request */ -static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_write_byte( - const struct emul *emul, - const struct tcpci_emul_dev_ops *ops, - int reg, uint8_t val, int bytes) +static int ps8xxx_emul_tcpc_write_byte(const struct emul *emul, int reg, + uint8_t val, int bytes) { uint16_t prod_id; + struct i2c_emul *i2c_emul = emul->bus.i2c; + + LOG_DBG("PS8XXX TCPC 0x%x: write reg 0x%x", i2c_emul->addr, reg); tcpci_emul_get_reg(emul, TCPC_REG_PRODUCT_ID, &prod_id); @@ -219,7 +218,7 @@ static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_write_byte( case PS8XXX_REG_RP_DETECT_CONTROL: /* This register is present only on PS8815 */ if (prod_id != PS8815_PRODUCT_ID) { - return TCPCI_EMUL_CONTINUE; + break; } case PS8XXX_REG_I2C_DEBUGGING_ENABLE: case PS8XXX_REG_MUX_IN_HPD_ASSERTION: @@ -230,34 +229,35 @@ static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_write_byte( if (bytes != 1) { LOG_ERR("Writing byte %d to 1 byte register 0x%x", bytes, reg); - return TCPCI_EMUL_ERROR; + return -EIO; } tcpci_emul_set_reg(emul, reg, val); - return TCPCI_EMUL_DONE; + return 0; default: - return TCPCI_EMUL_CONTINUE; + break; } + + return tcpci_emul_write_byte(emul, reg, val, bytes); } /** - * @brief Function called on the end of write message + * @brief Function called on the end of write message to TCPC chip * - * @param emul Pointer to TCPCI emulator - * @param ops Pointer to device operations structure + * @param emul Pointer to PS8xxx emulator * @param reg Register which is written * @param msg_len Length of handled I2C message * - * @return TCPCI_EMUL_CONTINUE to continue with default handler - * @return TCPCI_EMUL_DONE to immedietly return success - * @return TCPCI_EMUL_ERROR to immedietly return error + * @return 0 on success + * @return -EIO on error */ -static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_handle_write( - const struct emul *emul, - const struct tcpci_emul_dev_ops *ops, - int reg, int msg_len) +static int ps8xxx_emul_tcpc_finish_write(const struct emul *emul, int reg, + int msg_len) { uint16_t prod_id; + struct i2c_emul *i2c_emul = emul->bus.i2c; + + LOG_DBG("PS8XXX TCPC 0x%x: finish write reg 0x%x", i2c_emul->addr, reg); tcpci_emul_get_reg(emul, TCPC_REG_PRODUCT_ID, &prod_id); @@ -265,7 +265,7 @@ static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_handle_write( case PS8XXX_REG_RP_DETECT_CONTROL: /* This register is present only on PS8815 */ if (prod_id != PS8815_PRODUCT_ID) { - return TCPCI_EMUL_CONTINUE; + break; } case PS8XXX_REG_I2C_DEBUGGING_ENABLE: case PS8XXX_REG_MUX_IN_HPD_ASSERTION: @@ -273,99 +273,80 @@ static enum tcpci_emul_ops_resp ps8xxx_emul_tcpci_handle_write( case PS8XXX_REG_BIST_CONT_MODE_BYTE1: case PS8XXX_REG_BIST_CONT_MODE_BYTE2: case PS8XXX_REG_BIST_CONT_MODE_CTR: - return TCPCI_EMUL_DONE; + return 0; default: - return TCPCI_EMUL_CONTINUE; + break; } + + return tcpci_emul_handle_write(emul, reg, msg_len); } /** - * @brief Function called on reset + * @brief Get currently accessed register, which always equals to selected + * register from TCPC chip. * * @param emul Pointer to TCPCI emulator - * @param ops Pointer to device operations structure + * @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 void ps8xxx_emul_tcpci_reset(const struct emul *emul, - struct tcpci_emul_dev_ops *ops) +static int ps8xxx_emul_tcpc_access_reg(const struct emul *emul, int reg, + int bytes, bool read) { - tcpci_emul_set_reg(emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, 0x31); - tcpci_emul_set_reg(emul, PS8XXX_REG_MUX_IN_HPD_ASSERTION, 0x00); - tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE0, 0xff); - tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE1, 0x0f); - tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE2, 0x00); - tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_CTR, 0x00); + return reg; } -/** TCPCI PS8xxx operations */ -static struct tcpci_emul_dev_ops ps8xxx_emul_ops = { - .read_byte = ps8xxx_emul_tcpci_read_byte, - .write_byte = ps8xxx_emul_tcpci_write_byte, - .handle_write = ps8xxx_emul_tcpci_handle_write, - .reset = ps8xxx_emul_tcpci_reset, -}; - /** - * @brief Get port associated with given "hidden" I2C device - * - * @param i2c_emul Pointer to "hidden" I2C device + * @brief Function called on reset * - * @return Port associated with given I2C device + * @param emul Pointer to PS8xxx emulator */ -static enum ps8xxx_emul_port ps8xxx_emul_get_port(struct i2c_emul *i2c_emul) +static int ps8xxx_emul_tcpc_reset(const struct emul *emul) { - const struct ps8xxx_emul_cfg *cfg; - const struct emul *emul; - - emul = i2c_emul->parent; - cfg = emul->cfg; - - if (cfg->p0_cfg.addr == i2c_emul->addr) { - return PS8XXX_EMUL_PORT_0; - } - - if (cfg->p1_cfg.addr == i2c_emul->addr) { - return PS8XXX_EMUL_PORT_1; - } - - if (cfg->gpio_cfg.addr != 0 && cfg->gpio_cfg.addr == i2c_emul->addr) { - return PS8XXX_EMUL_PORT_GPIO; - } + tcpci_emul_set_reg(emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, 0x31); + tcpci_emul_set_reg(emul, PS8XXX_REG_MUX_IN_HPD_ASSERTION, 0x00); + tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE0, 0xff); + tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE1, 0x0f); + tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_BYTE2, 0x00); + tcpci_emul_set_reg(emul, PS8XXX_REG_BIST_CONT_MODE_CTR, 0x00); - return PS8XXX_EMUL_PORT_INVAL; + return tcpci_emul_reset(emul); } /** * @brief Function called for each byte of read message * - * @param i2c_emul Pointer to PS8xxx emulator + * @param emul Pointer to PS8xxx 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 + * @param bytes Number of bytes already read * * @return 0 on success * @return -EIO on invalid read request */ -static int ps8xxx_emul_read_byte(struct i2c_emul *i2c_emul, int reg, - uint8_t *val, int bytes) +static int ps8xxx_emul_read_byte_workhorse(const struct emul *emul, int reg, + uint8_t *val, int bytes, + enum ps8xxx_emul_port port) { + struct tcpc_emul_data *tcpc_data; struct ps8xxx_emul_data *data; - enum ps8xxx_emul_port port; - const struct emul *emul; + struct i2c_emul *i2c_emul = emul->bus.i2c; uint16_t i2c_dbg_reg; - emul = i2c_emul->parent; - data = emul->data; + LOG_DBG("PS8XXX 0x%x: read reg 0x%x", i2c_emul->addr, reg); + + tcpc_data = emul->data; + data = tcpc_data->chip_data; - tcpci_emul_get_reg(data->tcpci_emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - &i2c_dbg_reg); + tcpci_emul_get_reg(emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, &i2c_dbg_reg); /* There is no need to enable I2C debug on PS8815 */ if (data->prod_id != PS8815_PRODUCT_ID && i2c_dbg_reg & 0x1) { LOG_ERR("Accessing hidden i2c address without enabling debug"); return -EIO; } - port = ps8xxx_emul_get_port(i2c_emul); - /* This is only 2 bytes register so handle it separately */ if (data->prod_id == PS8815_PRODUCT_ID && port == PS8XXX_EMUL_PORT_1 && reg == PS8815_P1_REG_HW_REVISION) { @@ -412,10 +393,31 @@ static int ps8xxx_emul_read_byte(struct i2c_emul *i2c_emul, int reg, return -EIO; } +static int ps8xxx_emul_p0_read_byte(const struct emul *emul, int reg, + uint8_t *val, int bytes) +{ + return ps8xxx_emul_read_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_0); +} + +static int ps8xxx_emul_p1_read_byte(const struct emul *emul, int reg, + uint8_t *val, int bytes) +{ + return ps8xxx_emul_read_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_1); +} + +static int ps8xxx_emul_gpio_read_byte(const struct emul *emul, int reg, + uint8_t *val, int bytes) +{ + return ps8xxx_emul_read_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_GPIO); +} + /** * @brief Function called for each byte of write message * - * @param i2c_emul Pointer to PS8xxx emulator + * @param emul Pointer to PS8xxx emulator * @param reg First byte of write message * @param val Received byte of write message * @param bytes Number of bytes already received @@ -423,27 +425,27 @@ static int ps8xxx_emul_read_byte(struct i2c_emul *i2c_emul, int reg, * @return 0 on success * @return -EIO on invalid write request */ -static int ps8xxx_emul_write_byte(struct i2c_emul *i2c_emul, int reg, - uint8_t val, int bytes) +static int ps8xxx_emul_write_byte_workhorse(const struct emul *emul, int reg, + uint8_t val, int bytes, + enum ps8xxx_emul_port port) { struct ps8xxx_emul_data *data; - enum ps8xxx_emul_port port; - const struct emul *emul; + struct tcpc_emul_data *tcpc_data; + const struct i2c_emul *i2c_emul = emul->bus.i2c; uint16_t i2c_dbg_reg; - emul = i2c_emul->parent; - data = emul->data; + LOG_DBG("PS8XXX 0x%x: write reg 0x%x", i2c_emul->addr, reg); + + tcpc_data = emul->data; + data = tcpc_data->chip_data; - tcpci_emul_get_reg(data->tcpci_emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - &i2c_dbg_reg); + tcpci_emul_get_reg(emul, PS8XXX_REG_I2C_DEBUGGING_ENABLE, &i2c_dbg_reg); /* There is no need to enable I2C debug on PS8815 */ if (data->prod_id != PS8815_PRODUCT_ID && i2c_dbg_reg & 0x1) { LOG_ERR("Accessing hidden i2c address without enabling debug"); return -EIO; } - port = ps8xxx_emul_get_port(i2c_emul); - if (bytes != 1) { LOG_ERR("Writing more than one byte at once"); return -EIO; @@ -473,6 +475,77 @@ static int ps8xxx_emul_write_byte(struct i2c_emul *i2c_emul, int reg, return -EIO; } +static int ps8xxx_emul_p0_write_byte(const struct emul *emul, int reg, + uint8_t val, int bytes) +{ + return ps8xxx_emul_write_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_0); +} + +static int ps8xxx_emul_p1_write_byte(const struct emul *emul, int reg, + uint8_t val, int bytes) +{ + return ps8xxx_emul_write_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_1); +} + +static int ps8xxx_emul_gpio_write_byte(const struct emul *emul, int reg, + uint8_t val, int bytes) +{ + return ps8xxx_emul_write_byte_workhorse(emul, reg, val, bytes, + PS8XXX_EMUL_PORT_GPIO); +} + +static int i2c_ps8xxx_emul_transfer(const struct emul *target, + struct i2c_msg *msgs, int num_msgs, + int addr) +{ + struct tcpc_emul_data *tcpc_data = target->data; + struct ps8xxx_emul_data *ps8_xxx_data = tcpc_data->chip_data; + const struct ps8xxx_emul_cfg *ps8_xxx_cfg = target->cfg; + struct i2c_common_emul_data *common_data; + + /* The chip itself */ + if (addr == tcpc_data->i2c_cfg.addr) { + const struct i2c_common_emul_cfg *common_cfg = + &tcpc_data->i2c_cfg; + common_data = &tcpc_data->tcpci_ctx->common; + + return i2c_common_emul_transfer_workhorse( + target, common_data, common_cfg, msgs, num_msgs, addr); + } + /* Subchips */ + else if (addr == ps8_xxx_cfg->gpio_cfg.addr) { + const struct i2c_common_emul_cfg *common_cfg = + &ps8_xxx_cfg->gpio_cfg; + common_data = &ps8_xxx_data->gpio_data; + + return i2c_common_emul_transfer_workhorse( + target, common_data, common_cfg, msgs, num_msgs, addr); + } else if (addr == ps8_xxx_cfg->p0_cfg.addr) { + const struct i2c_common_emul_cfg *common_cfg = + &ps8_xxx_cfg->p0_cfg; + common_data = &ps8_xxx_data->p0_data; + + return i2c_common_emul_transfer_workhorse( + target, common_data, common_cfg, msgs, num_msgs, addr); + } else if (addr == ps8_xxx_cfg->p1_cfg.addr) { + const struct i2c_common_emul_cfg *common_cfg = + &ps8_xxx_cfg->p1_cfg; + common_data = &ps8_xxx_data->p1_data; + + return i2c_common_emul_transfer_workhorse( + target, common_data, common_cfg, msgs, num_msgs, addr); + } + + LOG_ERR("Cannot map address %02x", addr); + return -EIO; +} + +struct i2c_emul_api i2c_ps8xxx_emul_api = { + .transfer = i2c_ps8xxx_emul_transfer, +}; + /** * @brief Set up a new PS8xxx emulator * @@ -488,100 +561,104 @@ static int ps8xxx_emul_write_byte(struct i2c_emul *i2c_emul, int reg, static int ps8xxx_emul_init(const struct emul *emul, const struct device *parent) { + struct tcpc_emul_data *tcpc_data = emul->data; + struct ps8xxx_emul_data *data = tcpc_data->chip_data; + struct tcpci_ctx *tcpci_ctx = tcpc_data->tcpci_ctx; const struct ps8xxx_emul_cfg *cfg = emul->cfg; - struct ps8xxx_emul_data *data = emul->data; const struct device *i2c_dev; - int ret; + int ret = 0; - data->tcpci_emul = emul_get_binding(cfg->tcpci_emul); i2c_dev = parent; - data->p0_data.emul.api = &i2c_common_emul_api; + tcpci_ctx->common.write_byte = ps8xxx_emul_tcpc_write_byte; + tcpci_ctx->common.finish_write = ps8xxx_emul_tcpc_finish_write; + tcpci_ctx->common.read_byte = ps8xxx_emul_tcpc_read_byte; + tcpci_ctx->common.access_reg = ps8xxx_emul_tcpc_access_reg; + + tcpci_emul_i2c_init(emul, i2c_dev); + + data->p0_data.emul.api = &i2c_ps8xxx_emul_api; data->p0_data.emul.addr = cfg->p0_cfg.addr; - data->p0_data.emul.parent = emul; + data->p0_data.emul.target = emul; data->p0_data.i2c = i2c_dev; data->p0_data.cfg = &cfg->p0_cfg; i2c_common_emul_init(&data->p0_data); - data->p1_data.emul.api = &i2c_common_emul_api; + data->p1_data.emul.api = &i2c_ps8xxx_emul_api; data->p1_data.emul.addr = cfg->p1_cfg.addr; - data->p1_data.emul.parent = emul; + data->p1_data.emul.target = emul; data->p1_data.i2c = i2c_dev; data->p1_data.cfg = &cfg->p1_cfg; i2c_common_emul_init(&data->p1_data); - ret = i2c_emul_register(i2c_dev, emul->dev_label, &data->p0_data.emul); - ret |= i2c_emul_register(i2c_dev, emul->dev_label, &data->p1_data.emul); + /* Have to manually register "hidden" addressed chips under overarching + * ps8xxx + * TODO(b/240564574): Call EMUL_DEFINE for each "hidden" sub-chip. + */ + ret |= i2c_emul_register(i2c_dev, &data->p0_data.emul); + ret |= i2c_emul_register(i2c_dev, &data->p1_data.emul); if (cfg->gpio_cfg.addr != 0) { - data->gpio_data.emul.api = &i2c_common_emul_api; + data->gpio_data.emul.api = &i2c_ps8xxx_emul_api; data->gpio_data.emul.addr = cfg->gpio_cfg.addr; - data->gpio_data.emul.parent = emul; + data->gpio_data.emul.target = emul; data->gpio_data.i2c = i2c_dev; data->gpio_data.cfg = &cfg->gpio_cfg; + ret |= i2c_emul_register(i2c_dev, &data->gpio_data.emul); i2c_common_emul_init(&data->gpio_data); - ret |= i2c_emul_register(i2c_dev, emul->dev_label, - &data->gpio_data.emul); } - tcpci_emul_set_dev_ops(data->tcpci_emul, &ps8xxx_emul_ops); - ps8xxx_emul_tcpci_reset(data->tcpci_emul, &ps8xxx_emul_ops); + ret |= ps8xxx_emul_tcpc_reset(emul); - tcpci_emul_set_reg(data->tcpci_emul, TCPC_REG_PRODUCT_ID, - data->prod_id); + tcpci_emul_set_reg(emul, TCPC_REG_PRODUCT_ID, data->prod_id); /* FW rev is never 0 in a working device. Set arbitrary FW rev. */ - tcpci_emul_set_reg(data->tcpci_emul, PS8XXX_REG_FW_REV, 0x31); + tcpci_emul_set_reg(emul, PS8XXX_REG_FW_REV, 0x31); return ret; } -#define PS8XXX_EMUL(n) \ +#define PS8XXX_EMUL(n) \ static struct ps8xxx_emul_data ps8xxx_emul_data_##n = { \ .prod_id = PS8805_PRODUCT_ID, \ .p0_data = { \ - .write_byte = ps8xxx_emul_write_byte, \ - .read_byte = ps8xxx_emul_read_byte, \ + .write_byte = ps8xxx_emul_p0_write_byte, \ + .read_byte = ps8xxx_emul_p0_read_byte, \ }, \ .p1_data = { \ - .write_byte = ps8xxx_emul_write_byte, \ - .read_byte = ps8xxx_emul_read_byte, \ + .write_byte = ps8xxx_emul_p1_write_byte, \ + .read_byte = ps8xxx_emul_p1_read_byte, \ }, \ .gpio_data = { \ - .write_byte = ps8xxx_emul_write_byte, \ - .read_byte = ps8xxx_emul_read_byte, \ + .write_byte = ps8xxx_emul_gpio_write_byte, \ + .read_byte = ps8xxx_emul_gpio_read_byte, \ }, \ - }; \ - \ + }; \ + \ static const struct ps8xxx_emul_cfg ps8xxx_emul_cfg_##n = { \ - .tcpci_emul = DT_LABEL(DT_INST_PHANDLE(n, tcpci_i2c)), \ .p0_cfg = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ + .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \ .data = &ps8xxx_emul_data_##n.p0_data, \ .addr = DT_INST_PROP(n, p0_i2c_addr), \ }, \ .p1_cfg = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ + .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \ .data = &ps8xxx_emul_data_##n.p1_data, \ .addr = DT_INST_PROP(n, p1_i2c_addr), \ }, \ .gpio_cfg = { \ - .i2c_label = DT_INST_BUS_LABEL(n), \ - .dev_label = DT_INST_LABEL(n), \ + .dev_label = DT_NODE_FULL_NAME(DT_DRV_INST(n)), \ .data = &ps8xxx_emul_data_##n.gpio_data, \ .addr = DT_INST_PROP(n, gpio_i2c_addr), \ }, \ - }; \ - EMUL_DEFINE(ps8xxx_emul_init, DT_DRV_INST(n), \ - &ps8xxx_emul_cfg_##n, &ps8xxx_emul_data_##n) + }; \ + TCPCI_EMUL_DEFINE(n, ps8xxx_emul_init, &ps8xxx_emul_cfg_##n, \ + &ps8xxx_emul_data_##n, &i2c_ps8xxx_emul_api) DT_INST_FOREACH_STATUS_OKAY(PS8XXX_EMUL) -#ifdef CONFIG_ZMAKE_NEW_API - +#ifdef CONFIG_ZTEST_NEW_API #define PS8XXX_EMUL_RESET_RULE_BEFORE(n) \ - ps8xxx_emul_tcpci_reset(&ps8xxx_emul_data_##n, &ps8xxx_emul_ops); + ps8xxx_emul_tcpc_reset(EMUL_DT_GET(DT_DRV_INST(n))); static void ps8xxx_emul_reset_rule_before(const struct ztest_unit_test *test, void *data) { @@ -589,5 +666,7 @@ static void ps8xxx_emul_reset_rule_before(const struct ztest_unit_test *test, ARG_UNUSED(data); DT_INST_FOREACH_STATUS_OKAY(PS8XXX_EMUL_RESET_RULE_BEFORE); } -ZTEST_RULE(ps8xxx_emul_reset, ps8xxx_emul_reset_rule_before, NULL); -#endif /* CONFIG_ZMAKE_NEW_API */ +ZTEST_RULE(PS8XXX_emul_reset, ps8xxx_emul_reset_rule_before, NULL); +#endif /* CONFIG_ZTEST_NEW_API */ + +DT_INST_FOREACH_STATUS_OKAY(EMUL_STUB_DEVICE); |