| From 4107f0d4d0f717e760954a046cc5a7b008e99151 Mon Sep 17 00:00:00 2001 |
| From: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> |
| Date: Sun, 24 Aug 2014 00:44:09 +0400 |
| Subject: Revert "i2c: rcar: remove spinlock" |
| |
| This reverts commit 150b8be3cda54412ad7b54f5392b513b25c0aaa7. |
| |
| The I2C core's per-adapter locks can't protect from IRQs, so the driver still |
| needs a spinlock to protect the register accesses. |
| |
| Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> |
| Cc: stable@vger.kernel.org # 3.16+ |
| Signed-off-by: Wolfram Sang <wsa@the-dreams.de> |
| (cherry picked from commit 91bfe2989af02e709ca01ccf518c4fbda3efc70f) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/i2c/busses/i2c-rcar.c | 22 ++++++++++++++++++++++ |
| 1 file changed, 22 insertions(+) |
| |
| diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c |
| index dc32f5fa75d0..1cc146cfc1f3 100644 |
| --- a/drivers/i2c/busses/i2c-rcar.c |
| +++ b/drivers/i2c/busses/i2c-rcar.c |
| @@ -34,6 +34,7 @@ |
| #include <linux/platform_device.h> |
| #include <linux/pm_runtime.h> |
| #include <linux/slab.h> |
| +#include <linux/spinlock.h> |
| |
| /* register offsets */ |
| #define ICSCR 0x00 /* slave ctrl */ |
| @@ -95,6 +96,7 @@ struct rcar_i2c_priv { |
| struct i2c_msg *msg; |
| struct clk *clk; |
| |
| + spinlock_t lock; |
| wait_queue_head_t wait; |
| |
| int pos; |
| @@ -365,6 +367,9 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) |
| struct rcar_i2c_priv *priv = ptr; |
| u32 msr; |
| |
| + /*-------------- spin lock -----------------*/ |
| + spin_lock(&priv->lock); |
| + |
| msr = rcar_i2c_read(priv, ICMSR); |
| |
| /* Only handle interrupts that are currently enabled */ |
| @@ -403,6 +408,9 @@ out: |
| wake_up(&priv->wait); |
| } |
| |
| + spin_unlock(&priv->lock); |
| + /*-------------- spin unlock -----------------*/ |
| + |
| return IRQ_HANDLED; |
| } |
| |
| @@ -412,14 +420,21 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, |
| { |
| struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); |
| struct device *dev = rcar_i2c_priv_to_dev(priv); |
| + unsigned long flags; |
| int i, ret, timeout; |
| |
| pm_runtime_get_sync(dev); |
| |
| + /*-------------- spin lock -----------------*/ |
| + spin_lock_irqsave(&priv->lock, flags); |
| + |
| rcar_i2c_init(priv); |
| /* start clock */ |
| rcar_i2c_write(priv, ICCCR, priv->icccr); |
| |
| + spin_unlock_irqrestore(&priv->lock, flags); |
| + /*-------------- spin unlock -----------------*/ |
| + |
| ret = rcar_i2c_bus_barrier(priv); |
| if (ret < 0) |
| goto out; |
| @@ -431,6 +446,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, |
| break; |
| } |
| |
| + /*-------------- spin lock -----------------*/ |
| + spin_lock_irqsave(&priv->lock, flags); |
| + |
| /* init each data */ |
| priv->msg = &msgs[i]; |
| priv->pos = 0; |
| @@ -440,6 +458,9 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, |
| |
| ret = rcar_i2c_prepare_msg(priv); |
| |
| + spin_unlock_irqrestore(&priv->lock, flags); |
| + /*-------------- spin unlock -----------------*/ |
| + |
| if (ret < 0) |
| break; |
| |
| @@ -543,6 +564,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) |
| |
| irq = platform_get_irq(pdev, 0); |
| init_waitqueue_head(&priv->wait); |
| + spin_lock_init(&priv->lock); |
| |
| adap = &priv->adap; |
| adap->nr = pdev->id; |
| -- |
| 2.1.2 |
| |