qup_i2c: Reset QUP before registering for interrupts.
If bootloaders leave a pending interrupt on certain GSBI's,
the driver registers for an interrupt handler during boot up.
The interrupt handler immediately fires because the interrupt was
triggered in the bootloader. The ahb clock is also off at this time,
hence any register writes in the interrupt handler does not go through.
Thus we loop forever in the interrupt handler effectively hanging the
device.
CRs-Fixed: 345805
Change-Id: I5545785142a39f8b78132745e74dfc55a8a5c917
Signed-off-by: Harini Jayaraman <harinij@codeaurora.org>
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index e11979b..8476033 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -1254,6 +1254,18 @@
dev->pos = 0;
/*
+ * If bootloaders leave a pending interrupt on certain GSBI's,
+ * then we reset the core before registering for interrupts.
+ */
+ clk_prepare_enable(dev->clk);
+ clk_prepare_enable(dev->pclk);
+ writel_relaxed(1, dev->base + QUP_SW_RESET);
+ if (qup_i2c_poll_state(dev, 0, true) != 0)
+ goto err_reset_failed;
+ clk_disable_unprepare(dev->clk);
+ clk_disable_unprepare(dev->pclk);
+
+ /*
* We use num_irqs to also indicate if we got 3 interrupts or just 1.
* If we have just 1, we use err_irq as the general purpose irq
* and handle the changes in ISR accordingly
@@ -1337,6 +1349,9 @@
qup_i2c_free_gpios(dev);
if (dev->gsbi)
iounmap(dev->gsbi);
+err_reset_failed:
+ clk_disable_unprepare(dev->clk);
+ clk_disable_unprepare(dev->pclk);
err_request_gpio_failed:
err_gsbi_failed:
iounmap(dev->base);