summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorJae Hyun Yoo <jae.hyun.yoo@intel.com>2021-07-26 21:42:20 +0300
committerJae Hyun Yoo <jae.hyun.yoo@linux.intel.com>2021-11-05 10:22:16 +0300
commitc7ed8aecff5c32d843d9cb2c92da9c1463e6144a (patch)
tree88820cfdad3f4dd1f247ff303af05e3945e3de76 /drivers/i2c
parentdfadfcc10559a8a0f0d096f5ebf559dbb40fbcbd (diff)
downloadlinux-c7ed8aecff5c32d843d9cb2c92da9c1463e6144a.tar.xz
i2c: aspeed: fix interrupt handling on some abnormal cases
These two exceptional cases were rarely observed in a slave device reset or in a peer master reset conditions. 1. aspeed-i2c-bus 1e78a480.i2c-bus: irq handled != irq. expected 0x00000030, but was 0x00000020 when master goes from ASPEED_I2C_MASTER_STOP to ASPEED_I2C_MASTER_INACTIVE state due to an ASPEED_I2CD_INTR_ABNORMAL event. In this case, ASPEED_I2CD_INTR_NORMAL_STOP should be simply ignored without printing out the error message. 2. aspeed-i2c-bus 1e78a480.i2c-bus: irq handled != irq. expected 0x00000010, but was 0x00000000 when master already went to ASPEED_I2C_MASTER_INACTIVE. H/W sends one additional ASPEED_I2CD_INTR_NORMAL_STOP event but it's a garbage because driver is already in inactive state so filter it off from the error message printing out. Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com> Change-Id: I94794a9612a7e8db445591e490bad6adae0faacf
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-aspeed.c12
1 files changed, 10 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
index 50b28c45e00e..0542be568588 100644
--- a/drivers/i2c/busses/i2c-aspeed.c
+++ b/drivers/i2c/busses/i2c-aspeed.c
@@ -899,10 +899,13 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
bus->cmd_err = ret;
- bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+ if (bus->master_state == ASPEED_I2C_MASTER_STOP)
+ irq_handled |= (irq_status &
+ ASPEED_I2CD_INTR_NORMAL_STOP);
if (ret == -EAGAIN)
irq_handled |= (irq_status &
ASPEED_I2CD_INTR_TX_ACK);
+ bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
goto out_complete;
}
}
@@ -1101,9 +1104,14 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
} else {
irq_handled = aspeed_i2c_slave_irq(bus, irq_remaining);
irq_remaining &= ~irq_handled;
- if (irq_remaining)
+ if (irq_remaining) {
irq_handled |= aspeed_i2c_master_irq(bus,
irq_remaining);
+ if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE &&
+ bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
+ irq_handled |= (irq_remaining &
+ ASPEED_I2CD_INTR_NORMAL_STOP);
+ }
}
/*