diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-exynos5.c')
-rw-r--r-- | drivers/i2c/busses/i2c-exynos5.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index bea607149972..cbd93ce0661f 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -130,12 +130,32 @@ /* I2C_TRANS_STATUS register bits */ #define HSI2C_MASTER_BUSY (1u << 17) #define HSI2C_SLAVE_BUSY (1u << 16) + +/* I2C_TRANS_STATUS register bits for Exynos5 variant */ #define HSI2C_TIMEOUT_AUTO (1u << 4) #define HSI2C_NO_DEV (1u << 3) #define HSI2C_NO_DEV_ACK (1u << 2) #define HSI2C_TRANS_ABORT (1u << 1) #define HSI2C_TRANS_DONE (1u << 0) +/* I2C_TRANS_STATUS register bits for Exynos7 variant */ +#define HSI2C_MASTER_ST_MASK 0xf +#define HSI2C_MASTER_ST_IDLE 0x0 +#define HSI2C_MASTER_ST_START 0x1 +#define HSI2C_MASTER_ST_RESTART 0x2 +#define HSI2C_MASTER_ST_STOP 0x3 +#define HSI2C_MASTER_ST_MASTER_ID 0x4 +#define HSI2C_MASTER_ST_ADDR0 0x5 +#define HSI2C_MASTER_ST_ADDR1 0x6 +#define HSI2C_MASTER_ST_ADDR2 0x7 +#define HSI2C_MASTER_ST_ADDR_SR 0x8 +#define HSI2C_MASTER_ST_READ 0x9 +#define HSI2C_MASTER_ST_WRITE 0xa +#define HSI2C_MASTER_ST_NO_ACK 0xb +#define HSI2C_MASTER_ST_LOSE 0xc +#define HSI2C_MASTER_ST_WAIT 0xd +#define HSI2C_MASTER_ST_WAIT_CMD 0xe + /* I2C_ADDR register bits */ #define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0) #define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) @@ -437,6 +457,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) int_status = readl(i2c->regs + HSI2C_INT_STATUS); writel(int_status, i2c->regs + HSI2C_INT_STATUS); + trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); /* handle interrupt related to the transfer status */ if (i2c->variant->hw == HSI2C_EXYNOS7) { @@ -460,8 +481,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->state = -ETIMEDOUT; goto stop; } + + if ((trans_status & HSI2C_MASTER_ST_MASK) == HSI2C_MASTER_ST_LOSE) { + i2c->state = -EAGAIN; + goto stop; + } } else if (int_status & HSI2C_INT_I2C) { - trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (trans_status & HSI2C_NO_DEV_ACK) { dev_dbg(i2c->dev, "No ACK from device\n"); i2c->state = -ENXIO; @@ -502,8 +527,13 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); len = i2c->variant->fifo_depth - fifo_level; - if (len > (i2c->msg->len - i2c->msg_ptr)) + if (len > (i2c->msg->len - i2c->msg_ptr)) { + u32 int_en = readl(i2c->regs + HSI2C_INT_ENABLE); + + int_en &= ~HSI2C_INT_TX_ALMOSTEMPTY_EN; + writel(int_en, i2c->regs + HSI2C_INT_ENABLE); len = i2c->msg->len - i2c->msg_ptr; + } while (len > 0) { byte = i2c->msg->buf[i2c->msg_ptr++]; |