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/clk-provider.h> 28 #include <linux/clkdev.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 #include <linux/clk.h> 36 37 #include "clk.h" 38 39 static DEFINE_SPINLOCK(hisi_clk_lock); 40 41 struct hisi_clock_data __init *hisi_clk_init(struct device_node *np, 42 int nr_clks) 43 { 44 struct hisi_clock_data *clk_data; 45 struct clk **clk_table; 46 void __iomem *base; 47 48 if (np) { 49 base = of_iomap(np, 0); 50 if (!base) { 51 pr_err("failed to map Hisilicon clock registers\n"); 52 goto err; 53 } 54 } else { 55 pr_err("failed to find Hisilicon clock node in DTS\n"); 56 goto err; 57 } 58 59 clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 60 if (!clk_data) { 61 pr_err("%s: could not allocate clock data\n", __func__); 62 goto err; 63 } 64 clk_data->base = base; 65 66 clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); 67 if (!clk_table) { 68 pr_err("%s: could not allocate clock lookup table\n", __func__); 69 goto err_data; 70 } 71 clk_data->clk_data.clks = clk_table; 72 clk_data->clk_data.clk_num = nr_clks; 73 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data); 74 return clk_data; 75 err_data: 76 kfree(clk_data); 77 err: 78 return NULL; 79 } 80 81 void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *clks, 82 int nums, struct hisi_clock_data *data) 83 { 84 struct clk *clk; 85 int i; 86 87 for (i = 0; i < nums; i++) { 88 clk = clk_register_fixed_rate(NULL, clks[i].name, 89 clks[i].parent_name, 90 clks[i].flags, 91 clks[i].fixed_rate); 92 if (IS_ERR(clk)) { 93 pr_err("%s: failed to register clock %s\n", 94 __func__, clks[i].name); 95 continue; 96 } 97 data->clk_data.clks[clks[i].id] = clk; 98 } 99 } 100 101 void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *clks, 102 int nums, 103 struct hisi_clock_data *data) 104 { 105 struct clk *clk; 106 int i; 107 108 for (i = 0; i < nums; i++) { 109 clk = clk_register_fixed_factor(NULL, clks[i].name, 110 clks[i].parent_name, 111 clks[i].flags, clks[i].mult, 112 clks[i].div); 113 if (IS_ERR(clk)) { 114 pr_err("%s: failed to register clock %s\n", 115 __func__, clks[i].name); 116 continue; 117 } 118 data->clk_data.clks[clks[i].id] = clk; 119 } 120 } 121 122 void __init hisi_clk_register_mux(struct hisi_mux_clock *clks, 123 int nums, struct hisi_clock_data *data) 124 { 125 struct clk *clk; 126 void __iomem *base = data->base; 127 int i; 128 129 for (i = 0; i < nums; i++) { 130 u32 mask = BIT(clks[i].width) - 1; 131 132 clk = clk_register_mux_table(NULL, clks[i].name, 133 clks[i].parent_names, 134 clks[i].num_parents, clks[i].flags, 135 base + clks[i].offset, clks[i].shift, 136 mask, clks[i].mux_flags, 137 clks[i].table, &hisi_clk_lock); 138 if (IS_ERR(clk)) { 139 pr_err("%s: failed to register clock %s\n", 140 __func__, clks[i].name); 141 continue; 142 } 143 144 if (clks[i].alias) 145 clk_register_clkdev(clk, clks[i].alias, NULL); 146 147 data->clk_data.clks[clks[i].id] = clk; 148 } 149 } 150 151 void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, 152 int nums, struct hisi_clock_data *data) 153 { 154 struct clk *clk; 155 void __iomem *base = data->base; 156 int i; 157 158 for (i = 0; i < nums; i++) { 159 clk = clk_register_divider_table(NULL, clks[i].name, 160 clks[i].parent_name, 161 clks[i].flags, 162 base + clks[i].offset, 163 clks[i].shift, clks[i].width, 164 clks[i].div_flags, 165 clks[i].table, 166 &hisi_clk_lock); 167 if (IS_ERR(clk)) { 168 pr_err("%s: failed to register clock %s\n", 169 __func__, clks[i].name); 170 continue; 171 } 172 173 if (clks[i].alias) 174 clk_register_clkdev(clk, clks[i].alias, NULL); 175 176 data->clk_data.clks[clks[i].id] = clk; 177 } 178 } 179 180 void __init hisi_clk_register_gate(struct hisi_gate_clock *clks, 181 int nums, struct hisi_clock_data *data) 182 { 183 struct clk *clk; 184 void __iomem *base = data->base; 185 int i; 186 187 for (i = 0; i < nums; i++) { 188 clk = clk_register_gate(NULL, clks[i].name, 189 clks[i].parent_name, 190 clks[i].flags, 191 base + clks[i].offset, 192 clks[i].bit_idx, 193 clks[i].gate_flags, 194 &hisi_clk_lock); 195 if (IS_ERR(clk)) { 196 pr_err("%s: failed to register clock %s\n", 197 __func__, clks[i].name); 198 continue; 199 } 200 201 if (clks[i].alias) 202 clk_register_clkdev(clk, clks[i].alias, NULL); 203 204 data->clk_data.clks[clks[i].id] = clk; 205 } 206 } 207 208 void __init hisi_clk_register_gate_sep(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