Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2014 Samsung Electronics Co., Ltd.
0004  * Sylwester Nawrocki <s.nawrocki@samsung.com>
0005  */
0006 
0007 #include <linux/clk.h>
0008 #include <linux/clk-provider.h>
0009 #include <linux/clk/clk-conf.h>
0010 #include <linux/device.h>
0011 #include <linux/of.h>
0012 #include <linux/printk.h>
0013 
0014 static int __set_clk_parents(struct device_node *node, bool clk_supplier)
0015 {
0016     struct of_phandle_args clkspec;
0017     int index, rc, num_parents;
0018     struct clk *clk, *pclk;
0019 
0020     num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
0021                          "#clock-cells");
0022     if (num_parents == -EINVAL)
0023         pr_err("clk: invalid value of clock-parents property at %pOF\n",
0024                node);
0025 
0026     for (index = 0; index < num_parents; index++) {
0027         rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
0028                     "#clock-cells", index, &clkspec);
0029         if (rc < 0) {
0030             /* skip empty (null) phandles */
0031             if (rc == -ENOENT)
0032                 continue;
0033             else
0034                 return rc;
0035         }
0036         if (clkspec.np == node && !clk_supplier)
0037             return 0;
0038         pclk = of_clk_get_from_provider(&clkspec);
0039         if (IS_ERR(pclk)) {
0040             if (PTR_ERR(pclk) != -EPROBE_DEFER)
0041                 pr_warn("clk: couldn't get parent clock %d for %pOF\n",
0042                     index, node);
0043             return PTR_ERR(pclk);
0044         }
0045 
0046         rc = of_parse_phandle_with_args(node, "assigned-clocks",
0047                     "#clock-cells", index, &clkspec);
0048         if (rc < 0)
0049             goto err;
0050         if (clkspec.np == node && !clk_supplier) {
0051             rc = 0;
0052             goto err;
0053         }
0054         clk = of_clk_get_from_provider(&clkspec);
0055         if (IS_ERR(clk)) {
0056             if (PTR_ERR(clk) != -EPROBE_DEFER)
0057                 pr_warn("clk: couldn't get assigned clock %d for %pOF\n",
0058                     index, node);
0059             rc = PTR_ERR(clk);
0060             goto err;
0061         }
0062 
0063         rc = clk_set_parent(clk, pclk);
0064         if (rc < 0)
0065             pr_err("clk: failed to reparent %s to %s: %d\n",
0066                    __clk_get_name(clk), __clk_get_name(pclk), rc);
0067         clk_put(clk);
0068         clk_put(pclk);
0069     }
0070     return 0;
0071 err:
0072     clk_put(pclk);
0073     return rc;
0074 }
0075 
0076 static int __set_clk_rates(struct device_node *node, bool clk_supplier)
0077 {
0078     struct of_phandle_args clkspec;
0079     struct property *prop;
0080     const __be32 *cur;
0081     int rc, index = 0;
0082     struct clk *clk;
0083     u32 rate;
0084 
0085     of_property_for_each_u32(node, "assigned-clock-rates", prop, cur, rate) {
0086         if (rate) {
0087             rc = of_parse_phandle_with_args(node, "assigned-clocks",
0088                     "#clock-cells", index, &clkspec);
0089             if (rc < 0) {
0090                 /* skip empty (null) phandles */
0091                 if (rc == -ENOENT)
0092                     continue;
0093                 else
0094                     return rc;
0095             }
0096             if (clkspec.np == node && !clk_supplier)
0097                 return 0;
0098 
0099             clk = of_clk_get_from_provider(&clkspec);
0100             if (IS_ERR(clk)) {
0101                 if (PTR_ERR(clk) != -EPROBE_DEFER)
0102                     pr_warn("clk: couldn't get clock %d for %pOF\n",
0103                         index, node);
0104                 return PTR_ERR(clk);
0105             }
0106 
0107             rc = clk_set_rate(clk, rate);
0108             if (rc < 0)
0109                 pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",
0110                        __clk_get_name(clk), rate, rc,
0111                        clk_get_rate(clk));
0112             clk_put(clk);
0113         }
0114         index++;
0115     }
0116     return 0;
0117 }
0118 
0119 /**
0120  * of_clk_set_defaults() - parse and set assigned clocks configuration
0121  * @node: device node to apply clock settings for
0122  * @clk_supplier: true if clocks supplied by @node should also be considered
0123  *
0124  * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties
0125  * and sets any specified clock parents and rates. The @clk_supplier argument
0126  * should be set to true if @node may be also a clock supplier of any clock
0127  * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
0128  * If @clk_supplier is false the function exits returning 0 as soon as it
0129  * determines the @node is also a supplier of any of the clocks.
0130  */
0131 int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
0132 {
0133     int rc;
0134 
0135     if (!node)
0136         return 0;
0137 
0138     rc = __set_clk_parents(node, clk_supplier);
0139     if (rc < 0)
0140         return rc;
0141 
0142     return __set_clk_rates(node, clk_supplier);
0143 }
0144 EXPORT_SYMBOL_GPL(of_clk_set_defaults);