1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Hisilicon clock driver 4 * 5 * Copyright (c) 2012-2013 Hisilicon Limited. 6 * Copyright (c) 2012-2013 Linaro Limited. 7 * 8 * Author: Haojian Zhuang <haojian.zhuang@linaro.org> 9 * Xin Li <li.xin@linaro.org> 10 */ 11 12 #include <linux/kernel.h> 13 #include <linux/clkdev.h> 14 #include <linux/clk-provider.h> 15 #include <linux/delay.h> 16 #include <linux/io.h> 17 #include <linux/of.h> 18 #include <linux/of_address.h> 19 #include <linux/platform_device.h> 20 #include <linux/slab.h> 21 22 #include "clk.h" 23 24 static DEFINE_SPINLOCK(hisi_clk_lock); 25 26 struct hisi_clock_data *hisi_clk_alloc(struct platform_device *pdev, 27 int nr_clks) 28 { 29 struct hisi_clock_data *clk_data; 30 struct resource *res; 31 struct clk **clk_table; 32 33 clk_data = devm_kmalloc(&pdev->dev, sizeof(*clk_data), GFP_KERNEL); 34 if (!clk_data) 35 return NULL; 36 37 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 38 if (!res) 39 return NULL; 40 clk_data->base = devm_ioremap(&pdev->dev, 41 res->start, resource_size(res)); 42 if (!clk_data->base) 43 return NULL; 44 45 clk_table = devm_kmalloc_array(&pdev->dev, nr_clks, 46 sizeof(*clk_table), 47 GFP_KERNEL); 48 if (!clk_table) 49 return NULL; 50 51 clk_data->clk_data.clks = clk_table; 52 clk_data->clk_data.clk_num = nr_clks; 53 54 return clk_data; 55 } 56 EXPORT_SYMBOL_GPL(hisi_clk_alloc); 57 58 struct hisi_clock_data *hisi_clk_init(struct device_node *np, 59 int nr_clks) 60 { 61 struct hisi_clock_data *clk_data; 62 struct clk **clk_table; 63 void __iomem *base; 64 65 base = of_iomap(np, 0); 66 if (!base) { 67 pr_err("%s: failed to map clock registers\n", __func__); 68 goto err; 69 } 70 71 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 72 if (!clk_data) 73 goto err; 74 75 clk_data->base = base; 76 clk_table = kcalloc(nr_clks, sizeof(*clk_table), GFP_KERNEL); 77 if (!clk_table) 78 goto err_data; 79 80 clk_data->clk_data.clks = clk_table; 81 clk_data->clk_data.clk_num = nr_clks; 82 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); 83 return clk_data; 84 err_data: 85 kfree(clk_data); 86 err: 87 return NULL; 88 } 89 EXPORT_SYMBOL_GPL(hisi_clk_init); 90 91 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, 92 int nums, struct hisi_clock_data *data) 93 { 94 struct clk *clk; 95 int i; 96 97 for (i = 0; i < nums; i++) { 98 clk = clk_register_fixed_rate(NULL, clks[i].name, 99 clks[i].parent_name, 100 clks[i].flags, 101 clks[i].fixed_rate); 102 if (IS_ERR(clk)) { 103 pr_err("%s: failed to register clock %s\n", 104 __func__, clks[i].name); 105 goto err; 106 } 107 data->clk_data.clks[clks[i].id] = clk; 108 } 109 110 return 0; 111 112 err: 113 while (i--) 114 clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]); 115 116 return PTR_ERR(clk); 117 } 118 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); 119 120 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, 121 int nums, 122 struct hisi_clock_data *data) 123 { 124 struct clk *clk; 125 int i; 126 127 for (i = 0; i < nums; i++) { 128 clk = clk_register_fixed_factor(NULL, clks[i].name, 129 clks[i].parent_name, 130 clks[i].flags, clks[i].mult, 131 clks[i].div); 132 if (IS_ERR(clk)) { 133 pr_err("%s: failed to register clock %s\n", 134 __func__, clks[i].name); 135 goto err; 136 } 137 data->clk_data.clks[clks[i].id] = clk; 138 } 139 140 return 0; 141 142 err: 143 while (i--) 144 clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]); 145 146 return PTR_ERR(clk); 147 } 148 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); 149 150 int hisi_clk_register_mux(const struct hisi_mux_clock *clks, 151 int nums, struct hisi_clock_data *data) 152 { 153 struct clk *clk; 154 void __iomem *base = data->base; 155 int i; 156 157 for (i = 0; i < nums; i++) { 158 u32 mask = BIT(clks[i].width) - 1; 159 160 clk = clk_register_mux_table(NULL, clks[i].name, 161 clks[i].parent_names, 162 clks[i].num_parents, clks[i].flags, 163 base + clks[i].offset, clks[i].shift, 164 mask, clks[i].mux_flags, 165 clks[i].table, &hisi_clk_lock); 166 if (IS_ERR(clk)) { 167 pr_err("%s: failed to register clock %s\n", 168 __func__, clks[i].name); 169 goto err; 170 } 171 172 if (clks[i].alias) 173 clk_register_clkdev(clk, clks[i].alias, NULL); 174 175 data->clk_data.clks[clks[i].id] = clk; 176 } 177 178 return 0; 179 180 err: 181 while (i--) 182 clk_unregister_mux(data->clk_data.clks[clks[i].id]); 183 184 return PTR_ERR(clk); 185 } 186 EXPORT_SYMBOL_GPL(hisi_clk_register_mux); 187 188 int hisi_clk_register_phase(struct device *dev, 189 const struct hisi_phase_clock *clks, 190 int nums, struct hisi_clock_data *data) 191 { 192 void __iomem *base = data->base; 193 struct clk *clk; 194 int i; 195 196 for (i = 0; i < nums; i++) { 197 clk = clk_register_hisi_phase(dev, &clks[i], base, 198 &hisi_clk_lock); 199 if (IS_ERR(clk)) { 200 pr_err("%s: failed to register clock %s\n", __func__, 201 clks[i].name); 202 return PTR_ERR(clk); 203 } 204 205 data->clk_data.clks[clks[i].id] = clk; 206 } 207 208 return 0; 209 } 210 EXPORT_SYMBOL_GPL(hisi_clk_register_phase); 211 212 int hisi_clk_register_divider(const struct hisi_divider_clock *clks, 213 int nums, struct hisi_clock_data *data) 214 { 215 struct clk *clk; 216 void __iomem *base = data->base; 217 int i; 218 219 for (i = 0; i < nums; i++) { 220 clk = clk_register_divider_table(NULL, clks[i].name, 221 clks[i].parent_name, 222 clks[i].flags, 223 base + clks[i].offset, 224 clks[i].shift, clks[i].width, 225 clks[i].div_flags, 226 clks[i].table, 227 &hisi_clk_lock); 228 if (IS_ERR(clk)) { 229 pr_err("%s: failed to register clock %s\n", 230 __func__, clks[i].name); 231 goto err; 232 } 233 234 if (clks[i].alias) 235 clk_register_clkdev(clk, clks[i].alias, NULL); 236 237 data->clk_data.clks[clks[i].id] = clk; 238 } 239 240 return 0; 241 242 err: 243 while (i--) 244 clk_unregister_divider(data->clk_data.clks[clks[i].id]); 245 246 return PTR_ERR(clk); 247 } 248 EXPORT_SYMBOL_GPL(hisi_clk_register_divider); 249 250 int hisi_clk_register_gate(const struct hisi_gate_clock *clks, 251 int nums, struct hisi_clock_data *data) 252 { 253 struct clk *clk; 254 void __iomem *base = data->base; 255 int i; 256 257 for (i = 0; i < nums; i++) { 258 clk = clk_register_gate(NULL, clks[i].name, 259 clks[i].parent_name, 260 clks[i].flags, 261 base + clks[i].offset, 262 clks[i].bit_idx, 263 clks[i].gate_flags, 264 &hisi_clk_lock); 265 if (IS_ERR(clk)) { 266 pr_err("%s: failed to register clock %s\n", 267 __func__, clks[i].name); 268 goto err; 269 } 270 271 if (clks[i].alias) 272 clk_register_clkdev(clk, clks[i].alias, NULL); 273 274 data->clk_data.clks[clks[i].id] = clk; 275 } 276 277 return 0; 278 279 err: 280 while (i--) 281 clk_unregister_gate(data->clk_data.clks[clks[i].id]); 282 283 return PTR_ERR(clk); 284 } 285 EXPORT_SYMBOL_GPL(hisi_clk_register_gate); 286 287 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, 288 int nums, struct hisi_clock_data *data) 289 { 290 struct clk *clk; 291 void __iomem *base = data->base; 292 int i; 293 294 for (i = 0; i < nums; i++) { 295 clk = hisi_register_clkgate_sep(NULL, clks[i].name, 296 clks[i].parent_name, 297 clks[i].flags, 298 base + clks[i].offset, 299 clks[i].bit_idx, 300 clks[i].gate_flags, 301 &hisi_clk_lock); 302 if (IS_ERR(clk)) { 303 pr_err("%s: failed to register clock %s\n", 304 __func__, clks[i].name); 305 continue; 306 } 307 308 if (clks[i].alias) 309 clk_register_clkdev(clk, clks[i].alias, NULL); 310 311 data->clk_data.clks[clks[i].id] = clk; 312 } 313 } 314 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); 315 316 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, 317 int nums, struct hisi_clock_data *data) 318 { 319 struct clk *clk; 320 void __iomem *base = data->base; 321 int i; 322 323 for (i = 0; i < nums; i++) { 324 clk = hi6220_register_clkdiv(NULL, clks[i].name, 325 clks[i].parent_name, 326 clks[i].flags, 327 base + clks[i].offset, 328 clks[i].shift, 329 clks[i].width, 330 clks[i].mask_bit, 331 &hisi_clk_lock); 332 if (IS_ERR(clk)) { 333 pr_err("%s: failed to register clock %s\n", 334 __func__, clks[i].name); 335 continue; 336 } 337 338 if (clks[i].alias) 339 clk_register_clkdev(clk, clks[i].alias, NULL); 340 341 data->clk_data.clks[clks[i].id] = clk; 342 } 343 } 344