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 static int __set_clk_spread_spectrum(struct device_node *node, bool clk_supplier) 159 { 160 u32 elem_size = sizeof(struct clk_spread_spectrum); 161 struct clk_spread_spectrum *sscs; 162 struct of_phandle_args clkspec; 163 int rc, count, index; 164 struct clk *clk; 165 166 /* modfreq, spreadPercent, modmethod */ 167 count = of_property_count_elems_of_size(node, "assigned-clock-sscs", elem_size); 168 if (count <= 0) 169 return 0; 170 171 sscs = kcalloc(count, elem_size, GFP_KERNEL); 172 if (!sscs) 173 return -ENOMEM; 174 175 rc = of_property_read_u32_array(node, "assigned-clock-sscs", (u32 *)sscs, 176 count * 3); 177 if (rc) 178 goto free_sscs; 179 180 for (index = 0; index < count; index++) { 181 struct clk_spread_spectrum *conf = &sscs[index]; 182 struct clk_hw *hw; 183 184 if (!conf->modfreq_hz && !conf->spread_bp && !conf->method) 185 continue; 186 187 rc = of_parse_phandle_with_args(node, "assigned-clocks", "#clock-cells", 188 index, &clkspec); 189 if (rc < 0) { 190 /* skip empty (null) phandles */ 191 if (rc == -ENOENT) { 192 rc = 0; 193 continue; 194 } else 195 goto free_sscs; 196 } 197 198 if (clkspec.np == node && !clk_supplier) { 199 of_node_put(clkspec.np); 200 goto free_sscs; 201 } 202 203 clk = of_clk_get_from_provider(&clkspec); 204 of_node_put(clkspec.np); 205 if (IS_ERR(clk)) { 206 if (PTR_ERR(clk) != -EPROBE_DEFER) 207 pr_warn("clk: couldn't get clock %d for %pOF\n", 208 index, node); 209 rc = PTR_ERR(clk); 210 goto free_sscs; 211 } 212 213 hw = __clk_get_hw(clk); 214 rc = clk_hw_set_spread_spectrum(hw, conf); 215 if (rc < 0) { 216 pr_err("clk: couldn't set %s clk spread spectrum %u %u %u: %d\n", 217 __clk_get_name(clk), conf->modfreq_hz, conf->spread_bp, 218 conf->method, rc); 219 /* Do not fail */ 220 rc = 0; 221 } 222 clk_put(clk); 223 } 224 225 free_sscs: 226 kfree(sscs); 227 return rc; 228 } 229 230 /** 231 * of_clk_set_defaults() - parse and set assigned clocks configuration 232 * @node: device node to apply clock settings for 233 * @clk_supplier: true if clocks supplied by @node should also be considered 234 * 235 * This function parses 'assigned-{clocks/clock-parents/clock-rates}' properties 236 * and sets any specified clock parents and rates. The @clk_supplier argument 237 * should be set to true if @node may be also a clock supplier of any clock 238 * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. 239 * If @clk_supplier is false the function exits returning 0 as soon as it 240 * determines the @node is also a supplier of any of the clocks. 241 */ 242 int of_clk_set_defaults(struct device_node *node, bool clk_supplier) 243 { 244 int rc; 245 246 if (!node) 247 return 0; 248 249 rc = __set_clk_spread_spectrum(node, clk_supplier); 250 if (rc < 0) 251 return rc; 252 253 rc = __set_clk_parents(node, clk_supplier); 254 if (rc < 0) 255 return rc; 256 257 return __set_clk_rates(node, clk_supplier); 258 } 259 EXPORT_SYMBOL_GPL(of_clk_set_defaults); 260