| From 049f5beddda932d66b2f6870a308f27cf66f6d00 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Wed, 13 Apr 2022 10:14:10 +0100 |
| Subject: i2c: cadence: Increase timeout per message if necessary |
| |
| From: Lucas Tanure <tanureal@opensource.cirrus.com> |
| |
| [ Upstream commit 96789dce043f5bff8b7d62aa28d52a7c59403a84 ] |
| |
| Timeout as 1 second sets an upper limit on the length |
| of the transfer executed, but there is no maximum length |
| of a write or read message set in i2c_adapter_quirks for |
| this controller. |
| |
| This upper limit affects devices that require sending |
| large firmware blobs over I2C. |
| |
| To remove that limitation, calculate the minimal time |
| necessary, plus some wiggle room, for every message and |
| use it instead of the default one second, if more than |
| one second. |
| |
| Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com> |
| Acked-by: Michal Simek <michal.simek@xilinx.com> |
| Signed-off-by: Wolfram Sang <wsa@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/i2c/busses/i2c-cadence.c | 12 ++++++++++-- |
| 1 file changed, 10 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c |
| index 23ee1a423654..a29ac9bae6d5 100644 |
| --- a/drivers/i2c/busses/i2c-cadence.c |
| +++ b/drivers/i2c/busses/i2c-cadence.c |
| @@ -511,7 +511,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap) |
| static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, |
| struct i2c_adapter *adap) |
| { |
| - unsigned long time_left; |
| + unsigned long time_left, msg_timeout; |
| u32 reg; |
| |
| id->p_msg = msg; |
| @@ -536,8 +536,16 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, |
| else |
| cdns_i2c_msend(id); |
| |
| + /* Minimal time to execute this message */ |
| + msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); |
| + /* Plus some wiggle room */ |
| + msg_timeout += msecs_to_jiffies(500); |
| + |
| + if (msg_timeout < adap->timeout) |
| + msg_timeout = adap->timeout; |
| + |
| /* Wait for the signal of completion */ |
| - time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout); |
| + time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); |
| if (time_left == 0) { |
| cdns_i2c_master_reset(adap); |
| dev_err(id->adap.dev.parent, |
| -- |
| 2.35.1 |
| |