1 /* 2 * Helper routines for SuperH Clock Pulse Generator blocks (CPG). 3 * 4 * Copyright (C) 2010 Magnus Damm 5 * Copyright (C) 2010 - 2012 Paul Mundt 6 * 7 * This file is subject to the terms and conditions of the GNU General Public 8 * License. See the file "COPYING" in the main directory of this archive 9 * for more details. 10 */ 11 #include <linux/clk.h> 12 #include <linux/compiler.h> 13 #include <linux/slab.h> 14 #include <linux/io.h> 15 #include <linux/sh_clk.h> 16 17 #define CPG_CKSTP_BIT BIT(8) 18 19 static unsigned int sh_clk_read(struct clk *clk) 20 { 21 if (clk->flags & CLK_ENABLE_REG_8BIT) 22 return ioread8(clk->mapped_reg); 23 else if (clk->flags & CLK_ENABLE_REG_16BIT) 24 return ioread16(clk->mapped_reg); 25 26 return ioread32(clk->mapped_reg); 27 } 28 29 static void sh_clk_write(int value, struct clk *clk) 30 { 31 if (clk->flags & CLK_ENABLE_REG_8BIT) 32 iowrite8(value, clk->mapped_reg); 33 else if (clk->flags & CLK_ENABLE_REG_16BIT) 34 iowrite16(value, clk->mapped_reg); 35 else 36 iowrite32(value, clk->mapped_reg); 37 } 38 39 static int sh_clk_mstp_enable(struct clk *clk) 40 { 41 sh_clk_write(sh_clk_read(clk) & ~(1 << clk->enable_bit), clk); 42 return 0; 43 } 44 45 static void sh_clk_mstp_disable(struct clk *clk) 46 { 47 sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk); 48 } 49 50 static struct sh_clk_ops sh_clk_mstp_clk_ops = { 51 .enable = sh_clk_mstp_enable, 52 .disable = sh_clk_mstp_disable, 53 .recalc = followparent_recalc, 54 }; 55 56 int __init sh_clk_mstp_register(struct clk *clks, int nr) 57 { 58 struct clk *clkp; 59 int ret = 0; 60 int k; 61 62 for (k = 0; !ret && (k < nr); k++) { 63 clkp = clks + k; 64 clkp->ops = &sh_clk_mstp_clk_ops; 65 ret |= clk_register(clkp); 66 } 67 68 return ret; 69 } 70 71 /* 72 * Div/mult table lookup helpers 73 */ 74 static inline struct clk_div_table *clk_to_div_table(struct clk *clk) 75 { 76 return clk->priv; 77 } 78 79 static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk) 80 { 81 return clk_to_div_table(clk)->div_mult_table; 82 } 83 84 /* 85 * Common div ops 86 */ 87 static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate) 88 { 89 return clk_rate_table_round(clk, clk->freq_table, rate); 90 } 91 92 static unsigned long sh_clk_div_recalc(struct clk *clk) 93 { 94 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 95 unsigned int idx; 96 97 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 98 table, clk->arch_flags ? &clk->arch_flags : NULL); 99 100 idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask; 101 102 return clk->freq_table[idx].frequency; 103 } 104 105 static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate) 106 { 107 struct clk_div_table *dt = clk_to_div_table(clk); 108 unsigned long value; 109 int idx; 110 111 idx = clk_rate_table_find(clk, clk->freq_table, rate); 112 if (idx < 0) 113 return idx; 114 115 value = sh_clk_read(clk); 116 value &= ~(clk->div_mask << clk->enable_bit); 117 value |= (idx << clk->enable_bit); 118 sh_clk_write(value, clk); 119 120 /* XXX: Should use a post-change notifier */ 121 if (dt->kick) 122 dt->kick(clk); 123 124 return 0; 125 } 126 127 static int sh_clk_div_enable(struct clk *clk) 128 { 129 sh_clk_write(sh_clk_read(clk) & ~CPG_CKSTP_BIT, clk); 130 return 0; 131 } 132 133 static void sh_clk_div_disable(struct clk *clk) 134 { 135 unsigned int val; 136 137 val = sh_clk_read(clk); 138 val |= CPG_CKSTP_BIT; 139 140 /* 141 * div6 clocks require the divisor field to be non-zero or the 142 * above CKSTP toggle silently fails. Ensure that the divisor 143 * array is reset to its initial state on disable. 144 */ 145 if (clk->flags & CLK_MASK_DIV_ON_DISABLE) 146 val |= clk->div_mask; 147 148 sh_clk_write(val, clk); 149 } 150 151 static struct sh_clk_ops sh_clk_div_clk_ops = { 152 .recalc = sh_clk_div_recalc, 153 .set_rate = sh_clk_div_set_rate, 154 .round_rate = sh_clk_div_round_rate, 155 }; 156 157 static struct sh_clk_ops sh_clk_div_enable_clk_ops = { 158 .recalc = sh_clk_div_recalc, 159 .set_rate = sh_clk_div_set_rate, 160 .round_rate = sh_clk_div_round_rate, 161 .enable = sh_clk_div_enable, 162 .disable = sh_clk_div_disable, 163 }; 164 165 static int __init sh_clk_init_parent(struct clk *clk) 166 { 167 u32 val; 168 169 if (clk->parent) 170 return 0; 171 172 if (!clk->parent_table || !clk->parent_num) 173 return 0; 174 175 if (!clk->src_width) { 176 pr_err("sh_clk_init_parent: cannot select parent clock\n"); 177 return -EINVAL; 178 } 179 180 val = (sh_clk_read(clk) >> clk->src_shift); 181 val &= (1 << clk->src_width) - 1; 182 183 if (val >= clk->parent_num) { 184 pr_err("sh_clk_init_parent: parent table size failed\n"); 185 return -EINVAL; 186 } 187 188 clk_reparent(clk, clk->parent_table[val]); 189 if (!clk->parent) { 190 pr_err("sh_clk_init_parent: unable to set parent"); 191 return -EINVAL; 192 } 193 194 return 0; 195 } 196 197 static int __init sh_clk_div_register_ops(struct clk *clks, int nr, 198 struct clk_div_table *table, struct sh_clk_ops *ops) 199 { 200 struct clk *clkp; 201 void *freq_table; 202 int nr_divs = table->div_mult_table->nr_divisors; 203 int freq_table_size = sizeof(struct cpufreq_frequency_table); 204 int ret = 0; 205 int k; 206 207 freq_table_size *= (nr_divs + 1); 208 freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL); 209 if (!freq_table) { 210 pr_err("%s: unable to alloc memory\n", __func__); 211 return -ENOMEM; 212 } 213 214 for (k = 0; !ret && (k < nr); k++) { 215 clkp = clks + k; 216 217 clkp->ops = ops; 218 clkp->priv = table; 219 220 clkp->freq_table = freq_table + (k * freq_table_size); 221 clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END; 222 223 ret = clk_register(clkp); 224 if (ret == 0) 225 ret = sh_clk_init_parent(clkp); 226 } 227 228 return ret; 229 } 230 231 /* 232 * div6 support 233 */ 234 static int sh_clk_div6_divisors[64] = { 235 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 236 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 237 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 238 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64 239 }; 240 241 static struct clk_div_mult_table div6_div_mult_table = { 242 .divisors = sh_clk_div6_divisors, 243 .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors), 244 }; 245 246 static struct clk_div_table sh_clk_div6_table = { 247 .div_mult_table = &div6_div_mult_table, 248 }; 249 250 static int sh_clk_div6_set_parent(struct clk *clk, struct clk *parent) 251 { 252 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 253 u32 value; 254 int ret, i; 255 256 if (!clk->parent_table || !clk->parent_num) 257 return -EINVAL; 258 259 /* Search the parent */ 260 for (i = 0; i < clk->parent_num; i++) 261 if (clk->parent_table[i] == parent) 262 break; 263 264 if (i == clk->parent_num) 265 return -ENODEV; 266 267 ret = clk_reparent(clk, parent); 268 if (ret < 0) 269 return ret; 270 271 value = sh_clk_read(clk) & 272 ~(((1 << clk->src_width) - 1) << clk->src_shift); 273 274 sh_clk_write(value | (i << clk->src_shift), clk); 275 276 /* Rebuild the frequency table */ 277 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 278 table, NULL); 279 280 return 0; 281 } 282 283 static struct sh_clk_ops sh_clk_div6_reparent_clk_ops = { 284 .recalc = sh_clk_div_recalc, 285 .round_rate = sh_clk_div_round_rate, 286 .set_rate = sh_clk_div_set_rate, 287 .enable = sh_clk_div_enable, 288 .disable = sh_clk_div_disable, 289 .set_parent = sh_clk_div6_set_parent, 290 }; 291 292 int __init sh_clk_div6_register(struct clk *clks, int nr) 293 { 294 return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, 295 &sh_clk_div_enable_clk_ops); 296 } 297 298 int __init sh_clk_div6_reparent_register(struct clk *clks, int nr) 299 { 300 return sh_clk_div_register_ops(clks, nr, &sh_clk_div6_table, 301 &sh_clk_div6_reparent_clk_ops); 302 } 303 304 /* 305 * div4 support 306 */ 307 static int sh_clk_div4_set_parent(struct clk *clk, struct clk *parent) 308 { 309 struct clk_div_mult_table *table = clk_to_div_mult_table(clk); 310 u32 value; 311 int ret; 312 313 /* we really need a better way to determine parent index, but for 314 * now assume internal parent comes with CLK_ENABLE_ON_INIT set, 315 * no CLK_ENABLE_ON_INIT means external clock... 316 */ 317 318 if (parent->flags & CLK_ENABLE_ON_INIT) 319 value = sh_clk_read(clk) & ~(1 << 7); 320 else 321 value = sh_clk_read(clk) | (1 << 7); 322 323 ret = clk_reparent(clk, parent); 324 if (ret < 0) 325 return ret; 326 327 sh_clk_write(value, clk); 328 329 /* Rebiuld the frequency table */ 330 clk_rate_table_build(clk, clk->freq_table, table->nr_divisors, 331 table, &clk->arch_flags); 332 333 return 0; 334 } 335 336 static struct sh_clk_ops sh_clk_div4_reparent_clk_ops = { 337 .recalc = sh_clk_div_recalc, 338 .set_rate = sh_clk_div_set_rate, 339 .round_rate = sh_clk_div_round_rate, 340 .enable = sh_clk_div_enable, 341 .disable = sh_clk_div_disable, 342 .set_parent = sh_clk_div4_set_parent, 343 }; 344 345 int __init sh_clk_div4_register(struct clk *clks, int nr, 346 struct clk_div4_table *table) 347 { 348 return sh_clk_div_register_ops(clks, nr, table, &sh_clk_div_clk_ops); 349 } 350 351 int __init sh_clk_div4_enable_register(struct clk *clks, int nr, 352 struct clk_div4_table *table) 353 { 354 return sh_clk_div_register_ops(clks, nr, table, 355 &sh_clk_div_enable_clk_ops); 356 } 357 358 int __init sh_clk_div4_reparent_register(struct clk *clks, int nr, 359 struct clk_div4_table *table) 360 { 361 return sh_clk_div_register_ops(clks, nr, table, 362 &sh_clk_div4_reparent_clk_ops); 363 } 364 365 /* FSI-DIV */ 366 static unsigned long fsidiv_recalc(struct clk *clk) 367 { 368 u32 value; 369 370 value = __raw_readl(clk->mapping->base); 371 372 value >>= 16; 373 if (value < 2) 374 return clk->parent->rate; 375 376 return clk->parent->rate / value; 377 } 378 379 static long fsidiv_round_rate(struct clk *clk, unsigned long rate) 380 { 381 return clk_rate_div_range_round(clk, 1, 0xffff, rate); 382 } 383 384 static void fsidiv_disable(struct clk *clk) 385 { 386 __raw_writel(0, clk->mapping->base); 387 } 388 389 static int fsidiv_enable(struct clk *clk) 390 { 391 u32 value; 392 393 value = __raw_readl(clk->mapping->base) >> 16; 394 if (value < 2) 395 return 0; 396 397 __raw_writel((value << 16) | 0x3, clk->mapping->base); 398 399 return 0; 400 } 401 402 static int fsidiv_set_rate(struct clk *clk, unsigned long rate) 403 { 404 int idx; 405 406 idx = (clk->parent->rate / rate) & 0xffff; 407 if (idx < 2) 408 __raw_writel(0, clk->mapping->base); 409 else 410 __raw_writel(idx << 16, clk->mapping->base); 411 412 return 0; 413 } 414 415 static struct sh_clk_ops fsidiv_clk_ops = { 416 .recalc = fsidiv_recalc, 417 .round_rate = fsidiv_round_rate, 418 .set_rate = fsidiv_set_rate, 419 .enable = fsidiv_enable, 420 .disable = fsidiv_disable, 421 }; 422 423 int __init sh_clk_fsidiv_register(struct clk *clks, int nr) 424 { 425 struct clk_mapping *map; 426 int i; 427 428 for (i = 0; i < nr; i++) { 429 430 map = kzalloc(sizeof(struct clk_mapping), GFP_KERNEL); 431 if (!map) { 432 pr_err("%s: unable to alloc memory\n", __func__); 433 return -ENOMEM; 434 } 435 436 /* clks[i].enable_reg came from SH_CLK_FSIDIV() */ 437 map->phys = (phys_addr_t)clks[i].enable_reg; 438 map->len = 8; 439 440 clks[i].enable_reg = 0; /* remove .enable_reg */ 441 clks[i].ops = &fsidiv_clk_ops; 442 clks[i].mapping = map; 443 444 clk_register(&clks[i]); 445 } 446 447 return 0; 448 } 449