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 <[email protected]> --- 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
