summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorSergei Shtylyov <sergei.shtylyov@cogentembedded.com>2014-09-02 01:15:26 +0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-10-06 00:40:53 +0400
commit893c48cfa1993c872f6e2aeb8ee560d62e14924a (patch)
treede75e4a665ff3e1a3846ef105d0d9d435954c9ec /drivers/i2c
parent2fb2af14c2dfcfbe656a3246b167f87e9ca2ff3c (diff)
downloadlinux-893c48cfa1993c872f6e2aeb8ee560d62e14924a.tar.xz
i2c: rcar: fix MNR interrupt handling
commit dd318b0df27c582ac0d72a346fd6e693700be23c upstream. 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> Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 f082d8ea8919..416e72e6cbe6 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -372,18 +372,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 */
@@ -393,6 +390,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