75 lines
2.7 KiB
Diff
75 lines
2.7 KiB
Diff
From 4a45831e4fc5204f7d72c5628a1b0167f78a94ce Mon Sep 17 00:00:00 2001
|
|
From: Samuel Holland <samuel@sholland.org>
|
|
Date: Mon, 30 Dec 2019 22:58:21 -0600
|
|
Subject: [PATCH 157/351] bus: sunxi-rsb: Make interrupt handling more robust
|
|
|
|
The RSB controller has two registers for controlling interrupt inputs:
|
|
RSB_INTE, which has bits for each possible interrupt, and the global
|
|
interrupt enable bit in RSB_CTRL.
|
|
|
|
Currently, we enable the bits in RSB_INTE before each transfer, but this
|
|
is unnecessary because we never disable them. Move the initialization of
|
|
RSB_INTE so it is done only once.
|
|
|
|
We also set the global interrupt enable bit before each transfer. Unlike
|
|
other bits in RSB_CTRL, this bit is cleared by writing a zero. Thus, we
|
|
clear the bit in the post-timeout cleanup code, but that is not
|
|
documented, so note that in the comment. However, in the success/error
|
|
path (when an IRQ is received), we do not disable further interrupts.
|
|
Add a register write to do just that.
|
|
|
|
Signed-off-by: Samuel Holland <samuel@sholland.org>
|
|
---
|
|
drivers/bus/sunxi-rsb.c | 14 ++++++++++----
|
|
1 file changed, 10 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c
|
|
index cbfbee32e15e..edb5f338f494 100644
|
|
--- a/drivers/bus/sunxi-rsb.c
|
|
+++ b/drivers/bus/sunxi-rsb.c
|
|
@@ -276,8 +276,6 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
|
|
|
|
reinit_completion(&rsb->complete);
|
|
|
|
- writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
|
|
- rsb->regs + RSB_INTE);
|
|
writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB,
|
|
rsb->regs + RSB_CTRL);
|
|
|
|
@@ -285,7 +283,7 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
|
|
msecs_to_jiffies(100))) {
|
|
dev_dbg(rsb->dev, "RSB timeout\n");
|
|
|
|
- /* abort the transfer */
|
|
+ /* abort the transfer and disable interrupts */
|
|
writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL);
|
|
|
|
/* clear any interrupt flags */
|
|
@@ -460,7 +458,8 @@ static irqreturn_t sunxi_rsb_irq(int irq, void *dev_id)
|
|
status = readl(rsb->regs + RSB_INTS);
|
|
rsb->status = status;
|
|
|
|
- /* Clear interrupts */
|
|
+ /* Disable and clear interrupts */
|
|
+ writel(0, rsb->regs + RSB_CTRL);
|
|
status &= (RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR |
|
|
RSB_INTS_TRANS_OVER);
|
|
writel(status, rsb->regs + RSB_INTS);
|
|
@@ -640,6 +639,13 @@ static int sunxi_rsb_init_controller(struct sunxi_rsb *rsb)
|
|
writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1),
|
|
rsb->regs + RSB_CCR);
|
|
|
|
+ /*
|
|
+ * Select the interrupts we care about. They will not actually fire
|
|
+ * until the RSB_CTRL_GLOBAL_INT_ENB bit is set.
|
|
+ */
|
|
+ writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
|
|
+ rsb->regs + RSB_INTE);
|
|
+
|
|
return 0;
|
|
|
|
err_clk_disable:
|
|
--
|
|
2.34.0
|
|
|