drivers: clk: Fix using assigned-clocks in the node of the clock it sets up
authorJean-Jacques Hiblot <jjhiblot@ti.com>
Tue, 22 Oct 2019 12:00:06 +0000 (14:00 +0200)
committerLukasz Majewski <lukma@denx.de>
Tue, 22 Oct 2019 14:14:05 +0000 (16:14 +0200)
This fixes the case where assigned-clocks is used to define a clock
defaults inside this same clock's node. This is used sometimes to setup a
default parents and/or rate for a clock.

example:
muxed_clock: muxed_clock {
clocks = <&clk_provider 0>, <&clk_provider 1>;
#clock-cells = <0>;
assigned-clocks = <&muxed_clock>;
assigned-clock-parents = <&clk_provider 1>;
};

It doesn't work in u-boot because the assigned-clocks are setup *before*
the clock is probed. (clk_set_parent() will likely crash or fail if called
before the device probe function)
Making it work by handling "assigned-clocks" in 2 steps: first before the
clk device is probed, and then after the clk device is probed.

Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
drivers/clk/clk-uclass.c
drivers/core/device.c
include/clk.h

index 80346987b9dc7df77474410f09b1c5a68d37c296..9aa8537004a339ce910751bedafdf0d4ee9ea50c 100644 (file)
@@ -178,7 +178,7 @@ bulk_get_err:
        return ret;
 }
 
-static int clk_set_default_parents(struct udevice *dev)
+static int clk_set_default_parents(struct udevice *dev, int stage)
 {
        struct clk clk, parent_clk;
        int index;
@@ -214,8 +214,18 @@ static int clk_set_default_parents(struct udevice *dev)
                        return ret;
                }
 
-               ret = clk_set_parent(&clk, &parent_clk);
+               /* This is clk provider device trying to reparent itself
+                * It cannot be done right now but need to wait after the
+                * device is probed
+                */
+               if (stage == 0 && clk.dev == dev)
+                       continue;
+
+               if (stage > 0 && clk.dev != dev)
+                       /* do not setup twice the parent clocks */
+                       continue;
 
+               ret = clk_set_parent(&clk, &parent_clk);
                /*
                 * Not all drivers may support clock-reparenting (as of now).
                 * Ignore errors due to this.
@@ -233,7 +243,7 @@ static int clk_set_default_parents(struct udevice *dev)
        return 0;
 }
 
-static int clk_set_default_rates(struct udevice *dev)
+static int clk_set_default_rates(struct udevice *dev, int stage)
 {
        struct clk clk;
        int index;
@@ -268,7 +278,19 @@ static int clk_set_default_rates(struct udevice *dev)
                        continue;
                }
 
+               /* This is clk provider device trying to program itself
+                * It cannot be done right now but need to wait after the
+                * device is probed
+                */
+               if (stage == 0 && clk.dev == dev)
+                       continue;
+
+               if (stage > 0 && clk.dev != dev)
+                       /* do not setup twice the parent clocks */
+                       continue;
+
                ret = clk_set_rate(&clk, rates[index]);
+
                if (ret < 0) {
                        debug("%s: failed to set rate on clock index %d (%ld) for %s\n",
                              __func__, index, clk.id, dev_read_name(dev));
@@ -281,7 +303,7 @@ fail:
        return ret;
 }
 
-int clk_set_defaults(struct udevice *dev)
+int clk_set_defaults(struct udevice *dev, int stage)
 {
        int ret;
 
@@ -294,11 +316,11 @@ int clk_set_defaults(struct udevice *dev)
 
        debug("%s(%s)\n", __func__, dev_read_name(dev));
 
-       ret = clk_set_default_parents(dev);
+       ret = clk_set_default_parents(dev, stage);
        if (ret)
                return ret;
 
-       ret = clk_set_default_rates(dev);
+       ret = clk_set_default_rates(dev, stage);
        if (ret < 0)
                return ret;
 
@@ -673,7 +695,21 @@ void devm_clk_put(struct udevice *dev, struct clk *clk)
        WARN_ON(rc);
 }
 
+int clk_uclass_post_probe(struct udevice *dev)
+{
+       /*
+        * when a clock provider is probed. Call clk_set_defaults()
+        * also after the device is probed. This takes care of cases
+        * where the DT is used to setup default parents and rates
+        * using assigned-clocks
+        */
+       clk_set_defaults(dev, 1);
+
+       return 0;
+}
+
 UCLASS_DRIVER(clk) = {
        .id             = UCLASS_CLK,
        .name           = "clk",
+       .post_probe     = clk_uclass_post_probe,
 };
index 95f26efdd3bad7b54d3ab8fef2e554b9d05ded02..8eabaf8b553219bea677d9a9c1be134ba57c5e0a 100644 (file)
@@ -423,7 +423,7 @@ int device_probe(struct udevice *dev)
                 * Process 'assigned-{clocks/clock-parents/clock-rates}'
                 * properties
                 */
-               ret = clk_set_defaults(dev);
+               ret = clk_set_defaults(dev, 0);
                if (ret)
                        goto fail;
        }
index 9be3264113f417745374f645a8f9ba2b14a0da66..a5ee53d94aa4f60c62bccf442dbf319e81c5c75b 100644 (file)
@@ -244,10 +244,13 @@ static inline int clk_release_all(struct clk *clk, int count)
  *
  * @dev:        A device to process (the ofnode associated with this device
  *              will be processed).
+ * @stage:     A integer. 0 indicates that this is called before the device
+ *             is probed. 1 indicates that this is called just after the
+ *             device has been probed
  */
-int clk_set_defaults(struct udevice *dev);
+int clk_set_defaults(struct udevice *dev, int stage);
 #else
-static inline int clk_set_defaults(struct udevice *dev)
+static inline int clk_set_defaults(struct udevice *dev, int stage)
 {
        return 0;
 }