summaryrefslogtreecommitdiff
path: root/zephyr/emul/tcpc/emul_ps8xxx.c
diff options
context:
space:
mode:
Diffstat (limited to 'zephyr/emul/tcpc/emul_ps8xxx.c')
-rw-r--r--zephyr/emul/tcpc/emul_ps8xxx.c429
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, &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);