Re: [PATCH] i2c: designware: call i2c_dw_read_clear_intrbits_slave() once

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi

On 10/20/20 11:33 AM, Michael Wu wrote:
i2c_dw_read_clear_intrbits_slave() was called per each interrupt handle.
It caused some interrupt bits which haven't been handled yet were cleared,
the corresponding handlers would do nothing due to interrupt bits been
discarded. For example,

$ i2cset -f -y 2 0x42 0x00 0x41; dmesg -c
[0][clear_intrbits]0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
[1][irq_handler   ]0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
WRITE_RECEIVED
[0][clear_intrbits]0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x714 : INTR_STAT=0x204
[1][irq_handler   ]0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4
WRITE_RECEIVED

   t1: ISR with the 1st IC_INTR_RX_FULL.
   t2: Clear listed IC_INTR bits by i2c_dw_read_clear_intrbits_slave().
   t3: Enter i2c_dw_irq_handler_slave() and then do
       i2c_slave_event(WRITE_RECEIVED) because
       if (stat & DW_IC_INTR_RX_FULL).
   t4: ISR with both IC_INTR_STOP_DET and the 2nd IC_INTR_RX_FULL.
   t5: Clear listed IC_INTR bits by i2c_dw_read_clear_intrbits_slave(). The
       current IC_INTR_STOP_DET is cleared by this
       i2c_dw_read_clear_intrbits_slave().
   t6: Enter i2c_dw_irq_handler_slave() and then do
       i2c_slave_event(WRITE_RECEIVED) because
       if (stat & DW_IC_INTR_RX_FULL).
   t7: i2c_slave_event(STOP) never be done because IC_INTR_STOP_DET was
       cleared in t5.

The root cause is that i2c_dw_read_clear_intrbits_slave() was called many
times. Calling i2c_dw_read_clear_intrbits_slave() once in one ISR and take
the returned stat for later handling is the solution.

Signed-off-by: Michael Wu <michael.wu@xxxxxxxxxx>
---
  drivers/i2c/busses/i2c-designware-slave.c | 16 +++++-----------
  1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c
index 44974b53a626..02e7c5171827 100644
--- a/drivers/i2c/busses/i2c-designware-slave.c
+++ b/drivers/i2c/busses/i2c-designware-slave.c
@@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
  	u32 raw_stat, stat, enabled, tmp;
  	u8 val = 0, slave_activity;
- regmap_read(dev->map, DW_IC_INTR_STAT, &stat);
  	regmap_read(dev->map, DW_IC_ENABLE, &enabled);
  	regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat);
  	regmap_read(dev->map, DW_IC_STATUS, &tmp);
@@ -168,13 +167,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev)
  	if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave)
  		return 0;
+ stat = i2c_dw_read_clear_intrbits_slave(dev);
  	dev_dbg(dev->dev,
  		"%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n",
  		enabled, slave_activity, raw_stat, stat);
- if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
-		i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
-

...

+
+	if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
+		i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);

Was this move a leftover that got committed by accident? I think it's better to have this logic change in another patch. Or was it even questionable to move the I2C_SLAVE_WRITE_REQUESTED reporting after all other?

Jarkko



[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux