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