Skip to content

Commit 9c975c4

Browse files
Wolfram Sangwsakernel
authored andcommitted
i2c: rcar: protect against supurious interrupts on V3U
V3U creates spurious interrupts which we need to handle. This costs time until BUS_PHASE_DATA can be activated which is problematic for Gen2 SoCs and earlier. Because of this we introduce two interrupt handlers here which will call a generic main irq function once the timing critical stuff is done. Signed-off-by: Wolfram Sang <[email protected]> Reviewed-by: Niklas Söderlund <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 24c6d4b commit 9c975c4

File tree

1 file changed

+43
-14
lines changed

1 file changed

+43
-14
lines changed

drivers/i2c/busses/i2c-rcar.c

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -625,20 +625,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
625625
* generated. It turned out that taking a spinlock at the beginning of the ISR
626626
* was already causing repeated messages. Thus, this driver was converted to
627627
* the now lockless behaviour. Please keep this in mind when hacking the driver.
628+
* R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are
629+
* likely affected. Therefore, we have different interrupt handler entries.
628630
*/
629-
static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
631+
static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
630632
{
631-
struct rcar_i2c_priv *priv = ptr;
632-
u32 msr;
633-
634-
/* Clear START or STOP immediately, except for REPSTART after read */
635-
if (likely(!(priv->flags & ID_P_REP_AFTER_RD)))
636-
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
637-
638-
msr = rcar_i2c_read(priv, ICMSR);
639-
640-
/* Only handle interrupts that are currently enabled */
641-
msr &= rcar_i2c_read(priv, ICMIER);
642633
if (!msr) {
643634
if (rcar_i2c_slave_irq(priv))
644635
return IRQ_HANDLED;
@@ -682,6 +673,41 @@ static irqreturn_t rcar_i2c_irq(int irq, void *ptr)
682673
return IRQ_HANDLED;
683674
}
684675

676+
static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr)
677+
{
678+
struct rcar_i2c_priv *priv = ptr;
679+
u32 msr;
680+
681+
/* Clear START or STOP immediately, except for REPSTART after read */
682+
if (likely(!(priv->flags & ID_P_REP_AFTER_RD)))
683+
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
684+
685+
/* Only handle interrupts that are currently enabled */
686+
msr = rcar_i2c_read(priv, ICMSR);
687+
msr &= rcar_i2c_read(priv, ICMIER);
688+
689+
return rcar_i2c_irq(irq, priv, msr);
690+
}
691+
692+
static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr)
693+
{
694+
struct rcar_i2c_priv *priv = ptr;
695+
u32 msr;
696+
697+
/* Only handle interrupts that are currently enabled */
698+
msr = rcar_i2c_read(priv, ICMSR);
699+
msr &= rcar_i2c_read(priv, ICMIER);
700+
701+
/*
702+
* Clear START or STOP immediately, except for REPSTART after read or
703+
* if a spurious interrupt was detected.
704+
*/
705+
if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr))
706+
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
707+
708+
return rcar_i2c_irq(irq, priv, msr);
709+
}
710+
685711
static struct dma_chan *rcar_i2c_request_dma_chan(struct device *dev,
686712
enum dma_transfer_direction dir,
687713
dma_addr_t port_addr)
@@ -929,6 +955,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
929955
struct i2c_adapter *adap;
930956
struct device *dev = &pdev->dev;
931957
unsigned long irqflags = 0;
958+
irqreturn_t (*irqhandler)(int irq, void *ptr) = rcar_i2c_gen3_irq;
932959
int ret;
933960

934961
/* Otherwise logic will break because some bytes must always use PIO */
@@ -977,8 +1004,10 @@ static int rcar_i2c_probe(struct platform_device *pdev)
9771004

9781005
rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */
9791006

980-
if (priv->devtype < I2C_RCAR_GEN3)
1007+
if (priv->devtype < I2C_RCAR_GEN3) {
9811008
irqflags |= IRQF_NO_THREAD;
1009+
irqhandler = rcar_i2c_gen2_irq;
1010+
}
9821011

9831012
if (priv->devtype == I2C_RCAR_GEN3) {
9841013
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
@@ -999,7 +1028,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
9991028
priv->flags |= ID_P_HOST_NOTIFY;
10001029

10011030
priv->irq = platform_get_irq(pdev, 0);
1002-
ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, irqflags, dev_name(dev), priv);
1031+
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv);
10031032
if (ret < 0) {
10041033
dev_err(dev, "cannot get irq %d\n", priv->irq);
10051034
goto out_pm_disable;

0 commit comments

Comments
 (0)