1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2014 Samsung Electronics Co., Ltd. 4 * Sylwester Nawrocki <s.nawrocki@samsung.com> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/clk-provider.h> 9 #include <linux/clk/clk-conf.h> 10 #include <linux/device.h> 11 #include <linux/of.h> 12 #include <linux/printk.h> 13 #include <linux/slab.h> 14 15 static int __set_clk_parents(struct device_node *node, bool clk_supplier) 16 { 17 struct of_phandle_args clkspec; 18 int index, rc, num_parents; 19 struct clk *clk, *pclk; 20 21 num_parents = of_count_phandle_with_args(node, "assigned-clock-parents", 22 "#clock-cells"); 23 if (num_parents == -EINVAL) 24 pr_err("clk: invalid value of clock-parents property at %pOF\n", 25 node); 26 27 for (index = 0; index < num_parents; index++) { 28 rc = of_parse_phandle_with_args(node, "assigned-clock-parents", 29 "#clock-cells", index, &clkspec); 30 if (rc < 0) { 31 /* skip empty (null) phandles */ 32 if (rc == -ENOENT) 33 continue; 34 else 35 return rc; 36 } 37 if (clkspec.np == node && !clk_supplier) { 38 of_node_put(clkspec.np); 39 return 0; 40 } 41 pclk = of_clk_get_from_provider(&clkspec); 42 of_node_put(clkspec.np); 43 if (IS_ERR(pclk)) { 44 if (PTR_ERR(pclk) != -EPROBE_DEFER) 45 pr_warn("clk: couldn't get parent clock %d for %pOF\n", 46 index, node); 47 return PTR_ERR(pclk); 48 } 49 50 rc = of_parse_phandle_with_args(node, "assigned-clocks", 51 "#clock-cells", index, &clkspec); 52 if (rc < 0) 53 goto err; 54 if (clkspec.np == node && !clk_supplier) { 55 of_node_put(clkspec.np); 56 rc = 0; 57 goto err; 58 } 59 clk = of_clk_get_from_provider(&clkspec); 60 of_node_put(clkspec.np); 61 if (IS_ERR(clk)) { 62 if (PTR_ERR(clk) != -EPROBE_DEFER) 63 pr_warn("clk: couldn't get assigned clock %d for %pOF\n", 64 index, node); 65 rc = PTR_ERR(clk); 66 goto err; 67 } 68 69 rc = clk_set_parent(clk, pclk); 70 if (rc < 0) 71 pr_err("clk: failed to reparent %s to %s: %d\n", 72 __clk_get_name(clk), __clk_get_name(pclk), rc); 73 clk_put(clk); 74 clk_put(pclk); 75 } 76 return 0; 77 err: 78 clk_put(pclk); 79 return rc; 80 } 81 82 static int __set_clk_rates(struct device_node *node, bool clk_supplier) 83 { 84 struct of_phandle_args clkspec; 85 int rc, count, count_64, index; 86 struct clk *clk; 87 u64 *rates_64 __free(kfree) = NULL; 88 u32 *rates __free(kfree) = NULL; 89 90 count = of_property_count_u32_elems(node, "assigned-clock-rates"); 91 count_64 = of_property_count_u64_elems(node, "assigned-clock-rates-u64"); 92 if (count_64 > 0) { 93 count = count_64; 94 rates_64 = kcalloc(count, sizeof(*rates_64), GFP_KERNEL); 95 if (!rates_64) 96 return -ENOMEM; 97 98 rc = of_property_read_u64_array(node, 99 "assigned-clock-rates-u64", 100 rates_64, count); 101 } else if (count > 0) { 102 rates = kcalloc(count, sizeof(*rates), GFP_KERNEL); 103 if (!rates) 104 return -ENOMEM; 105 106 rc = of_property_read_u32_array(node, "assigned-clock-rates", 107 rates, count); 108 } else { 109 return 0; 110 } 111 112 if (rc) 113 return rc; 114 115 for (index = 0; index < count; index++) { 116 unsigned long rate; 117 118 if (rates_64) 119 rate = rates_64[index]; 120 else 121 rate = rates[index]; 122 123 if (rate) { 124 rc = of_parse_phandle_with_args(node, "assigned-clocks", 125 "#clock-cells", index, &clkspec); 126 if (rc < 0) { 127 /* skip empty (null) phandles */ 128 if (rc == -ENOENT) 129 continue; 130 else 131 return rc; 132 } 133 if (clkspec.np == node && !clk_supplier) { 134 of_node_put(clkspec.np); 135 return 0; 136 } 137 138 clk = of_clk_get_from_provider(&clkspec); 139 of_node_put(clkspec.np); 140 if (IS_ERR(clk)) { 141 if (PTR_ERR(clk) != -EPROBE_DEFER) 142 pr_warn("clk: couldn't get clock %d for %pOF\n", 143 index, node); 144 return PTR_ERR(clk); 145 } 146 147 rc = clk_set_rate(clk, rate); 148 if (rc < 0) 149 pr_err("clk: couldn't set %s clk rate to %lu (%d), current rate: %lu\n", 150 __clk_get_name(clk), rate, rc, 151 clk_get_rate(clk)); 152 clk_put(clk); 153 } 154 } 155 return 0; 156 } 157 158 /** 159 * of_clk_set_defaults() - parse and set assigned clocks configuration 160 * @node: device node to apply clock settings for 161 * @clk_supplier: true if clocks supplied by @node should also be considered 162 * 163 * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties 164 * and sets any specified clock parents and rates. The @clk_supplier argument 165 * should be set to true if @node may be also a clock supplier of any clock 166 * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. 167 * If @clk_supplier is false the function exits returning 0 as soon as it 168 * determines the @node is also a supplier of any of the clocks. 169 */ 170 int of_clk_set_defaults(struct device_node *node, bool clk_supplier) 171 { 172 int rc; 173 174 if (!node) 175 return 0; 176 177 rc = __set_clk_parents(node, clk_supplier); 178 if (rc < 0) 179 return rc; 180 181 return __set_clk_rates(node, clk_supplier); 182 } 183 EXPORT_SYMBOL_GPL(of_clk_set_defaults); 184