diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-09-05 16:45:09 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-09-05 16:45:09 -0400 |
| commit | 86ba8b0aee711b01fa5a14868035a3f4d6b1e1d9 (patch) | |
| tree | e668317a21cb7bc41969847d8e735a3b11ea35a5 | |
| parent | fb762340e55638332407560396aea380b7af9cbf (diff) | |
| parent | 91bfe2989af02e709ca01ccf518c4fbda3efc70f (diff) | |
Merge branch 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c bugfixes from Wolfram Sang:
"I2C driver bugfixes for the 3.17 release. Details can be found in the
commit messages, yet I think this is typical driver stuff"
* 'i2c/for-current' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux:
Revert "i2c: rcar: remove spinlock"
i2c: at91: add bound checking on SMBus block length bytes
i2c: rk3x: fix bug that cause transfer fails in master receive mode
i2c: at91: Fix a race condition during signal handling in at91_do_twi_xfer.
i2c: mv64xxx: continue probe when clock-frequency is missing
i2c: rcar: fix MNR interrupt handling
| -rw-r--r-- | drivers/i2c/busses/i2c-at91.c | 32 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-mv64xxx.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-rcar.c | 37 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-rk3x.c | 4 |
4 files changed, 62 insertions, 14 deletions
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 79a68999a696..917d54588d95 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c | |||
| @@ -101,6 +101,7 @@ struct at91_twi_dev { | |||
| 101 | unsigned twi_cwgr_reg; | 101 | unsigned twi_cwgr_reg; |
| 102 | struct at91_twi_pdata *pdata; | 102 | struct at91_twi_pdata *pdata; |
| 103 | bool use_dma; | 103 | bool use_dma; |
| 104 | bool recv_len_abort; | ||
| 104 | struct at91_twi_dma dma; | 105 | struct at91_twi_dma dma; |
| 105 | }; | 106 | }; |
| 106 | 107 | ||
| @@ -267,12 +268,24 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) | |||
| 267 | *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; | 268 | *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; |
| 268 | --dev->buf_len; | 269 | --dev->buf_len; |
| 269 | 270 | ||
| 271 | /* return if aborting, we only needed to read RHR to clear RXRDY*/ | ||
| 272 | if (dev->recv_len_abort) | ||
| 273 | return; | ||
| 274 | |||
| 270 | /* handle I2C_SMBUS_BLOCK_DATA */ | 275 | /* handle I2C_SMBUS_BLOCK_DATA */ |
| 271 | if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { | 276 | if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { |
| 272 | dev->msg->flags &= ~I2C_M_RECV_LEN; | 277 | /* ensure length byte is a valid value */ |
| 273 | dev->buf_len += *dev->buf; | 278 | if (*dev->buf <= I2C_SMBUS_BLOCK_MAX && *dev->buf > 0) { |
| 274 | dev->msg->len = dev->buf_len + 1; | 279 | dev->msg->flags &= ~I2C_M_RECV_LEN; |
| 275 | dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); | 280 | dev->buf_len += *dev->buf; |
| 281 | dev->msg->len = dev->buf_len + 1; | ||
| 282 | dev_dbg(dev->dev, "received block length %d\n", | ||
| 283 | dev->buf_len); | ||
| 284 | } else { | ||
| 285 | /* abort and send the stop by reading one more byte */ | ||
| 286 | dev->recv_len_abort = true; | ||
| 287 | dev->buf_len = 1; | ||
| 288 | } | ||
| 276 | } | 289 | } |
| 277 | 290 | ||
| 278 | /* send stop if second but last byte has been read */ | 291 | /* send stop if second but last byte has been read */ |
| @@ -421,8 +434,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) | |||
| 421 | } | 434 | } |
| 422 | } | 435 | } |
| 423 | 436 | ||
| 424 | ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, | 437 | ret = wait_for_completion_io_timeout(&dev->cmd_complete, |
| 425 | dev->adapter.timeout); | 438 | dev->adapter.timeout); |
| 426 | if (ret == 0) { | 439 | if (ret == 0) { |
| 427 | dev_err(dev->dev, "controller timed out\n"); | 440 | dev_err(dev->dev, "controller timed out\n"); |
| 428 | at91_init_twi_bus(dev); | 441 | at91_init_twi_bus(dev); |
| @@ -444,6 +457,12 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) | |||
| 444 | ret = -EIO; | 457 | ret = -EIO; |
| 445 | goto error; | 458 | goto error; |
| 446 | } | 459 | } |
| 460 | if (dev->recv_len_abort) { | ||
| 461 | dev_err(dev->dev, "invalid smbus block length recvd\n"); | ||
| 462 | ret = -EPROTO; | ||
| 463 | goto error; | ||
| 464 | } | ||
| 465 | |||
| 447 | dev_dbg(dev->dev, "transfer complete\n"); | 466 | dev_dbg(dev->dev, "transfer complete\n"); |
| 448 | 467 | ||
| 449 | return 0; | 468 | return 0; |
| @@ -500,6 +519,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) | |||
| 500 | dev->buf_len = m_start->len; | 519 | dev->buf_len = m_start->len; |
| 501 | dev->buf = m_start->buf; | 520 | dev->buf = m_start->buf; |
| 502 | dev->msg = m_start; | 521 | dev->msg = m_start; |
| 522 | dev->recv_len_abort = false; | ||
| 503 | 523 | ||
| 504 | ret = at91_do_twi_transfer(dev); | 524 | ret = at91_do_twi_transfer(dev); |
| 505 | 525 | ||
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6dc5ded86f62..2f64273d3f2b 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c | |||
| @@ -746,8 +746,7 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, | |||
| 746 | } | 746 | } |
| 747 | tclk = clk_get_rate(drv_data->clk); | 747 | tclk = clk_get_rate(drv_data->clk); |
| 748 | 748 | ||
| 749 | rc = of_property_read_u32(np, "clock-frequency", &bus_freq); | 749 | if (of_property_read_u32(np, "clock-frequency", &bus_freq)) |
| 750 | if (rc) | ||
| 751 | bus_freq = 100000; /* 100kHz by default */ | 750 | bus_freq = 100000; /* 100kHz by default */ |
| 752 | 751 | ||
| 753 | if (!mv64xxx_find_baud_factors(bus_freq, tclk, | 752 | if (!mv64xxx_find_baud_factors(bus_freq, tclk, |
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index f3c7139dfa25..1cc146cfc1f3 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c | |||
| @@ -34,6 +34,7 @@ | |||
| 34 | #include <linux/platform_device.h> | 34 | #include <linux/platform_device.h> |
| 35 | #include <linux/pm_runtime.h> | 35 | #include <linux/pm_runtime.h> |
| 36 | #include <linux/slab.h> | 36 | #include <linux/slab.h> |
| 37 | #include <linux/spinlock.h> | ||
| 37 | 38 | ||
| 38 | /* register offsets */ | 39 | /* register offsets */ |
| 39 | #define ICSCR 0x00 /* slave ctrl */ | 40 | #define ICSCR 0x00 /* slave ctrl */ |
| @@ -95,6 +96,7 @@ struct rcar_i2c_priv { | |||
| 95 | struct i2c_msg *msg; | 96 | struct i2c_msg *msg; |
| 96 | struct clk *clk; | 97 | struct clk *clk; |
| 97 | 98 | ||
| 99 | spinlock_t lock; | ||
| 98 | wait_queue_head_t wait; | 100 | wait_queue_head_t wait; |
| 99 | 101 | ||
| 100 | int pos; | 102 | int pos; |
| @@ -365,20 +367,20 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) | |||
| 365 | struct rcar_i2c_priv *priv = ptr; | 367 | struct rcar_i2c_priv *priv = ptr; |
| 366 | u32 msr; | 368 | u32 msr; |
| 367 | 369 | ||
| 370 | /*-------------- spin lock -----------------*/ | ||
| 371 | spin_lock(&priv->lock); | ||
| 372 | |||
| 368 | msr = rcar_i2c_read(priv, ICMSR); | 373 | msr = rcar_i2c_read(priv, ICMSR); |
| 369 | 374 | ||
| 375 | /* Only handle interrupts that are currently enabled */ | ||
| 376 | msr &= rcar_i2c_read(priv, ICMIER); | ||
| 377 | |||
| 370 | /* Arbitration lost */ | 378 | /* Arbitration lost */ |
| 371 | if (msr & MAL) { | 379 | if (msr & MAL) { |
| 372 | rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); | 380 | rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); |
| 373 | goto out; | 381 | goto out; |
| 374 | } | 382 | } |
| 375 | 383 | ||
| 376 | /* Stop */ | ||
| 377 | if (msr & MST) { | ||
| 378 | rcar_i2c_flags_set(priv, ID_DONE); | ||
| 379 | goto out; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* Nack */ | 384 | /* Nack */ |
| 383 | if (msr & MNR) { | 385 | if (msr & MNR) { |
| 384 | /* go to stop phase */ | 386 | /* go to stop phase */ |
| @@ -388,6 +390,12 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr) | |||
| 388 | goto out; | 390 | goto out; |
| 389 | } | 391 | } |
| 390 | 392 | ||
| 393 | /* Stop */ | ||
| 394 | if (msr & MST) { | ||
| 395 | rcar_i2c_flags_set(priv, ID_DONE); | ||
| 396 | goto out; | ||
| 397 | } | ||
| 398 | |||
| 391 | if (rcar_i2c_is_recv(priv)) | 399 | if (rcar_i2c_is_recv(priv)) |
| 392 | rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); | 400 | rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); |
| 393 | else | 401 | else |
| @@ -400,6 +408,9 @@ out: | |||
| 400 | wake_up(&priv->wait); | 408 | wake_up(&priv->wait); |
| 401 | } | 409 | } |
| 402 | 410 | ||
| 411 | spin_unlock(&priv->lock); | ||
| 412 | /*-------------- spin unlock -----------------*/ | ||
| 413 | |||
| 403 | return IRQ_HANDLED; | 414 | return IRQ_HANDLED; |
| 404 | } | 415 | } |
| 405 | 416 | ||
| @@ -409,14 +420,21 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, | |||
| 409 | { | 420 | { |
| 410 | struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); | 421 | struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); |
| 411 | struct device *dev = rcar_i2c_priv_to_dev(priv); | 422 | struct device *dev = rcar_i2c_priv_to_dev(priv); |
