| From 331fb731824c9a0b18238f0cbf98dc0daac640a3 Mon Sep 17 00:00:00 2001 |
| From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> |
| Date: Tue, 2 Sep 2014 01:15:26 +0400 |
| Subject: 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> |
| (cherry picked from commit dd318b0df27c582ac0d72a346fd6e693700be23c) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/i2c/busses/i2c-rcar.c | 15 +++++++++------ |
| 1 file 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) |
| |
| msr = rcar_i2c_read(priv, ICMSR); |
| |
| + /* Only handle interrupts that are currently enabled */ |
| + msr &= rcar_i2c_read(priv, ICMIER); |
| + |
| /* Arbitration lost */ |
| if (msr & MAL) { |
| rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); |
| goto out; |
| } |
| |
| - /* Stop */ |
| - if (msr & MST) { |
| - rcar_i2c_flags_set(priv, ID_DONE); |
| - goto out; |
| - } |
| - |
| /* Nack */ |
| if (msr & MNR) { |
| /* go to stop phase */ |
| @@ -388,6 +385,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) |
| goto out; |
| } |
| |
| + /* Stop */ |
| + if (msr & MST) { |
| + rcar_i2c_flags_set(priv, ID_DONE); |
| + goto out; |
| + } |
| + |
| if (rcar_i2c_is_recv(priv)) |
| rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); |
| else |
| -- |
| 2.1.2 |
| |