mirror of
https://github.com/torvalds/linux.git
synced 2026-06-04 04:23:35 +02:00
i2c: pasemi: Improve error recovery
Add handling for all the missing error condition, and better recovery in pasemi_smb_clear(). Reviewed-by: Alyssa Rosenzweig <alyssa@rosenzweig.io> Reviewed-by: Neal Gompa <neal@gompa.dev> Signed-off-by: Hector Martin <marcan@marcan.st> Co-developed-by: Sven Peter <sven@svenpeter.dev> Signed-off-by: Sven Peter <sven@svenpeter.dev> Link: https://lore.kernel.org/r/20250427-pasemi-fixes-v3-3-af28568296c0@svenpeter.dev Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
This commit is contained in:
parent
390b8f5834
commit
f4f64fa8a6
|
|
@ -87,12 +87,31 @@ static void pasemi_reset(struct pasemi_smbus *smbus)
|
|||
reinit_completion(&smbus->irq_completion);
|
||||
}
|
||||
|
||||
static void pasemi_smb_clear(struct pasemi_smbus *smbus)
|
||||
static int pasemi_smb_clear(struct pasemi_smbus *smbus)
|
||||
{
|
||||
unsigned int status;
|
||||
int ret;
|
||||
|
||||
status = reg_read(smbus, REG_SMSTA);
|
||||
/* First wait for the bus to go idle */
|
||||
ret = readx_poll_timeout(ioread32, smbus->ioaddr + REG_SMSTA,
|
||||
status, !(status & (SMSTA_XIP | SMSTA_JAM)),
|
||||
USEC_PER_MSEC,
|
||||
USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(smbus->dev, "Bus is still stuck (status 0x%08x)\n", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If any badness happened or there is data in the FIFOs, reset the FIFOs */
|
||||
if ((status & (SMSTA_MRNE | SMSTA_JMD | SMSTA_MTO | SMSTA_TOM | SMSTA_MTN | SMSTA_MTA)) ||
|
||||
!(status & SMSTA_MTE))
|
||||
pasemi_reset(smbus);
|
||||
|
||||
/* Clear the flags */
|
||||
reg_write(smbus, REG_SMSTA, status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
|
||||
|
|
@ -130,9 +149,35 @@ static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
|
|||
}
|
||||
}
|
||||
|
||||
/* Controller timeout? */
|
||||
if (status & SMSTA_TOM) {
|
||||
dev_err(smbus->dev, "Controller timeout, status 0x%08x\n", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Peripheral timeout? */
|
||||
if (status & SMSTA_MTO) {
|
||||
dev_err(smbus->dev, "Peripheral timeout, status 0x%08x\n", status);
|
||||
return -ETIME;
|
||||
}
|
||||
|
||||
/* Still stuck in a transaction? */
|
||||
if (status & SMSTA_XIP) {
|
||||
dev_err(smbus->dev, "Bus stuck, status 0x%08x\n", status);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Arbitration loss? */
|
||||
if (status & SMSTA_MTA) {
|
||||
dev_err(smbus->dev, "Arbitration loss, status 0x%08x\n", status);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Got NACK? */
|
||||
if (status & SMSTA_MTN)
|
||||
if (status & SMSTA_MTN) {
|
||||
dev_err(smbus->dev, "NACK, status 0x%08x\n", status);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* Clear XEN */
|
||||
reg_write(smbus, REG_SMSTA, SMSTA_XEN);
|
||||
|
|
@ -194,9 +239,9 @@ static int pasemi_i2c_xfer(struct i2c_adapter *adapter,
|
|||
struct pasemi_smbus *smbus = adapter->algo_data;
|
||||
int ret, i;
|
||||
|
||||
pasemi_smb_clear(smbus);
|
||||
|
||||
ret = 0;
|
||||
ret = pasemi_smb_clear(smbus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num && !ret; i++)
|
||||
ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1)));
|
||||
|
|
@ -217,7 +262,9 @@ static int pasemi_smb_xfer(struct i2c_adapter *adapter,
|
|||
addr <<= 1;
|
||||
read_flag = read_write == I2C_SMBUS_READ;
|
||||
|
||||
pasemi_smb_clear(smbus);
|
||||
err = pasemi_smb_clear(smbus);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (size) {
|
||||
case I2C_SMBUS_QUICK:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user