1 /* 2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG). 3 * 4 * Copyright (C) 2010 Magnus Damm 5 * 6 * This file is subject to the terms and conditions of the GNU General Public 7 * License. See the file "COPYING" in the main directory of this archive 8 * for more details. 9 */ 10 #include <linux/clk.h> 11 #include <linux/compiler.h> 12 #include <linux/slab.h> 13 #include <linux/io.h> 14 #include <linux/sh_clk.h> 15 16 static int sh_clk_mstp32_enable(struct clk *clk) 17 { 18 __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit), 19 clk->enable_reg); 20 return 0; 21 } 22 23 static void sh_clk_mstp32_disable(struct clk *clk) 24 { 25 __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit), 26 clk->enable_reg); 27 } 28 29 static struct clk_ops sh_clk_mstp32_clk_ops = { 30 .enable = sh_clk_mstp32_enable, 31 .disable = sh_clk_mstp32_disable, 32 .recalc = followparent_recalc, 33 }; 34 35 int __init sh_clk_mstp32_register(struct clk *clks, int nr) 36 { 37 struct clk *clkp; 38 int ret = 0; 39 int k; 40 41 for (k = 0; !ret && (k < nr); k++) { 42 clkp = clks + k; 43 clkp->ops = &sh_clk_mstp32_clk_ops; 44 ret |= clk_register(clkp); 45 } 46 47 return ret; 48 } 49 50 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate) 51 { 52 return clk_rate_table_round(clk, clk->freq_table, rate); 53 } 54 55 static int sh_clk_div6_divisors[64] = { 56 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 57 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 58 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 59 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 60 }; 61 62 static struct clk_div_mult_table sh_clk_div6_table = { 63 .divisors = sh_clk_div6_divisors, 64 .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors), 65 }; 66 67 static unsigned long sh_clk_div6_recalc(struct clk *clk) 68 { 69 struct clk_div_mult_table *table = &sh_clk_div6_table; 70 unsigned int idx; 71 72 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 73 table, NULL); 74 75 idx = __raw_readl(clk->enable_reg) & 0x003f; 76 77 return clk->freq_table[idx].frequency; 78 } 79 80 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) 81 { 82 struct clk_div_mult_table *table = &sh_clk_div6_table; 83 u32 value; 84 int ret, i; 85 86 if (!clk->parent_table || !clk->parent_num) 87 return -EINVAL; 88 89 /* Search the parent */ 90 for (i = 0; i < clk->parent_num; i++) 91 if (clk->parent_table[i] == parent) 92 break; 93 94 if (i == clk->parent_num) 95 return -ENODEV; 96 97 ret = clk_reparent(clk, parent); 98 if (ret < 0) 99 return ret; 100 101 value = __raw_readl(clk->enable_reg) & 102 ~(((1 << clk->src_width) - 1) << clk->src_shift); 103 104 __raw_writel(value | (i << clk->src_shift), clk->enable_reg); 105 106 /* Rebuild the frequency table */ 107 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 108 table, &clk->arch_flags); 109 110 return 0; 111 } 112 113 static int sh_clk_div6_set_rate(struct clk *clk, 114 unsigned long rate, int algo_id) 115 { 116 unsigned long value; 117 int idx; 118 119 idx = clk_rate_table_find(clk, clk->freq_table, rate); 120 if (idx < 0) 121 return idx; 122 123 value = __raw_readl(clk->enable_reg); 124 value &= ~0x3f; 125 value |= idx; 126 __raw_writel(value, clk->enable_reg); 127 return 0; 128 } 129 130 static int sh_clk_div6_enable(struct clk *clk) 131 { 132 unsigned long value; 133 int ret; 134 135 ret = sh_clk_div6_set_rate(clk, clk->rate, 0); 136 if (ret == 0) { 137 value = __raw_readl(clk->enable_reg); 138 value &= ~0x100; /* clear stop bit to enable clock */ 139 __raw_writel(value, clk->enable_reg); 140 } 141 return ret; 142 } 143 144 static void sh_clk_div6_disable(struct clk *clk) 145 { 146 unsigned long value; 147 148 value = __raw_readl(clk->enable_reg); 149 value |= 0x100; /* stop clock */ 150 value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */ 151 __raw_writel(value, clk->enable_reg); 152 } 153 154 static struct clk_ops sh_clk_div6_clk_ops = { 155 .recalc = sh_clk_div6_recalc, 156 .round_rate = sh_clk_div_round_rate, 157 .set_rate = sh_clk_div6_set_rate, 158 .enable = sh_clk_div6_enable, 159 .disable = sh_clk_div6_disable, 160 }; 161 162 static struct clk_ops sh_clk_div6_reparent_clk_ops = { 163 .recalc = sh_clk_div6_recalc, 164 .round_rate = sh_clk_div_round_rate, 165 .set_rate = sh_clk_div6_set_rate, 166 .enable = sh_clk_div6_enable, 167 .disable = sh_clk_div6_disable, 168 .set_parent = sh_clk_div6_set_parent, 169 }; 170 171 static int __init sh_clk_div6_register_ops(struct clk *clks, int nr, 172 struct clk_ops *ops) 173 { 174 struct clk *clkp; 175 void *freq_table; 176 int nr_divs = sh_clk_div6_table.nr_divisors; 177 int freq_table_size = sizeof(struct cpufreq_frequency_table); 178 int ret = 0; 179 int k; 180 181 freq_table_size *= (nr_divs + 1); 182 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); 183 if (!freq_table) { 184 pr_err("sh_clk_div6_register: unable to alloc memory\n"); 185 return -ENOMEM; 186 } 187 188 for (k = 0; !ret && (k < nr); k++) { 189 clkp = clks + k; 190 191 clkp->ops = ops; 192 clkp->freq_table = freq_table + (k * freq_table_size); 193 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; 194 195 ret = clk_register(clkp); 196 } 197 198 return ret; 199 } 200 201 int __init sh_clk_div6_register(struct clk *clks, int nr) 202 { 203 return sh_clk_div6_register_ops(clks, nr, &sh_clk_div6_clk_ops); 204 } 205 206 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) 207 { 208 return sh_clk_div6_register_ops(clks, nr, 209 &sh_clk_div6_reparent_clk_ops); 210 } 211 212 static unsigned long sh_clk_div4_recalc(struct clk *clk) 213 { 214 struct clk_div4_table *d4t = clk->priv; 215 struct clk_div_mult_table *table = d4t->div_mult_table; 216 unsigned int idx; 217 218 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 219 table, &clk->arch_flags); 220 221 idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f; 222 223 return clk->freq_table[idx].frequency; 224 } 225 226 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) 227 { 228 struct clk_div4_table *d4t = clk->priv; 229 struct clk_div_mult_table *table = d4t->div_mult_table; 230 u32 value; 231 int ret; 232 233 /* we really need a better way to determine parent index, but for 234 * now assume internal parent comes with CLK_ENABLE_ON_INIT set, 235 * no CLK_ENABLE_ON_INIT means external clock... 236 */ 237 238 if (parent->flags & CLK_ENABLE_ON_INIT) 239 value = __raw_readl(clk->enable_reg) & ~(1 << 7); 240 else 241 value = __raw_readl(clk->enable_reg) | (1 << 7); 242 243 ret = clk_reparent(clk, parent); 244 if (ret < 0) 245 return ret; 246 247 __raw_writel(value, clk->enable_reg); 248 249 /* Rebiuld the frequency table */ 250 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 251 table, &clk->arch_flags); 252 253 return 0; 254 } 255 256 static int sh_clk_div4_set_rate(struct clk *clk, unsigned long rate, int algo_id) 257 { 258 struct clk_div4_table *d4t = clk->priv; 259 unsigned long value; 260 int idx = clk_rate_table_find(clk, clk->freq_table, rate); 261 if (idx < 0) 262 return idx; 263 264 value = __raw_readl(clk->enable_reg); 265 value &= ~(0xf << clk->enable_bit); 266 value |= (idx << clk->enable_bit); 267 __raw_writel(value, clk->enable_reg); 268 269 if (d4t->kick) 270 d4t->kick(clk); 271 272 return 0; 273 } 274 275 static int sh_clk_div4_enable(struct clk *clk) 276 { 277 __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << 8), clk->enable_reg); 278 return 0; 279 } 280 281 static void sh_clk_div4_disable(struct clk *clk) 282 { 283 __raw_writel(__raw_readl(clk->enable_reg) | (1 << 8), clk->enable_reg); 284 } 285 286 static struct clk_ops sh_clk_div4_clk_ops = { 287 .recalc = sh_clk_div4_recalc, 288 .set_rate = sh_clk_div4_set_rate, 289 .round_rate = sh_clk_div_round_rate, 290 }; 291 292 static struct clk_ops sh_clk_div4_enable_clk_ops = { 293 .recalc = sh_clk_div4_recalc, 294 .set_rate = sh_clk_div4_set_rate, 295 .round_rate = sh_clk_div_round_rate, 296 .enable = sh_clk_div4_enable, 297 .disable = sh_clk_div4_disable, 298 }; 299 300 static struct clk_ops sh_clk_div4_reparent_clk_ops = { 301 .recalc = sh_clk_div4_recalc, 302 .set_rate = sh_clk_div4_set_rate, 303 .round_rate = sh_clk_div_round_rate, 304 .enable = sh_clk_div4_enable, 305 .disable = sh_clk_div4_disable, 306 .set_parent = sh_clk_div4_set_parent, 307 }; 308 309 static int __init sh_clk_div4_register_ops(struct clk *clks, int nr, 310 struct clk_div4_table *table, struct clk_ops *ops) 311 { 312 struct clk *clkp; 313 void *freq_table; 314 int nr_divs = table->div_mult_table->nr_divisors; 315 int freq_table_size = sizeof(struct cpufreq_frequency_table); 316 int ret = 0; 317 int k; 318 319 freq_table_size *= (nr_divs + 1); 320 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); 321 if (!freq_table) { 322 pr_err("sh_clk_div4_register: unable to alloc memory\n"); 323 return -ENOMEM; 324 } 325 326 for (k = 0; !ret && (k < nr); k++) { 327 clkp = clks + k; 328 329 clkp->ops = ops; 330 clkp->priv = table; 331 332 clkp->freq_table = freq_table + (k * freq_table_size); 333 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; 334 335 ret = clk_register(clkp); 336 } 337 338 return ret; 339 } 340 341 int __init sh_clk_div4_register(struct clk *clks, int nr, 342 struct clk_div4_table *table) 343 { 344 return sh_clk_div4_register_ops(clks, nr, table, &sh_clk_div4_clk_ops); 345 } 346 347 int __init sh_clk_div4_enable_register(struct clk *clks, int nr, 348 struct clk_div4_table *table) 349 { 350 return sh_clk_div4_register_ops(clks, nr, table, 351 &sh_clk_div4_enable_clk_ops); 352 } 353 354 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, 355 struct clk_div4_table *table) 356 { 357 return sh_clk_div4_register_ops(clks, nr, table, 358 &sh_clk_div4_reparent_clk_ops); 359 } 360