diff options
-rw-r--r-- | drivers/i2c/busses/i2c-uniphier-f.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index a403e8579b65..200dfd1771af 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c | |||
@@ -98,6 +98,7 @@ struct uniphier_fi2c_priv { | |||
98 | unsigned int flags; | 98 | unsigned int flags; |
99 | unsigned int busy_cnt; | 99 | unsigned int busy_cnt; |
100 | unsigned int clk_cycle; | 100 | unsigned int clk_cycle; |
101 | spinlock_t lock; /* IRQ synchronization */ | ||
101 | }; | 102 | }; |
102 | 103 | ||
103 | static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, | 104 | static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, |
@@ -162,7 +163,10 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) | |||
162 | struct uniphier_fi2c_priv *priv = dev_id; | 163 | struct uniphier_fi2c_priv *priv = dev_id; |
163 | u32 irq_status; | 164 | u32 irq_status; |
164 | 165 | ||
166 | spin_lock(&priv->lock); | ||
167 | |||
165 | irq_status = readl(priv->membase + UNIPHIER_FI2C_INT); | 168 | irq_status = readl(priv->membase + UNIPHIER_FI2C_INT); |
169 | irq_status &= priv->enabled_irqs; | ||
166 | 170 | ||
167 | dev_dbg(&priv->adap.dev, | 171 | dev_dbg(&priv->adap.dev, |
168 | "interrupt: enabled_irqs=%04x, irq_status=%04x\n", | 172 | "interrupt: enabled_irqs=%04x, irq_status=%04x\n", |
@@ -230,6 +234,8 @@ static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id) | |||
230 | goto handled; | 234 | goto handled; |
231 | } | 235 | } |
232 | 236 | ||
237 | spin_unlock(&priv->lock); | ||
238 | |||
233 | return IRQ_NONE; | 239 | return IRQ_NONE; |
234 | 240 | ||
235 | data_done: | 241 | data_done: |
@@ -246,6 +252,8 @@ complete: | |||
246 | handled: | 252 | handled: |
247 | uniphier_fi2c_clear_irqs(priv); | 253 | uniphier_fi2c_clear_irqs(priv); |
248 | 254 | ||
255 | spin_unlock(&priv->lock); | ||
256 | |||
249 | return IRQ_HANDLED; | 257 | return IRQ_HANDLED; |
250 | } | 258 | } |
251 | 259 | ||
@@ -311,7 +319,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, | |||
311 | { | 319 | { |
312 | struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); | 320 | struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); |
313 | bool is_read = msg->flags & I2C_M_RD; | 321 | bool is_read = msg->flags & I2C_M_RD; |
314 | unsigned long time_left; | 322 | unsigned long time_left, flags; |
315 | 323 | ||
316 | dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", | 324 | dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n", |
317 | is_read ? "receive" : "transmit", msg->addr, msg->len, stop); | 325 | is_read ? "receive" : "transmit", msg->addr, msg->len, stop); |
@@ -342,6 +350,12 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, | |||
342 | priv->membase + UNIPHIER_FI2C_CR); | 350 | priv->membase + UNIPHIER_FI2C_CR); |
343 | 351 | ||
344 | time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); | 352 | time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); |
353 | |||
354 | spin_lock_irqsave(&priv->lock, flags); | ||
355 | priv->enabled_irqs = 0; | ||
356 | uniphier_fi2c_set_irqs(priv); | ||
357 | spin_unlock_irqrestore(&priv->lock, flags); | ||
358 | |||
345 | if (!time_left) { | 359 | if (!time_left) { |
346 | dev_err(&adap->dev, "transaction timeout.\n"); | 360 | dev_err(&adap->dev, "transaction timeout.\n"); |
347 | uniphier_fi2c_recover(priv); | 361 | uniphier_fi2c_recover(priv); |
@@ -529,6 +543,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) | |||
529 | 543 | ||
530 | priv->clk_cycle = clk_rate / bus_speed; | 544 | priv->clk_cycle = clk_rate / bus_speed; |
531 | init_completion(&priv->comp); | 545 | init_completion(&priv->comp); |
546 | spin_lock_init(&priv->lock); | ||
532 | priv->adap.owner = THIS_MODULE; | 547 | priv->adap.owner = THIS_MODULE; |
533 | priv->adap.algo = &uniphier_fi2c_algo; | 548 | priv->adap.algo = &uniphier_fi2c_algo; |
534 | priv->adap.dev.parent = dev; | 549 | priv->adap.dev.parent = dev; |