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 __init *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 75 void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, 76 int nums, struct hisi_clock_data *data) 77 { 78 struct clk *clk; 79 int i; 80 81 for (i = 0; i < nums; i++) { 82 clk = clk_register_fixed_rate(NULL, clks[i].name, 83 clks[i].parent_name, 84 clks[i].flags, 85 clks[i].fixed_rate); 86 if (IS_ERR(clk)) { 87 pr_err("%s: failed to register clock %s\n", 88 __func__, clks[i].name); 89 continue; 90 } 91 data->clk_data.clks[clks[i].id] = clk; 92 } 93 } 94 95 void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, 96 int nums, 97 struct hisi_clock_data *data) 98 { 99 struct clk *clk; 100 int i; 101 102 for (i = 0; i < nums; i++) { 103 clk = clk_register_fixed_factor(NULL, clks[i].name, 104 clks[i].parent_name, 105 clks[i].flags, clks[i].mult, 106 clks[i].div); 107 if (IS_ERR(clk)) { 108 pr_err("%s: failed to register clock %s\n", 109 __func__, clks[i].name); 110 continue; 111 } 112 data->clk_data.clks[clks[i].id] = clk; 113 } 114 } 115 116 void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, 117 int nums, struct hisi_clock_data *data) 118 { 119 struct clk *clk; 120 void __iomem *base = data->base; 121 int i; 122 123 for (i = 0; i < nums; i++) { 124 u32 mask = BIT(clks[i].width) - 1; 125 126 clk = clk_register_mux_table(NULL, clks[i].name, 127 clks[i].parent_names, 128 clks[i].num_parents, clks[i].flags, 129 base + clks[i].offset, clks[i].shift, 130 mask, clks[i].mux_flags, 131 clks[i].table, &hisi_clk_lock); 132 if (IS_ERR(clk)) { 133 pr_err("%s: failed to register clock %s\n", 134 __func__, clks[i].name); 135 continue; 136 } 137 138 if (clks[i].alias) 139 clk_register_clkdev(clk, clks[i].alias, NULL); 140 141 data->clk_data.clks[clks[i].id] = clk; 142 } 143 } 144 145 void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, 146 int nums, struct hisi_clock_data *data) 147 { 148 struct clk *clk; 149 void __iomem *base = data->base; 150 int i; 151 152 for (i = 0; i < nums; i++) { 153 clk = clk_register_divider_table(NULL, clks[i].name, 154 clks[i].parent_name, 155 clks[i].flags, 156 base + clks[i].offset, 157 clks[i].shift, clks[i].width, 158 clks[i].div_flags, 159 clks[i].table, 160 &hisi_clk_lock); 161 if (IS_ERR(clk)) { 162 pr_err("%s: failed to register clock %s\n", 163 __func__, clks[i].name); 164 continue; 165 } 166 167 if (clks[i].alias) 168 clk_register_clkdev(clk, clks[i].alias, NULL); 169 170 data->clk_data.clks[clks[i].id] = clk; 171 } 172 } 173 174 void __init hisi_clk_register_gate(struct hisi_gate_clock *clks, 175 int nums, struct hisi_clock_data *data) 176 { 177 struct clk *clk; 178 void __iomem *base = data->base; 179 int i; 180 181 for (i = 0; i < nums; i++) { 182 clk = clk_register_gate(NULL, clks[i].name, 183 clks[i].parent_name, 184 clks[i].flags, 185 base + clks[i].offset, 186 clks[i].bit_idx, 187 clks[i].gate_flags, 188 &hisi_clk_lock); 189 if (IS_ERR(clk)) { 190 pr_err("%s: failed to register clock %s\n", 191 __func__, clks[i].name); 192 continue; 193 } 194 195 if (clks[i].alias) 196 clk_register_clkdev(clk, clks[i].alias, NULL); 197 198 data->clk_data.clks[clks[i].id] = clk; 199 } 200 } 201 202 void __init hisi_clk_register_gate_sep(struct hisi_gate_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 = hisi_register_clkgate_sep(NULL, clks[i].name, 211 clks[i].parent_name, 212 clks[i].flags, 213 base + clks[i].offset, 214 clks[i].bit_idx, 215 clks[i].gate_flags, 216 &hisi_clk_lock); 217 if (IS_ERR(clk)) { 218 pr_err("%s: failed to register clock %s\n", 219 __func__, clks[i].name); 220 continue; 221 } 222 223 if (clks[i].alias) 224 clk_register_clkdev(clk, clks[i].alias, NULL); 225 226 data->clk_data.clks[clks[i].id] = clk; 227 } 228 } 229 230 void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks, 231 int nums, struct hisi_clock_data *data) 232 { 233 struct clk *clk; 234 void __iomem *base = data->base; 235 int i; 236 237 for (i = 0; i < nums; i++) { 238 clk = hi6220_register_clkdiv(NULL, clks[i].name, 239 clks[i].parent_name, 240 clks[i].flags, 241 base + clks[i].offset, 242 clks[i].shift, 243 clks[i].width, 244 clks[i].mask_bit, 245 &hisi_clk_lock); 246 if (IS_ERR(clk)) { 247 pr_err("%s: failed to register clock %s\n", 248 __func__, clks[i].name); 249 continue; 250 } 251 252 if (clks[i].alias) 253 clk_register_clkdev(clk, clks[i].alias, NULL); 254 255 data->clk_data.clks[clks[i].id] = clk; 256 } 257 } 258