[PATCH 7/7] i2c: nomadik: add support for I2C_XFER_V2 - detailed fault reporting
From: Dmitry Guzman
Date: Tue Jun 23 2026 - 12:37:03 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 9cff0c2757fafeaf809395e02a5e754570f65e08..1cf03d634fdc856dc335a58597e0fd31ab077078 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -197,6 +197,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;
@@ -216,6 +217,7 @@ struct nmk_i2c_dev {
int stop;
struct wait_queue_head xfer_wq;
int result;
+ int bytes_cplt;
};
/* controller's abort causes */
@@ -529,6 +531,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);
@@ -653,6 +657,7 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags)
{
int status;
+ priv->bytes_cplt = 0;
if (flags & I2C_M_RD) {
/* read operation */
priv->cli.operation = I2C_READ;
@@ -678,6 +683,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, 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;
@@ -687,10 +702,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
@@ -733,14 +749,16 @@ 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;
struct nmk_i2c_dev *priv = i2c_get_adapdata(i2c_adap);
pm_runtime_get_sync(&priv->adev->dev);
+ priv->bytes_cplt = 0;
/* setup the i2c controller */
setup_i2c_controller(priv);
@@ -760,10 +778,17 @@ 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 {
+ report->msgs_cplt = num_msgs;
+ report->bytes_cplt = 0;
+ report->fault_msg_idx = num_msgs;
return num_msgs;
+ }
}
/**
@@ -1014,7 +1039,7 @@ static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
}
static const struct i2c_algorithm nmk_i2c_algo = {
- .xfer = nmk_i2c_xfer,
+ .xfer_v2 = nmk_i2c_xfer_v2,
.functionality = nmk_i2c_functionality
};
--
2.43.0