diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-tegra.c')
-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 | ||