The i2c controller needs to read back the data written to its registers. This way we can avoid the long delay in the interrupt handler. Signed-off-by: Marc Dietrich <marvin24@xxxxxx> --- drivers/staging/nvec/nvec.c | 39 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 282a664c9176..9914c30b6933 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -565,6 +565,20 @@ static void nvec_tx_set(struct nvec_chip *nvec) (uint)nvec->tx->size, nvec->tx->data[1]); } +/** + * i2c_writel - savely write to an i2c client controller register + @ val: value to be written + @ reg: register to write to + */ + +static void i2c_writel(u32 val, void *reg) +{ + writel_relaxed(val, reg); + + /* read back register to make sure that register writes completed */ + readl_relaxed(reg); +} + /** * nvec_interrupt - Interrupt handler * @irq: The IRQ @@ -599,7 +613,7 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) if ((status & RNW) == 0) { received = readl(nvec->base + I2C_SL_RCVD); if (status & RCVD) - writel(0, nvec->base + I2C_SL_RCVD); + i2c_writel(0, nvec->base + I2C_SL_RCVD); } if (status == (I2C_SL_IRQ | RCVD)) @@ -691,7 +705,7 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) /* Send data if requested, but not on end of transmission */ if ((status & (RNW | END_TRANS)) == RNW) - writel(to_send, nvec->base + I2C_SL_RCVD); + i2c_writel(to_send, nvec->base + I2C_SL_RCVD); /* If we have send the first byte */ if (status == (I2C_SL_IRQ | RNW | RCVD)) @@ -708,15 +722,6 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) status & RCVD ? " RCVD" : "", status & RNW ? " RNW" : ""); - /* - * TODO: replace the udelay with a read back after each writel above - * in order to work around a hardware issue, see i2c-tegra.c - * - * Unfortunately, this change causes an intialisation issue with the - * touchpad, which needs to be fixed first. - */ - udelay(100); - return IRQ_HANDLED; } @@ -732,15 +737,15 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec) val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); - writel(val, nvec->base + I2C_CNFG); + i2c_writel(val, nvec->base + I2C_CNFG); clk_set_rate(nvec->i2c_clk, 8 * 80000); - writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); - writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); + i2c_writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); + i2c_writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); - writel(nvec->i2c_addr >> 1, nvec->base + I2C_SL_ADDR1); - writel(0, nvec->base + I2C_SL_ADDR2); + i2c_writel(nvec->i2c_addr >> 1, nvec->base + I2C_SL_ADDR1); + i2c_writel(0, nvec->base + I2C_SL_ADDR2); enable_irq(nvec->irq); } @@ -749,7 +754,7 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec) static void nvec_disable_i2c_slave(struct nvec_chip *nvec) { disable_irq(nvec->irq); - writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG); + i2c_writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG); clk_disable_unprepare(nvec->i2c_clk); } #endif -- 2.43.0