Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95046a50 authored by Christian Eggers's avatar Christian Eggers Committed by Greg Kroah-Hartman
Browse files

i2c: imx: Fix reset of I2SR_IAL flag



commit 384a9565f70a876c2e78e58c5ca0bbf0547e4f6d upstream.

According to the "VFxxx Controller Reference Manual" (and the comment
block starting at line 97), Vybrid requires writing a one for clearing
an interrupt flag. Syncing the method for clearing I2SR_IIF in
i2c_imx_isr().

Signed-off-by: default avatarChristian Eggers <ceggers@arri.de>
Fixes: 4b775022 ("i2c: imx: add struct to hold more configurable quirks")
Reviewed-by: default avatarUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Acked-by: default avatarOleksij Rempel <o.rempel@pengutronix.de>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent da407a00
Loading
Loading
Loading
Loading
+15 −5
Original line number Diff line number Diff line
@@ -413,6 +413,19 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx)
	dma->chan_using = NULL;
}

static void i2c_imx_clear_irq(struct imx_i2c_struct *i2c_imx, unsigned int bits)
{
	unsigned int temp;

	/*
	 * i2sr_clr_opcode is the value to clear all interrupts. Here we want to
	 * clear only <bits>, so we write ~i2sr_clr_opcode with just <bits>
	 * toggled. This is required because i.MX needs W0C and Vybrid uses W1C.
	 */
	temp = ~i2c_imx->hwdata->i2sr_clr_opcode ^ bits;
	imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
}

static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)
{
	unsigned long orig_jiffies = jiffies;
@@ -425,8 +438,7 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy)

		/* check for arbitration lost */
		if (temp & I2SR_IAL) {
			temp &= ~I2SR_IAL;
			imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
			i2c_imx_clear_irq(i2c_imx, I2SR_IAL);
			return -EAGAIN;
		}

@@ -595,9 +607,7 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id)
	if (temp & I2SR_IIF) {
		/* save status register */
		i2c_imx->i2csr = temp;
		temp &= ~I2SR_IIF;
		temp |= (i2c_imx->hwdata->i2sr_clr_opcode & I2SR_IIF);
		imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2SR);
		i2c_imx_clear_irq(i2c_imx, I2SR_IIF);
		wake_up(&i2c_imx->queue);
		return IRQ_HANDLED;
	}