mfd: tps80031: fix irq status clear sequence
David Schalig [Wed, 14 Dec 2011 07:01:30 +0000 (16:01 +0900)]
According to tps80031 datasheet, all 3 interrupt status registers should
be read, before writing to clear them. The old code used interleaved status
read/clear, which may drop interrupts.

Bug 914740

Change-Id: I4c9c0b7c623ea0fe01d90e9a531ff2e9d34f125c
Signed-off-by: David Schalig <dschalig@nvidia.com>
Reviewed-on: http://git-master/r/69941
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

drivers/mfd/tps80031.c

index 6fe80dc..e6bfd47 100644 (file)
@@ -801,35 +801,35 @@ static irqreturn_t tps80031_irq(int irq, void *data)
 {
        struct tps80031 *tps80031 = data;
        int ret = 0;
-       u8 tmp[3];
        u32 acks;
        int i;
+       uint8_t tmp[3];
 
-       for (i = 0; i < 3; i++) {
-               ret = tps80031_read(tps80031->dev, SLAVE_ID2,
-                       TPS80031_INT_STS_A + i, &tmp[i]);
+       ret = tps80031_reads(tps80031->dev, SLAVE_ID2,
+                            TPS80031_INT_STS_A, 3, tmp);
+       if (ret < 0) {
+               dev_err(tps80031->dev, "failed to read interrupt status\n");
+               return IRQ_NONE;
+       }
+       acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
+
+       if (acks) {
+               ret = tps80031_writes(tps80031->dev, SLAVE_ID2,
+                                     TPS80031_INT_STS_A, 3, tmp);
                if (ret < 0) {
-                       dev_err(tps80031->dev, "failed to read interrupt "
-                                                       "status\n");
+                       dev_err(tps80031->dev, "failed to write "
+                                               "interrupt status\n");
                        return IRQ_NONE;
                }
-               if (tmp[i]) {
-                       ret = tps80031_write(tps80031->dev, SLAVE_ID2,
-                                       TPS80031_INT_STS_A + i, tmp[i]);
-                       if (ret < 0) {
-                               dev_err(tps80031->dev, "failed to write "
-                                                       "interrupt status\n");
-                               return IRQ_NONE;
-                       }
+
+               while (acks) {
+                       i = __ffs(acks);
+                       if (tps80031->irq_en & (1 << i))
+                               handle_nested_irq(tps80031->irq_base + i);
+                       acks &= ~(1 << i);
                }
        }
-       acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0];
-       while (acks) {
-               i = __ffs(acks);
-               if (tps80031->irq_en & (1 << i))
-                       handle_nested_irq(tps80031->irq_base + i);
-               acks &= ~(1 << i);
-       }
+
        return IRQ_HANDLED;
 }