mfd: tps80031: fix missed irq issue
Steve Kuo [Fri, 30 Mar 2012 07:00:38 +0000 (15:00 +0800)]
We found missed irq could be happened if clear all INT_STS_x register in one time.
Shadow register pushes the irq status after the first byte of INT_STS_x was cleared
The proposed way to clear interrupt is to write only one INT_STS_x register.
It will also clear the other two ones.

Bug 952476

Reviewed-on: http://git-master/r/93453
Signed-off-by: Steve Kuo <stevek@nvidia.com>

(cherry picked from commit 0c92f32e9e03defaeac991518b26134e59ef4db6)

Change-Id: I76179be4847f59a1687926b9b0dde6ebd3f58aa4
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/100306

drivers/mfd/tps80031.c

index e8ea75c..94ba777 100644 (file)
@@ -874,8 +874,22 @@ static irqreturn_t tps80031_irq(int irq, void *data)
        acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
 
        if (acks) {
-               ret = tps80031_writes(tps80031->dev, SLAVE_ID2,
-                                     TPS80031_INT_STS_A, 3, tmp);
+               /*
+                * Hardware behavior: hardware have the shadow register for
+                * interrupt status register which is updated if interrupt
+                * comes just after the interrupt status read. This shadow
+                * register gets written to main status register and cleared
+                * if any byte write happens in any of status register like
+                * STS_A, STS_B or STS_C.
+                * Hence here to clear the original interrupt status and
+                * updating the STS register with the shadow register, it is
+                * require to write only one byte in any of STS register.
+                * Having multiple register write can cause the STS register
+                * to clear without handling those interrupt and can cause
+                * interrupt miss.
+                */
+               ret = tps80031_write(tps80031->dev, SLAVE_ID2,
+                                     TPS80031_INT_STS_A, 0);
                if (ret < 0) {
                        dev_err(tps80031->dev, "failed to write "
                                                "interrupt status\n");