diff options
| -rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 26 |
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 5f1b92c74bd9..c0b9aa7df0e2 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #define I2C_CNFG 0x000 | 37 | #define I2C_CNFG 0x000 |
| 38 | #define I2C_CNFG_PACKET_MODE_EN (1<<10) | 38 | #define I2C_CNFG_PACKET_MODE_EN (1<<10) |
| 39 | #define I2C_CNFG_NEW_MASTER_FSM (1<<11) | 39 | #define I2C_CNFG_NEW_MASTER_FSM (1<<11) |
| 40 | #define I2C_STATUS 0x01C | ||
| 40 | #define I2C_SL_CNFG 0x020 | 41 | #define I2C_SL_CNFG 0x020 |
| 41 | #define I2C_SL_CNFG_NEWSL (1<<2) | 42 | #define I2C_SL_CNFG_NEWSL (1<<2) |
| 42 | #define I2C_SL_ADDR1 0x02c | 43 | #define I2C_SL_ADDR1 0x02c |
| @@ -77,6 +78,7 @@ | |||
| 77 | #define I2C_ERR_NONE 0x00 | 78 | #define I2C_ERR_NONE 0x00 |
| 78 | #define I2C_ERR_NO_ACK 0x01 | 79 | #define I2C_ERR_NO_ACK 0x01 |
| 79 | #define I2C_ERR_ARBITRATION_LOST 0x02 | 80 | #define I2C_ERR_ARBITRATION_LOST 0x02 |
| 81 | #define I2C_ERR_UNKNOWN_INTERRUPT 0x04 | ||
| 80 | 82 | ||
| 81 | #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 | 83 | #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 |
| 82 | #define PACKET_HEADER0_PACKET_ID_SHIFT 16 | 84 | #define PACKET_HEADER0_PACKET_ID_SHIFT 16 |
| @@ -121,6 +123,7 @@ struct tegra_i2c_dev { | |||
| 121 | void __iomem *base; | 123 | void __iomem *base; |
| 122 | int cont_id; | 124 | int cont_id; |
| 123 | int irq; | 125 | int irq; |
| 126 | bool irq_disabled; | ||
| 124 | int is_dvc; | 127 | int is_dvc; |
| 125 | struct completion msg_complete; | 128 | struct completion msg_complete; |
| 126 | int msg_err; | 129 | int msg_err; |
| @@ -343,6 +346,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) | |||
| 343 | err = -ETIMEDOUT; | 346 | err = -ETIMEDOUT; |
| 344 | 347 | ||
| 345 | clk_disable(i2c_dev->clk); | 348 | clk_disable(i2c_dev->clk); |
| 349 | |||
| 350 | if (i2c_dev->irq_disabled) { | ||
| 351 | i2c_dev->irq_disabled = 0; | ||
| 352 | enable_irq(i2c_dev->irq); | ||
| 353 | } | ||
| 354 | |||
| 346 | return err; | 355 | return err; |
| 347 | } | 356 | } |
| 348 | 357 | ||
| @@ -355,8 +364,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) | |||
| 355 | status = i2c_readl(i2c_dev, I2C_INT_STATUS); | 364 | status = i2c_readl(i2c_dev, I2C_INT_STATUS); |
| 356 | 365 | ||
| 357 | if (status == 0) { | 366 | if (status == 0) { |
| 358 | dev_warn(i2c_dev->dev, "interrupt with no status\n"); | 367 | dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", |
| 359 | return IRQ_NONE; | 368 | i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), |
| 369 | i2c_readl(i2c_dev, I2C_STATUS), | ||
| 370 | i2c_readl(i2c_dev, I2C_CNFG)); | ||
| 371 | i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT; | ||
| 372 | |||
| 373 | if (!i2c_dev->irq_disabled) { | ||
| 374 | disable_irq_nosync(i2c_dev->irq); | ||
| 375 | i2c_dev->irq_disabled = 1; | ||
| 376 | } | ||
| 377 | |||
| 378 | complete(&i2c_dev->msg_complete); | ||
| 379 | goto err; | ||
| 360 | } | 380 | } |
| 361 | 381 | ||
| 362 | if (unlikely(status & status_err)) { | 382 | if (unlikely(status & status_err)) { |
| @@ -396,6 +416,8 @@ err: | |||
| 396 | I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | | 416 | I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ | |
| 397 | I2C_INT_RX_FIFO_DATA_REQ); | 417 | I2C_INT_RX_FIFO_DATA_REQ); |
| 398 | i2c_writel(i2c_dev, status, I2C_INT_STATUS); | 418 | i2c_writel(i2c_dev, status, I2C_INT_STATUS); |
| 419 | if (i2c_dev->is_dvc) | ||
| 420 | dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); | ||
| 399 | return IRQ_HANDLED; | 421 | return IRQ_HANDLED; |
| 400 | } | 422 | } |
| 401 | 423 | ||
