bus: sunxi-rsb: Split out controller init/exit functions
authorSamuel Holland <samuel@sholland.org>
Sun, 3 Jan 2021 11:06:33 +0000 (05:06 -0600)
committerChen-Yu Tsai <wens@csie.org>
Wed, 6 Jan 2021 11:33:57 +0000 (19:33 +0800)
This separates the resource acquisition from the hardware initialization
phase, so the hardware initialization can be repeated after system
suspend/resume. The same is done for the exit/remove function, except
that there is no resource deallocation phase due to the use of devres.

The requested RSB clock frequency is stored in `struct sunxi_rsb` so it
will be available when reinitializing the hardware.

Signed-off-by: Samuel Holland <samuel@sholland.org>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
drivers/bus/sunxi-rsb.c

index c13340c..3f290da 100644 (file)
@@ -126,6 +126,7 @@ struct sunxi_rsb {
        struct completion complete;
        struct mutex lock;
        unsigned int status;
+       u32 clk_freq;
 };
 
 /* bus / slave device related functions */
@@ -614,16 +615,74 @@ static int of_rsb_register_devices(struct sunxi_rsb *rsb)
        return 0;
 }
 
+static int sunxi_rsb_hw_init(struct sunxi_rsb *rsb)
+{
+       struct device *dev = rsb->dev;
+       unsigned long p_clk_freq;
+       u32 clk_delay, reg;
+       int clk_div, ret;
+
+       ret = clk_prepare_enable(rsb->clk);
+       if (ret) {
+               dev_err(dev, "failed to enable clk: %d\n", ret);
+               return ret;
+       }
+
+       ret = reset_control_deassert(rsb->rstc);
+       if (ret) {
+               dev_err(dev, "failed to deassert reset line: %d\n", ret);
+               goto err_clk_disable;
+       }
+
+       /* reset the controller */
+       writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL);
+       readl_poll_timeout(rsb->regs + RSB_CTRL, reg,
+                          !(reg & RSB_CTRL_SOFT_RST), 1000, 100000);
+
+       /*
+        * Clock frequency and delay calculation code is from
+        * Allwinner U-boot sources.
+        *
+        * From A83 user manual:
+        * bus clock frequency = parent clock frequency / (2 * (divider + 1))
+        */
+       p_clk_freq = clk_get_rate(rsb->clk);
+       clk_div = p_clk_freq / rsb->clk_freq / 2;
+       if (!clk_div)
+               clk_div = 1;
+       else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1)
+               clk_div = RSB_CCR_MAX_CLK_DIV + 1;
+
+       clk_delay = clk_div >> 1;
+       if (!clk_delay)
+               clk_delay = 1;
+
+       dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2);
+       writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1),
+              rsb->regs + RSB_CCR);
+
+       return 0;
+
+err_clk_disable:
+       clk_disable_unprepare(rsb->clk);
+
+       return ret;
+}
+
+static void sunxi_rsb_hw_exit(struct sunxi_rsb *rsb)
+{
+       reset_control_assert(rsb->rstc);
+       clk_disable_unprepare(rsb->clk);
+}
+
 static int sunxi_rsb_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct device_node *np = dev->of_node;
        struct resource *r;
        struct sunxi_rsb *rsb;
-       unsigned long p_clk_freq;
-       u32 clk_delay, clk_freq = 3000000;
-       int clk_div, irq, ret;
-       u32 reg;
+       u32 clk_freq = 3000000;
+       int irq, ret;
 
        of_property_read_u32(np, "clock-frequency", &clk_freq);
        if (clk_freq > RSB_MAX_FREQ) {
@@ -638,6 +697,7 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        rsb->dev = dev;
+       rsb->clk_freq = clk_freq;
        platform_set_drvdata(pdev, rsb);
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        rsb->regs = devm_ioremap_resource(dev, r);
@@ -655,63 +715,27 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = clk_prepare_enable(rsb->clk);
-       if (ret) {
-               dev_err(dev, "failed to enable clk: %d\n", ret);
-               return ret;
-       }
-
-       p_clk_freq = clk_get_rate(rsb->clk);
-
        rsb->rstc = devm_reset_control_get(dev, NULL);
        if (IS_ERR(rsb->rstc)) {
                ret = PTR_ERR(rsb->rstc);
                dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
-               goto err_clk_disable;
-       }
-
-       ret = reset_control_deassert(rsb->rstc);
-       if (ret) {
-               dev_err(dev, "failed to deassert reset line: %d\n", ret);
-               goto err_clk_disable;
+               return ret;
        }
 
        init_completion(&rsb->complete);
        mutex_init(&rsb->lock);
 
-       /* reset the controller */
-       writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL);
-       readl_poll_timeout(rsb->regs + RSB_CTRL, reg,
-                          !(reg & RSB_CTRL_SOFT_RST), 1000, 100000);
-
-       /*
-        * Clock frequency and delay calculation code is from
-        * Allwinner U-boot sources.
-        *
-        * From A83 user manual:
-        * bus clock frequency = parent clock frequency / (2 * (divider + 1))
-        */
-       clk_div = p_clk_freq / clk_freq / 2;
-       if (!clk_div)
-               clk_div = 1;
-       else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1)
-               clk_div = RSB_CCR_MAX_CLK_DIV + 1;
-
-       clk_delay = clk_div >> 1;
-       if (!clk_delay)
-               clk_delay = 1;
-
-       dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2);
-       writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1),
-              rsb->regs + RSB_CCR);
-
        ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb);
        if (ret) {
                dev_err(dev, "can't register interrupt handler irq %d: %d\n",
                        irq, ret);
-               goto err_reset_assert;
+               return ret;
        }
 
+       ret = sunxi_rsb_hw_init(rsb);
+       if (ret)
+               return ret;
+
        /* initialize all devices on the bus into RSB mode */
        ret = sunxi_rsb_init_device_mode(rsb);
        if (ret)
@@ -720,14 +744,6 @@ static int sunxi_rsb_probe(struct platform_device *pdev)
        of_rsb_register_devices(rsb);
 
        return 0;
-
-err_reset_assert:
-       reset_control_assert(rsb->rstc);
-
-err_clk_disable:
-       clk_disable_unprepare(rsb->clk);
-
-       return ret;
 }
 
 static int sunxi_rsb_remove(struct platform_device *pdev)
@@ -735,8 +751,7 @@ static int sunxi_rsb_remove(struct platform_device *pdev)
        struct sunxi_rsb *rsb = platform_get_drvdata(pdev);
 
        device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices);
-       reset_control_assert(rsb->rstc);
-       clk_disable_unprepare(rsb->clk);
+       sunxi_rsb_hw_exit(rsb);
 
        return 0;
 }