aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorSergei Shtylyov <sergei.shtylyov@cogentembedded.com>2014-09-01 17:15:26 -0400
committerWolfram Sang <wsa@the-dreams.de>2014-09-02 06:28:15 -0400
commitdd318b0df27c582ac0d72a346fd6e693700be23c (patch)
treee113a2153307feb3b3c02859d742f0a036eded7f /drivers/i2c
parent69e273c0b0a3c337a521d083374c918dc52c666f (diff)
i2c: rcar: fix MNR interrupt handling
Sometimes the MNR and MST interrupts happen simultaneously (stop automatically follows NACK, according to the manuals) and in such case the ID_NACK flag isn't set since the MST interrupt handling precedes MNR and all interrupts are cleared and disabled then, so that MNR interrupt is never noticed -- this causes NACK'ed transfers to be falsely reported as successful. Exchanging MNR and MST handlers fixes this issue, however the MNR bit somehow gets set again even after being explicitly cleared, so I decided to completely suppress handling of all disabled interrupts (which is a good thing anyway)... Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Cc: stable@vger.kernel.org Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/i2c-rcar.c15
1 files changed, 9 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index f3c7139dfa25..dc32f5fa75d0 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -367,18 +367,15 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
367 367
368 msr = rcar_i2c_read(priv, ICMSR); 368 msr = rcar_i2c_read(priv, ICMSR);
369 369
370 /* Only handle interrupts that are currently enabled */
371 msr &= rcar_i2c_read(priv, ICMIER);
372
370 /* Arbitration lost */ 373 /* Arbitration lost */
371 if (msr & MAL) { 374 if (msr & MAL) {
372 rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); 375 rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST));
373 goto out; 376 goto out;
374 } 377 }
375 378
376 /* Stop */
377 if (msr & MST) {
378 rcar_i2c_flags_set(priv, ID_DONE);
379 goto out;
380 }
381
382 /* Nack */ 379 /* Nack */
383 if (msr & MNR) { 380 if (msr & MNR) {
384 /* go to stop phase */ 381 /* go to stop phase */
@@ -388,6 +385,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
388 goto out; 385 goto out;
389 } 386 }
390 387
388 /* Stop */
389 if (msr & MST) {
390 rcar_i2c_flags_set(priv, ID_DONE);
391 goto out;
392 }
393
391 if (rcar_i2c_is_recv(priv)) 394 if (rcar_i2c_is_recv(priv))
392 rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); 395 rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr));
393 else 396 else