[PATCH RFC v3 12/14] i2c: nomadik: add support for I2C_XFER_V2 - detailed fault reporting

From: Dmitry Guzman

Date: Thu Nov 05 2026 - 12:25:25 EST


I2C_XFER_V2 is a new API that allows I2C clients to get the detailed
report in case of transmission failure. Previously, the only information
returned by I2C bus controller was the error code; there was no way to
find out how many messages or bytes in a certain message have been sent
or received until the fault condition occurred.

This commit introduces support of this feature in i2c-nomadik driver.

Signed-off-by: Dmitry Guzman <Dmitry.Guzman@xxxxxxxxxxxx>
---
drivers/i2c/busses/i2c-nomadik.c | 37 +++++++++++++++++++++++++++++++------
1 file changed, 31 insertions(+), 6 deletions(-)

diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index f68d4cf7c0e7..9f43ab792ae2 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -198,6 +198,7 @@ struct i2c_nmk_client {
* @stop: stop condition.
* @xfer_wq: xfer done wait queue.
* @result: controller propogated result.
+ * @bytes_cplt: number of bytes completed in the message that caused a fault.
*/
struct nmk_i2c_dev {
struct i2c_vendor_data *vendor;
@@ -218,6 +219,7 @@ struct nmk_i2c_dev {
int stop;
struct wait_queue_head xfer_wq;
int result;
+ int bytes_cplt;
};

/* controller's abort causes */
@@ -530,6 +532,8 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
int status = 0;
bool xfer_done;

+ priv->cli.xfer_bytes = 0;
+
mcr = load_i2c_mcr_reg(priv, flags);
writel(mcr, priv->virtbase + I2C_MCR);

@@ -655,6 +659,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
int status;

priv->i2c_sr = 0;
+ priv->bytes_cplt = 0;
if (flags & I2C_M_RD) {
/* read operation */
priv->cli.operation = I2C_READ;
@@ -690,6 +695,16 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
status = priv->result;
}

+ if (flags & I2C_M_RD) {
+ /* For READ messages, return the number of bytes read from FIFO */
+ priv->bytes_cplt = priv->cli.xfer_bytes;
+ } else {
+ /* For WRITE messages, return the number of bytes sent on bus */
+ priv->bytes_cplt = FIELD_GET(I2C_SR_LENGTH, priv->i2c_sr);
+ /* LENGTH value includes the last byte that has not been sent or ACKed */
+ if (priv->bytes_cplt > 0)
+ priv->bytes_cplt--;
+ }
init_hw(priv);

status = status ? status : priv->result;
@@ -699,10 +714,11 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
}

/**
- * nmk_i2c_xfer() - I2C transfer function used by kernel framework
+ * nmk_i2c_xfer_v2() - I2C transfer function used by kernel framework
* @i2c_adap: Adapter pointer to the controller
* @msgs: Pointer to data to be written.
* @num_msgs: Number of messages to be executed
+ * @report: Pointer to transfer report to be written.
*
* This is the function called by the generic kernel i2c_transfer()
* or i2c_smbus...() API calls. Note that this code is protected by the
@@ -745,8 +761,9 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
* please use the i2c_smbus_read_i2c_block_data()
* or i2c_smbus_write_i2c_block_data() API
*/
-static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg msgs[], int num_msgs)
+static int nmk_i2c_xfer_v2(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[], int num_msgs,
+ struct i2c_transfer_report *report)
{
int status = 0;
int i;
@@ -756,6 +773,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
if (i)
return i;

+ priv->bytes_cplt = 0;
+
/* setup the i2c controller */
setup_i2c_controller(priv);

@@ -774,10 +793,15 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
pm_runtime_put_sync(&priv->adev->dev);

/* return the no. messages processed */
- if (status)
+ if (status) {
+ report->msgs_cplt = i;
+ report->bytes_cplt = priv->bytes_cplt;
+ report->fault_msg_idx = i;
return status;
- else
+ } else {
+ i2c_transfer_report_success(report, num_msgs);
return num_msgs;
+ }
}

/**
@@ -1029,7 +1053,8 @@ static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
}

static const struct i2c_algorithm nmk_i2c_algo = {
- .xfer = nmk_i2c_xfer,
+ .xfer = i2c_xfer_to_xfer_v2,
+ .xfer_v2 = nmk_i2c_xfer_v2,
.functionality = nmk_i2c_functionality
};


--
2.43.0