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_init(struct device_node *np, 41 int nr_clks) 42 { 43 struct hisi_clock_data *clk_data; 44 struct clk **clk_table; 45 void __iomem *base; 46 47 base = of_iomap(np, 0); 48 if (!base) { 49 pr_err("%s: failed to map clock registers\n", __func__); 50 goto err; 51 } 52 53 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 54 if (!clk_data) { 55 pr_err("%s: could not allocate clock data\n", __func__); 56 goto err; 57 } 58 clk_data->base = base; 59 60 clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); 61 if (!clk_table) { 62 pr_err("%s: could not allocate clock lookup table\n", __func__); 63 goto err_data; 64 } 65 clk_data->clk_data.clks = clk_table; 66 clk_data->clk_data.clk_num = nr_clks; 67 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); 68 return clk_data; 69 err_data: 70 kfree(clk_data); 71 err: 72 return NULL; 73 } 74 EXPORT_SYMBOL_GPL(hisi_clk_init); 75 76 void hisi_clk_register_fixed_rate(const struct hisi_fixed_rate_clock *clks, 77 int nums, struct hisi_clock_data *data) 78 { 79 struct clk *clk; 80 int i; 81 82 for (i = 0; i < nums; i++) { 83 clk = clk_register_fixed_rate(NULL, clks[i].name, 84 clks[i].parent_name, 85 clks[i].flags, 86 clks[i].fixed_rate); 87 if (IS_ERR(clk)) { 88 pr_err("%s: failed to register clock %s\n", 89 __func__, clks[i].name); 90 continue; 91 } 92 data->clk_data.clks[clks[i].id] = clk; 93 } 94 } 95 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_rate); 96 97 void hisi_clk_register_fixed_factor(const struct hisi_fixed_factor_clock *clks, 98 int nums, 99 struct hisi_clock_data *data) 100 { 101 struct clk *clk; 102 int i; 103 104 for (i = 0; i < nums; i++) { 105 clk = clk_register_fixed_factor(NULL, clks[i].name, 106 clks[i].parent_name, 107 clks[i].flags, clks[i].mult, 108 clks[i].div); 109 if (IS_ERR(clk)) { 110 pr_err("%s: failed to register clock %s\n", 111 __func__, clks[i].name); 112 continue; 113 } 114 data->clk_data.clks[clks[i].id] = clk; 115 } 116 } 117 EXPORT_SYMBOL_GPL(hisi_clk_register_fixed_factor); 118 119 void hisi_clk_register_mux(const struct hisi_mux_clock *clks, 120 int nums, struct hisi_clock_data *data) 121 { 122 struct clk *clk; 123 void __iomem *base = data->base; 124 int i; 125 126 for (i = 0; i < nums; i++) { 127 u32 mask = BIT(clks[i].width) - 1; 128 129 clk = clk_register_mux_table(NULL, clks[i].name, 130 clks[i].parent_names, 131 clks[i].num_parents, clks[i].flags, 132 base + clks[i].offset, clks[i].shift, 133 mask, clks[i].mux_flags, 134 clks[i].table, &hisi_clk_lock); 135 if (IS_ERR(clk)) { 136 pr_err("%s: failed to register clock %s\n", 137 __func__, clks[i].name); 138 continue; 139 } 140 141 if (clks[i].alias) 142 clk_register_clkdev(clk, clks[i].alias, NULL); 143 144 data->clk_data.clks[clks[i].id] = clk; 145 } 146 } 147 EXPORT_SYMBOL_GPL(hisi_clk_register_mux); 148 149 void hisi_clk_register_divider(const struct hisi_divider_clock *clks, 150 int nums, struct hisi_clock_data *data) 151 { 152 struct clk *clk; 153 void __iomem *base = data->base; 154 int i; 155 156 for (i = 0; i < nums; i++) { 157 clk = clk_register_divider_table(NULL, clks[i].name, 158 clks[i].parent_name, 159 clks[i].flags, 160 base + clks[i].offset, 161 clks[i].shift, clks[i].width, 162 clks[i].div_flags, 163 clks[i].table, 164 &hisi_clk_lock); 165 if (IS_ERR(clk)) { 166 pr_err("%s: failed to register clock %s\n", 167 __func__, clks[i].name); 168 continue; 169 } 170 171 if (clks[i].alias) 172 clk_register_clkdev(clk, clks[i].alias, NULL); 173 174 data->clk_data.clks[clks[i].id] = clk; 175 } 176 } 177 EXPORT_SYMBOL_GPL(hisi_clk_register_divider); 178 179 void hisi_clk_register_gate(const struct hisi_gate_clock *clks, 180 int nums, struct hisi_clock_data *data) 181 { 182 struct clk *clk; 183 void __iomem *base = data->base; 184 int i; 185 186 for (i = 0; i < nums; i++) { 187 clk = clk_register_gate(NULL, clks[i].name, 188 clks[i].parent_name, 189 clks[i].flags, 190 base + clks[i].offset, 191 clks[i].bit_idx, 192 clks[i].gate_flags, 193 &hisi_clk_lock); 194 if (IS_ERR(clk)) { 195 pr_err("%s: failed to register clock %s\n", 196 __func__, clks[i].name); 197 continue; 198 } 199 200 if (clks[i].alias) 201 clk_register_clkdev(clk, clks[i].alias, NULL); 202 203 data->clk_data.clks[clks[i].id] = clk; 204 } 205 } 206 EXPORT_SYMBOL_GPL(hisi_clk_register_gate); 207 208 void hisi_clk_register_gate_sep(const struct hisi_gate_clock *clks, 209 int nums, struct hisi_clock_data *data) 210 { 211 struct clk *clk; 212 void __iomem *base = data->base; 213 int i; 214 215 for (i = 0; i < nums; i++) { 216 clk = hisi_register_clkgate_sep(NULL, clks[i].name, 217 clks[i].parent_name, 218 clks[i].flags, 219 base + clks[i].offset, 220 clks[i].bit_idx, 221 clks[i].gate_flags, 222 &hisi_clk_lock); 223 if (IS_ERR(clk)) { 224 pr_err("%s: failed to register clock %s\n", 225 __func__, clks[i].name); 226 continue; 227 } 228 229 if (clks[i].alias) 230 clk_register_clkdev(clk, clks[i].alias, NULL); 231 232 data->clk_data.clks[clks[i].id] = clk; 233 } 234 } 235 EXPORT_SYMBOL_GPL(hisi_clk_register_gate_sep); 236 237 void __init hi6220_clk_register_divider(const struct hi6220_divider_clock *clks, 238 int nums, struct hisi_clock_data *data) 239 { 240 struct clk *clk; 241 void __iomem *base = data->base; 242 int i; 243 244 for (i = 0; i < nums; i++) { 245 clk = hi6220_register_clkdiv(NULL, clks[i].name, 246 clks[i].parent_name, 247 clks[i].flags, 248 base + clks[i].offset, 249 clks[i].shift, 250 clks[i].width, 251 clks[i].mask_bit, 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 continue; 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