From 4a45831e4fc5204f7d72c5628a1b0167f78a94ce Mon Sep 17 00:00:00 2001 From: Samuel Holland 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 --- 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