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