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 clk = clk_register_mux(NULL, clks[i].name, clks[i].parent_names, 131 clks[i].num_parents, clks[i].flags, 132 base + clks[i].offset, clks[i].shift, 133 clks[i].width, clks[i].mux_flags, 134 &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 148 void __init hisi_clk_register_divider(struct hisi_divider_clock *clks, 149 int nums, struct hisi_clock_data *data) 150 { 151 struct clk *clk; 152 void __iomem *base = data->base; 153 int i; 154 155 for (i = 0; i < nums; i++) { 156 clk = clk_register_divider_table(NULL, clks[i].name, 157 clks[i].parent_name, 158 clks[i].flags, 159 base + clks[i].offset, 160 clks[i].shift, clks[i].width, 161 clks[i].div_flags, 162 clks[i].table, 163 &hisi_clk_lock); 164 if (IS_ERR(clk)) { 165 pr_err("%s: failed to register clock %s\n", 166 __func__, clks[i].name); 167 continue; 168 } 169 170 if (clks[i].alias) 171 clk_register_clkdev(clk, clks[i].alias, NULL); 172 173 data->clk_data.clks[clks[i].id] = clk; 174 } 175 } 176 177 void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, 178 int nums, struct hisi_clock_data *data) 179 { 180 struct clk *clk; 181 void __iomem *base = data->base; 182 int i; 183 184 for (i = 0; i < nums; i++) { 185 clk = hisi_register_clkgate_sep(NULL, clks[i].name, 186 clks[i].parent_name, 187 clks[i].flags, 188 base + clks[i].offset, 189 clks[i].bit_idx, 190 clks[i].gate_flags, 191 &hisi_clk_lock); 192 if (IS_ERR(clk)) { 193 pr_err("%s: failed to register clock %s\n", 194 __func__, clks[i].name); 195 continue; 196 } 197 198 if (clks[i].alias) 199 clk_register_clkdev(clk, clks[i].alias, NULL); 200 201 data->clk_data.clks[clks[i].id] = clk; 202 } 203 } 204