pwm: rockchip: Add APB and function both clocks support
authorDavid Wu <david.wu@rock-chips.com>
Tue, 8 Aug 2017 15:38:29 +0000 (23:38 +0800)
committerThierry Reding <thierry.reding@gmail.com>
Fri, 18 Aug 2017 15:31:56 +0000 (17:31 +0200)
New PWM module provides two individual clocks for APB clock and function
clock.

Signed-off-by: David Wu <david.wu@rock-chips.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Documentation/devicetree/bindings/pwm/pwm-rockchip.txt
drivers/pwm/pwm-rockchip.c

index b8be3d09ee26b7522fa373eefd1903aef8ce3d41..2350ef918befacb0c4b0915f79526badde9b4ed7 100644 (file)
@@ -6,7 +6,13 @@ Required properties:
    "rockchip,rk3288-pwm": found on RK3288 SoC
    "rockchip,vop-pwm": found integrated in VOP on RK3288 SoC
  - reg: physical base address and length of the controller's registers
- - clocks: phandle and clock specifier of the PWM reference clock
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk2928, rk3066, rk3188, rk3228, rk3288, rk3399):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.
+   - For newer hardware (rk3328 and future socs): specified by name
+     - "pwm": This is used to derive the functional clock.
+     - "pclk": This is the APB bus clock.
  - #pwm-cells: must be 2 (rk2928) or 3 (rk3288). See pwm.txt in this directory
    for a description of the cell format.
 
index 744d56197286a45eb148de437d31a3c3ca8fbd1a..ac3cd5ec5310d5e5bae276c1d04a21f9d808fb72 100644 (file)
@@ -33,6 +33,7 @@
 struct rockchip_pwm_chip {
        struct pwm_chip chip;
        struct clk *clk;
+       struct clk *pclk;
        const struct rockchip_pwm_data *data;
        void __iomem *base;
 };
@@ -145,7 +146,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
        u64 tmp;
        int ret;
 
-       ret = clk_enable(pc->clk);
+       ret = clk_enable(pc->pclk);
        if (ret)
                return;
 
@@ -161,7 +162,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip,
 
        pc->data->get_state(chip, pwm, state);
 
-       clk_disable(pc->clk);
+       clk_disable(pc->pclk);
 }
 
 static int rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@ -224,7 +225,7 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        pwm_get_state(pwm, &curstate);
        enabled = curstate.enabled;
 
-       ret = clk_enable(pc->clk);
+       ret = clk_enable(pc->pclk);
        if (ret)
                return ret;
 
@@ -257,7 +258,7 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
        rockchip_pwm_get_state(chip, pwm, state);
 
 out:
-       clk_disable(pc->clk);
+       clk_disable(pc->pclk);
 
        return ret;
 }
@@ -328,7 +329,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
        const struct of_device_id *id;
        struct rockchip_pwm_chip *pc;
        struct resource *r;
-       int ret;
+       int ret, count;
 
        id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev);
        if (!id)
@@ -343,13 +344,43 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
        if (IS_ERR(pc->base))
                return PTR_ERR(pc->base);
 
-       pc->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pc->clk))
-               return PTR_ERR(pc->clk);
+       pc->clk = devm_clk_get(&pdev->dev, "pwm");
+       if (IS_ERR(pc->clk)) {
+               pc->clk = devm_clk_get(&pdev->dev, NULL);
+               if (IS_ERR(pc->clk)) {
+                       ret = PTR_ERR(pc->clk);
+                       if (ret != -EPROBE_DEFER)
+                               dev_err(&pdev->dev, "Can't get bus clk: %d\n",
+                                       ret);
+                       return ret;
+               }
+       }
+
+       count = of_count_phandle_with_args(pdev->dev.of_node,
+                                          "clocks", "#clock-cells");
+       if (count == 2)
+               pc->pclk = devm_clk_get(&pdev->dev, "pclk");
+       else
+               pc->pclk = pc->clk;
+
+       if (IS_ERR(pc->pclk)) {
+               ret = PTR_ERR(pc->pclk);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "Can't get APB clk: %d\n", ret);
+               return ret;
+       }
 
        ret = clk_prepare_enable(pc->clk);
-       if (ret)
+       if (ret) {
+               dev_err(&pdev->dev, "Can't prepare enable bus clk: %d\n", ret);
                return ret;
+       }
+
+       ret = clk_prepare(pc->pclk);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't prepare APB clk: %d\n", ret);
+               goto err_clk;
+       }
 
        platform_set_drvdata(pdev, pc);
 
@@ -368,12 +399,20 @@ static int rockchip_pwm_probe(struct platform_device *pdev)
        if (ret < 0) {
                clk_unprepare(pc->clk);
                dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+               goto err_pclk;
        }
 
        /* Keep the PWM clk enabled if the PWM appears to be up and running. */
        if (!pwm_is_enabled(pc->chip.pwms))
                clk_disable(pc->clk);
 
+       return 0;
+
+err_pclk:
+       clk_unprepare(pc->pclk);
+err_clk:
+       clk_disable_unprepare(pc->clk);
+
        return ret;
 }
 
@@ -395,6 +434,7 @@ static int rockchip_pwm_remove(struct platform_device *pdev)
        if (pwm_is_enabled(pc->chip.pwms))
                clk_disable(pc->clk);
 
+       clk_unprepare(pc->pclk);
        clk_unprepare(pc->clk);
 
        return pwmchip_remove(&pc->chip);