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_obj(*clk_data); 72 if (!clk_data) 73 goto err_base; 74 75 clk_data->base = base; 76 clk_table = kzalloc_objs(*clk_table, nr_clks); 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_base: 87 iounmap(base); 88 err: 89 return NULL; 90 } 91 EXPORT_SYMBOL_GPL(hisi_clk_init); 92 93 int hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, 94 int nums, struct hisi_clock_data *data) 95 { 96 struct clk *clk; 97 int i; 98 99 for (i = 0; i < nums; i++) { 100 clk = clk_register_fixed_rate(NULL, clks[i].name, 101 clks[i].parent_name, 102 clks[i].flags, 103 clks[i].fixed_rate); 104 if (IS_ERR(clk)) { 105 pr_err("%s: failed to register clock %s\n", 106 __func__, clks[i].name); 107 goto err; 108 } 109 data->clk_data.clks[clks[i].id] = clk; 110 } 111 112 return 0; 113 114 err: 115 while (i--) 116 clk_unregister_fixed_rate(data->clk_data.clks[clks[i].id]); 117 118 return PTR_ERR(clk); 119 } 120 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); 121 122 int hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, 123 int nums, 124 struct hisi_clock_data *data) 125 { 126 struct clk *clk; 127 int i; 128 129 for (i = 0; i < nums; i++) { 130 clk = clk_register_fixed_factor(NULL, clks[i].name, 131 clks[i].parent_name, 132 clks[i].flags, clks[i].mult, 133 clks[i].div); 134 if (IS_ERR(clk)) { 135 pr_err("%s: failed to register clock %s\n", 136 __func__, clks[i].name); 137 goto err; 138 } 139 data->clk_data.clks[clks[i].id] = clk; 140 } 141 142 return 0; 143 144 err: 145 while (i--) 146 clk_unregister_fixed_factor(data->clk_data.clks[clks[i].id]); 147 148 return PTR_ERR(clk); 149 } 150 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); 151 152 int hisi_clk_register_mux(const struct hisi_mux_clock *clks, 153 int nums, struct hisi_clock_data *data) 154 { 155 struct clk *clk; 156 void __iomem *base = data->base; 157 int i; 158 159 for (i = 0; i < nums; i++) { 160 u32 mask = BIT(clks[i].width) - 1; 161 162 clk = clk_register_mux_table(NULL, clks[i].name, 163 clks[i].parent_names, 164 clks[i].num_parents, clks[i].flags, 165 base + clks[i].offset, clks[i].shift, 166 mask, clks[i].mux_flags, 167 clks[i].table, &hisi_clk_lock); 168 if (IS_ERR(clk)) { 169 pr_err("%s: failed to register clock %s\n", 170 __func__, clks[i].name); 171 goto err; 172 } 173 174 if (clks[i].alias) 175 clk_register_clkdev(clk, clks[i].alias, NULL); 176 177 data->clk_data.clks[clks[i].id] = clk; 178 } 179 180 return 0; 181 182 err: 183 while (i--) 184 clk_unregister_mux(data->clk_data.clks[clks[i].id]); 185 186 return PTR_ERR(clk); 187 } 188 EXPORT_SYMBOL_GPL(hisi_clk_register_mux); 189 190 int hisi_clk_register_phase(struct device *dev, 191 const struct hisi_phase_clock *clks, 192 int nums, struct hisi_clock_data *data) 193 { 194 void __iomem *base = data->base; 195 struct clk *clk; 196 int i; 197 198 for (i = 0; i < nums; i++) { 199 clk = clk_register_hisi_phase(dev, &clks[i], base, 200 &hisi_clk_lock); 201 if (IS_ERR(clk)) { 202 pr_err("%s: failed to register clock %s\n", __func__, 203 clks[i].name); 204 return PTR_ERR(clk); 205 } 206 207 data->clk_data.clks[clks[i].id] = clk; 208 } 209 210 return 0; 211 } 212 EXPORT_SYMBOL_GPL(hisi_clk_register_phase); 213 214 int hisi_clk_register_divider(const struct hisi_divider_clock *clks, 215 int nums, struct hisi_clock_data *data) 216 { 217 struct clk *clk; 218 void __iomem *base = data->base; 219 int i; 220 221 for (i = 0; i < nums; i++) { 222 clk = clk_register_divider_table(NULL, clks[i].name, 223 clks[i].parent_name, 224 clks[i].flags, 225 base + clks[i].offset, 226 clks[i].shift, clks[i].width, 227 clks[i].div_flags, 228 clks[i].table, 229 &hisi_clk_lock); 230 if (IS_ERR(clk)) { 231 pr_err("%s: failed to register clock %s\n", 232 __func__, clks[i].name); 233 goto err; 234 } 235 236 if (clks[i].alias) 237 clk_register_clkdev(clk, clks[i].alias, NULL); 238 239 data->clk_data.clks[clks[i].id] = clk; 240 } 241 242 return 0; 243 244 err: 245 while (i--) 246 clk_unregister_divider(data->clk_data.clks[clks[i].id]); 247 248 return PTR_ERR(clk); 249 } 250 EXPORT_SYMBOL_GPL(hisi_clk_register_divider); 251 252 int hisi_clk_register_gate(const struct hisi_gate_clock *clks, 253 int nums, struct hisi_clock_data *data) 254 { 255 struct clk *clk; 256 void __iomem *base = data->base; 257 int i; 258 259 for (i = 0; i < nums; i++) { 260 clk = clk_register_gate(NULL, clks[i].name, 261 clks[i].parent_name, 262 clks[i].flags, 263 base + clks[i].offset, 264 clks[i].bit_idx, 265 clks[i].gate_flags, 266 &hisi_clk_lock); 267 if (IS_ERR(clk)) { 268 pr_err("%s: failed to register clock %s\n", 269 __func__, clks[i].name); 270 goto err; 271 } 272 273 if (clks[i].alias) 274 clk_register_clkdev(clk, clks[i].alias, NULL); 275 276 data->clk_data.clks[clks[i].id] = clk; 277 } 278 279 return 0; 280 281 err: 282 while (i--) 283 clk_unregister_gate(data->clk_data.clks[clks[i].id]); 284 285 return PTR_ERR(clk); 286 } 287 EXPORT_SYMBOL_GPL(hisi_clk_register_gate); 288 289 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, 290 int nums, struct hisi_clock_data *data) 291 { 292 struct clk *clk; 293 void __iomem *base = data->base; 294 int i; 295 296 for (i = 0; i < nums; i++) { 297 clk = hisi_register_clkgate_sep(NULL, clks[i].name, 298 clks[i].parent_name, 299 clks[i].flags, 300 base + clks[i].offset, 301 clks[i].bit_idx, 302 clks[i].gate_flags, 303 &hisi_clk_lock); 304 if (IS_ERR(clk)) { 305 pr_err("%s: failed to register clock %s\n", 306 __func__, clks[i].name); 307 continue; 308 } 309 310 if (clks[i].alias) 311 clk_register_clkdev(clk, clks[i].alias, NULL); 312 313 data->clk_data.clks[clks[i].id] = clk; 314 } 315 } 316 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); 317 318 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, 319 int nums, struct hisi_clock_data *data) 320 { 321 struct clk *clk; 322 void __iomem *base = data->base; 323 int i; 324 325 for (i = 0; i < nums; i++) { 326 clk = hi6220_register_clkdiv(NULL, clks[i].name, 327 clks[i].parent_name, 328 clks[i].flags, 329 base + clks[i].offset, 330 clks[i].shift, 331 clks[i].width, 332 clks[i].mask_bit, 333 &hisi_clk_lock); 334 if (IS_ERR(clk)) { 335 pr_err("%s: failed to register clock %s\n", 336 __func__, clks[i].name); 337 continue; 338 } 339 340 if (clks[i].alias) 341 clk_register_clkdev(clk, clks[i].alias, NULL); 342 343 data->clk_data.clks[clks[i].id] = clk; 344 } 345 } 346