Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

staging: nvec: make i2c controller register writes robust

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@gmx.de>
Reviewed-by: Thierry Reding <treding@nvidia.com>
Link: https://lore.kernel.org/r/20240526193932.57277-1-marvin24@gmx.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Marc Dietrich and committed by
Greg Kroah-Hartman
c8c96293 331fd192

+24 -17
+24 -17
drivers/staging/nvec/nvec.c
··· 571 571 } 572 572 573 573 /** 574 + * tegra_i2c_writel - safely write to an I2C client controller register 575 + * @val: value to be written 576 + * @reg: register to write to 577 + * 578 + * A write to an I2C controller register needs to be read back to make sure 579 + * that the value has arrived. 580 + */ 581 + static void tegra_i2c_writel(u32 val, void *reg) 582 + { 583 + writel_relaxed(val, reg); 584 + 585 + /* read back register to make sure that register writes completed */ 586 + readl_relaxed(reg); 587 + } 588 + 589 + /** 574 590 * nvec_interrupt - Interrupt handler 575 591 * @irq: The IRQ 576 592 * @dev: The nvec device ··· 620 604 if ((status & RNW) == 0) { 621 605 received = readl(nvec->base + I2C_SL_RCVD); 622 606 if (status & RCVD) 623 - writel(0, nvec->base + I2C_SL_RCVD); 607 + tegra_i2c_writel(0, nvec->base + I2C_SL_RCVD); 624 608 } 625 609 626 610 if (status == (I2C_SL_IRQ | RCVD)) ··· 712 696 713 697 /* Send data if requested, but not on end of transmission */ 714 698 if ((status & (RNW | END_TRANS)) == RNW) 715 - writel(to_send, nvec->base + I2C_SL_RCVD); 699 + tegra_i2c_writel(to_send, nvec->base + I2C_SL_RCVD); 716 700 717 701 /* If we have send the first byte */ 718 702 if (status == (I2C_SL_IRQ | RNW | RCVD)) ··· 729 713 status & RCVD ? " RCVD" : "", 730 714 status & RNW ? " RNW" : ""); 731 715 732 - /* 733 - * TODO: replace the udelay with a read back after each writel above 734 - * in order to work around a hardware issue, see i2c-tegra.c 735 - * 736 - * Unfortunately, this change causes an initialisation issue with the 737 - * touchpad, which needs to be fixed first. 738 - */ 739 - udelay(100); 740 - 741 716 return IRQ_HANDLED; 742 717 } 743 718 ··· 744 737 745 738 val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | 746 739 (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); 747 - writel(val, nvec->base + I2C_CNFG); 740 + tegra_i2c_writel(val, nvec->base + I2C_CNFG); 748 741 749 742 clk_set_rate(nvec->i2c_clk, 8 * 80000); 750 743 751 - writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); 752 - writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); 744 + tegra_i2c_writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); 745 + tegra_i2c_writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); 753 746 754 - writel(nvec->i2c_addr >> 1, nvec->base + I2C_SL_ADDR1); 755 - writel(0, nvec->base + I2C_SL_ADDR2); 747 + tegra_i2c_writel(nvec->i2c_addr >> 1, nvec->base + I2C_SL_ADDR1); 748 + tegra_i2c_writel(0, nvec->base + I2C_SL_ADDR2); 756 749 757 750 enable_irq(nvec->irq); 758 751 } ··· 761 754 static void nvec_disable_i2c_slave(struct nvec_chip *nvec) 762 755 { 763 756 disable_irq(nvec->irq); 764 - writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG); 757 + tegra_i2c_writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG); 765 758 clk_disable_unprepare(nvec->i2c_clk); 766 759 } 767 760 #endif