diff options
author | Jae Hyun Yoo <jae.hyun.yoo@intel.com> | 2021-07-26 21:42:20 +0300 |
---|---|---|
committer | Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com> | 2021-10-20 01:10:39 +0300 |
commit | 66848473087df256b90a8ad9069e85b64b4dd14f (patch) | |
tree | 760364006e3c421315f1ea3c0154603e214edf8c | |
parent | c4619560139566f1bed1d2e573b43da71e9fde51 (diff) | |
download | linux-66848473087df256b90a8ad9069e85b64b4dd14f.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
-rw-r--r-- | drivers/i2c/busses/i2c-aspeed.c | 12 |
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); + } } /* |