|
@@ -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,20 +367,20 @@ 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 */
|
|
|
+ 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 +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
|
|
@@ -400,6 +408,9 @@ out:
|
|
|
wake_up(&priv->wait);
|
|
|
}
|
|
|
|
|
|
+ spin_unlock(&priv->lock);
|
|
|
+ /*-------------- spin unlock -----------------*/
|
|
|
+
|
|
|
return IRQ_HANDLED;
|
|
|
}
|
|
|
|
|
@@ -409,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;
|
|
@@ -428,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;
|
|
@@ -437,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;
|
|
|
|
|
@@ -540,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;
|