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(&pdev->dev, sizeof(struct clk *) * nr_clks, 58 GFP_KERNEL); 59 if (!clk_table) 60 return NULL; 61 62 clk_data->clk_data.clks = clk_table; 63 clk_data->clk_data.clk_num = nr_clks; 64 65 return clk_data; 66 } 67 EXPORT_SYMBOL_GPL(hisi_clk_alloc); 68 69 struct hisi_clock_data *hisi_clk_init(struct device_node *np, 70 int nr_clks) 71 { 72 struct hisi_clock_data *clk_data; 73 struct clk **clk_table; 74 void __iomem *base; 75 76 base = of_iomap(np, 0); 77 if (!base) { 78 pr_err("%s: failed to map clock registers\n", __func__); 79 goto err; 80 } 81 82 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 83 if (!clk_data) { 84 pr_err("%s: could not allocate clock data\n", __func__); 85 goto err; 86 } 87 clk_data->base = base; 88 89 clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); 90 if (!clk_table) { 91 pr_err("%s: could not allocate clock lookup table\n", __func__); 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_divider(const struct hisi_divider_clock *clks, 203 int nums, struct hisi_clock_data *data) 204 { 205 struct clk *clk; 206 void __iomem *base = data->base; 207 int i; 208 209 for (i = 0; i < nums; i++) { 210 clk = clk_register_divider_table(NULL, clks[i].name, 211 clks[i].parent_name, 212 clks[i].flags, 213 base + clks[i].offset, 214 clks[i].shift, clks[i].width, 215 clks[i].div_flags, 216 clks[i].table, 217 &hisi_clk_lock); 218 if (IS_ERR(clk)) { 219 pr_err("%s: failed to register clock %s\n", 220 __func__, clks[i].name); 221 goto err; 222 } 223 224 if (clks[i].alias) 225 clk_register_clkdev(clk, clks[i].alias, NULL); 226 227 data->clk_data.clks[clks[i].id] = clk; 228 } 229 230 return 0; 231 232 err: 233 while (i--) 234 clk_unregister_divider(data->clk_data.clks[clks[i].id]); 235 236 return PTR_ERR(clk); 237 } 238 EXPORT_SYMBOL_GPL(hisi_clk_register_divider); 239 240 int hisi_clk_register_gate(const struct hisi_gate_clock *clks, 241 int nums, struct hisi_clock_data *data) 242 { 243 struct clk *clk; 244 void __iomem *base = data->base; 245 int i; 246 247 for (i = 0; i < nums; i++) { 248 clk = clk_register_gate(NULL, clks[i].name, 249 clks[i].parent_name, 250 clks[i].flags, 251 base + clks[i].offset, 252 clks[i].bit_idx, 253 clks[i].gate_flags, 254 &hisi_clk_lock); 255 if (IS_ERR(clk)) { 256 pr_err("%s: failed to register clock %s\n", 257 __func__, clks[i].name); 258 goto err; 259 } 260 261 if (clks[i].alias) 262 clk_register_clkdev(clk, clks[i].alias, NULL); 263 264 data->clk_data.clks[clks[i].id] = clk; 265 } 266 267 return 0; 268 269 err: 270 while (i--) 271 clk_unregister_gate(data->clk_data.clks[clks[i].id]); 272 273 return PTR_ERR(clk); 274 } 275 EXPORT_SYMBOL_GPL(hisi_clk_register_gate); 276 277 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, 278 int nums, struct hisi_clock_data *data) 279 { 280 struct clk *clk; 281 void __iomem *base = data->base; 282 int i; 283 284 for (i = 0; i < nums; i++) { 285 clk = hisi_register_clkgate_sep(NULL, clks[i].name, 286 clks[i].parent_name, 287 clks[i].flags, 288 base + clks[i].offset, 289 clks[i].bit_idx, 290 clks[i].gate_flags, 291 &hisi_clk_lock); 292 if (IS_ERR(clk)) { 293 pr_err("%s: failed to register clock %s\n", 294 __func__, clks[i].name); 295 continue; 296 } 297 298 if (clks[i].alias) 299 clk_register_clkdev(clk, clks[i].alias, NULL); 300 301 data->clk_data.clks[clks[i].id] = clk; 302 } 303 } 304 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); 305 306 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, 307 int nums, struct hisi_clock_data *data) 308 { 309 struct clk *clk; 310 void __iomem *base = data->base; 311 int i; 312 313 for (i = 0; i < nums; i++) { 314 clk = hi6220_register_clkdiv(NULL, clks[i].name, 315 clks[i].parent_name, 316 clks[i].flags, 317 base + clks[i].offset, 318 clks[i].shift, 319 clks[i].width, 320 clks[i].mask_bit, 321 &hisi_clk_lock); 322 if (IS_ERR(clk)) { 323 pr_err("%s: failed to register clock %s\n", 324 __func__, clks[i].name); 325 continue; 326 } 327 328 if (clks[i].alias) 329 clk_register_clkdev(clk, clks[i].alias, NULL); 330 331 data->clk_data.clks[clks[i].id] = clk; 332 } 333 } 334