Skip to content

Commit f4f64fa

Browse files
marcanAndi Shyti
authored andcommitted
i2c: pasemi: Improve error recovery
Add handling for all the missing error condition, and better recovery in pasemi_smb_clear(). Reviewed-by: Alyssa Rosenzweig <[email protected]> Reviewed-by: Neal Gompa <[email protected]> Signed-off-by: Hector Martin <[email protected]> Co-developed-by: Sven Peter <[email protected]> Signed-off-by: Sven Peter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Andi Shyti <[email protected]>
1 parent 390b8f5 commit f4f64fa

File tree

1 file changed

+54
-7
lines changed

1 file changed

+54
-7
lines changed

drivers/i2c/busses/i2c-pasemi-core.c

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,31 @@ static void pasemi_reset(struct pasemi_smbus *smbus)
8787
reinit_completion(&smbus->irq_completion);
8888
}
8989

90-
static void pasemi_smb_clear(struct pasemi_smbus *smbus)
90+
static int pasemi_smb_clear(struct pasemi_smbus *smbus)
9191
{
9292
unsigned int status;
93+
int ret;
94+
95+
/* First wait for the bus to go idle */
96+
ret = readx_poll_timeout(ioread32, smbus->ioaddr + REG_SMSTA,
97+
status, !(status & (SMSTA_XIP | SMSTA_JAM)),
98+
USEC_PER_MSEC,
99+
USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS);
100+
101+
if (ret < 0) {
102+
dev_err(smbus->dev, "Bus is still stuck (status 0x%08x)\n", status);
103+
return -EIO;
104+
}
105+
106+
/* If any badness happened or there is data in the FIFOs, reset the FIFOs */
107+
if ((status & (SMSTA_MRNE | SMSTA_JMD | SMSTA_MTO | SMSTA_TOM | SMSTA_MTN | SMSTA_MTA)) ||
108+
!(status & SMSTA_MTE))
109+
pasemi_reset(smbus);
93110

94-
status = reg_read(smbus, REG_SMSTA);
111+
/* Clear the flags */
95112
reg_write(smbus, REG_SMSTA, status);
113+
114+
return 0;
96115
}
97116

98117
static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
@@ -130,9 +149,35 @@ static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
130149
}
131150
}
132151

152+
/* Controller timeout? */
153+
if (status & SMSTA_TOM) {
154+
dev_err(smbus->dev, "Controller timeout, status 0x%08x\n", status);
155+
return -EIO;
156+
}
157+
158+
/* Peripheral timeout? */
159+
if (status & SMSTA_MTO) {
160+
dev_err(smbus->dev, "Peripheral timeout, status 0x%08x\n", status);
161+
return -ETIME;
162+
}
163+
164+
/* Still stuck in a transaction? */
165+
if (status & SMSTA_XIP) {
166+
dev_err(smbus->dev, "Bus stuck, status 0x%08x\n", status);
167+
return -EIO;
168+
}
169+
170+
/* Arbitration loss? */
171+
if (status & SMSTA_MTA) {
172+
dev_err(smbus->dev, "Arbitration loss, status 0x%08x\n", status);
173+
return -EBUSY;
174+
}
175+
133176
/* Got NACK? */
134-
if (status & SMSTA_MTN)
177+
if (status & SMSTA_MTN) {
178+
dev_err(smbus->dev, "NACK, status 0x%08x\n", status);
135179
return -ENXIO;
180+
}
136181

137182
/* Clear XEN */
138183
reg_write(smbus, REG_SMSTA, SMSTA_XEN);
@@ -194,9 +239,9 @@ static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
194239
struct pasemi_smbus *smbus = adapter->algo_data;
195240
int ret, i;
196241

197-
pasemi_smb_clear(smbus);
198-
199-
ret = 0;
242+
ret = pasemi_smb_clear(smbus);
243+
if (ret)
244+
return ret;
200245

201246
for (i = 0; i < num && !ret; i++)
202247
ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
@@ -217,7 +262,9 @@ static int pasemi_smb_xfer(struct i2c_adapter *adapter,
217262
addr <<= 1;
218263
read_flag = read_write == I2C_SMBUS_READ;
219264

220-
pasemi_smb_clear(smbus);
265+
err = pasemi_smb_clear(smbus);
266+
if (err)
267+
return err;
221268

222269
switch (size) {
223270
case I2C_SMBUS_QUICK:

0 commit comments

Comments
 (0)