1/* linux/arch/arm/mach-s3c2443/clock.c 2 * 3 * Copyright (c) 2007, 2010 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * S3C2443 Clock control support 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*/ 22 23#include <linux/init.h> 24 25#include <linux/module.h> 26#include <linux/kernel.h> 27#include <linux/list.h> 28#include <linux/errno.h> 29#include <linux/err.h> 30#include <linux/sysdev.h> 31#include <linux/clk.h> 32#include <linux/mutex.h> 33#include <linux/serial_core.h> 34#include <linux/io.h> 35 36#include <asm/mach/map.h> 37 38#include <mach/hardware.h> 39 40#include <mach/regs-s3c2443-clock.h> 41 42#include <plat/cpu-freq.h> 43 44#include <plat/s3c2443.h> 45#include <plat/clock.h> 46#include <plat/clock-clksrc.h> 47#include <plat/cpu.h> 48 49/* We currently have to assume that the system is running 50 * from the XTPll input, and that all ***REFCLKs are being 51 * fed from it, as we cannot read the state of OM[4] from 52 * software. 53 * 54 * It would be possible for each board initialisation to 55 * set the correct muxing at initialisation 56*/ 57 58/* clock selections */ 59 60static struct clk clk_i2s_ext = { 61 .name = "i2s-ext", 62 .id = -1, 63}; 64 65/* armdiv 66 * 67 * this clock is sourced from msysclk and can have a number of 68 * divider values applied to it to then be fed into armclk. 69*/ 70 71/* armdiv divisor table */ 72 73static unsigned int armdiv[16] = { 74 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, 75 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, 76 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, 77 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, 78 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, 79 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, 80 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, 81 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, 82}; 83 84static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) 85{ 86 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; 87 88 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; 89} 90 91static unsigned long s3c2443_armclk_roundrate(struct clk *clk, 92 unsigned long rate) 93{ 94 unsigned long parent = clk_get_rate(clk->parent); 95 unsigned long calc; 96 unsigned best = 256; /* bigger than any value */ 97 unsigned div; 98 int ptr; 99 100 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) { 101 div = armdiv[ptr]; 102 calc = parent / div; 103 if (calc <= rate && div < best) 104 best = div; 105 } 106 107 return parent / best; 108} 109 110static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) 111{ 112 unsigned long parent = clk_get_rate(clk->parent); 113 unsigned long calc; 114 unsigned div; 115 unsigned best = 256; /* bigger than any value */ 116 int ptr; 117 int val = -1; 118 119 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) { 120 div = armdiv[ptr]; 121 calc = parent / div; 122 if (calc <= rate && div < best) { 123 best = div; 124 val = ptr; 125 } 126 } 127 128 if (val >= 0) { 129 unsigned long clkcon0; 130 131 clkcon0 = __raw_readl(S3C2443_CLKDIV0); 132 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; 133 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; 134 __raw_writel(clkcon0, S3C2443_CLKDIV0); 135 } 136 137 return (val == -1) ? -EINVAL : 0; 138} 139 140static struct clk clk_armdiv = { 141 .name = "armdiv", 142 .id = -1, 143 .parent = &clk_msysclk.clk, 144 .ops = &(struct clk_ops) { 145 .round_rate = s3c2443_armclk_roundrate, 146 .set_rate = s3c2443_armclk_setrate, 147 }, 148}; 149 150/* armclk 151 * 152 * this is the clock fed into the ARM core itself, from armdiv or from hclk. 153 */ 154 155static struct clk *clk_arm_sources[] = { 156 [0] = &clk_armdiv, 157 [1] = &clk_h, 158}; 159 160static struct clksrc_clk clk_arm = { 161 .clk = { 162 .name = "armclk", 163 .id = -1, 164 }, 165 .sources = &(struct clksrc_sources) { 166 .sources = clk_arm_sources, 167 .nr_sources = ARRAY_SIZE(clk_arm_sources), 168 }, 169 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, 170}; 171 172/* hsspi 173 * 174 * high-speed spi clock, sourced from esysclk 175*/ 176 177static struct clksrc_clk clk_hsspi = { 178 .clk = { 179 .name = "hsspi", 180 .id = -1, 181 .parent = &clk_esysclk.clk, 182 .ctrlbit = S3C2443_SCLKCON_HSSPICLK, 183 .enable = s3c2443_clkcon_enable_s, 184 }, 185 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, 186}; 187 188 189/* clk_hsmcc_div 190 * 191 * this clock is sourced from epll, and is fed through a divider, 192 * to a mux controlled by sclkcon where either it or a extclk can 193 * be fed to the hsmmc block 194*/ 195 196static struct clksrc_clk clk_hsmmc_div = { 197 .clk = { 198 .name = "hsmmc-div", 199 .id = -1, 200 .parent = &clk_esysclk.clk, 201 }, 202 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, 203}; 204 205static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) 206{ 207 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON); 208 209 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT | 210 S3C2443_SCLKCON_HSMMCCLK_EPLL); 211 212 if (parent == &clk_epll) 213 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL; 214 else if (parent == &clk_ext) 215 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT; 216 else 217 return -EINVAL; 218 219 if (clk->usage > 0) { 220 __raw_writel(clksrc, S3C2443_SCLKCON); 221 } 222 223 clk->parent = parent; 224 return 0; 225} 226 227static int s3c2443_enable_hsmmc(struct clk *clk, int enable) 228{ 229 return s3c2443_setparent_hsmmc(clk, clk->parent); 230} 231 232static struct clk clk_hsmmc = { 233 .name = "hsmmc-if", 234 .id = -1, 235 .parent = &clk_hsmmc_div.clk, 236 .enable = s3c2443_enable_hsmmc, 237 .ops = &(struct clk_ops) { 238 .set_parent = s3c2443_setparent_hsmmc, 239 }, 240}; 241 242/* i2s_eplldiv 243 * 244 * This clock is the output from the I2S divisor of ESYSCLK, and is separate 245 * from the mux that comes after it (cannot merge into one single clock) 246*/ 247 248static struct clksrc_clk clk_i2s_eplldiv = { 249 .clk = { 250 .name = "i2s-eplldiv", 251 .id = -1, 252 .parent = &clk_esysclk.clk, 253 }, 254 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, 255}; 256 257/* i2s-ref 258 * 259 * i2s bus reference clock, selectable from external, esysclk or epllref 260 * 261 * Note, this used to be two clocks, but was compressed into one. 262*/ 263 264struct clk *clk_i2s_srclist[] = { 265 [0] = &clk_i2s_eplldiv.clk, 266 [1] = &clk_i2s_ext, 267 [2] = &clk_epllref.clk, 268 [3] = &clk_epllref.clk, 269}; 270 271static struct clksrc_clk clk_i2s = { 272 .clk = { 273 .name = "i2s-if", 274 .id = -1, 275 .ctrlbit = S3C2443_SCLKCON_I2SCLK, 276 .enable = s3c2443_clkcon_enable_s, 277 278 }, 279 .sources = &(struct clksrc_sources) { 280 .sources = clk_i2s_srclist, 281 .nr_sources = ARRAY_SIZE(clk_i2s_srclist), 282 }, 283 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, 284}; 285 286/* standard clock definitions */ 287 288static struct clk init_clocks_off[] = { 289 { 290 .name = "sdi", 291 .id = -1, 292 .parent = &clk_p, 293 .enable = s3c2443_clkcon_enable_p, 294 .ctrlbit = S3C2443_PCLKCON_SDI, 295 }, { 296 .name = "iis", 297 .id = -1, 298 .parent = &clk_p, 299 .enable = s3c2443_clkcon_enable_p, 300 .ctrlbit = S3C2443_PCLKCON_IIS, 301 }, { 302 .name = "spi", 303 .id = 0, 304 .parent = &clk_p, 305 .enable = s3c2443_clkcon_enable_p, 306 .ctrlbit = S3C2443_PCLKCON_SPI0, 307 }, { 308 .name = "spi", 309 .id = 1, 310 .parent = &clk_p, 311 .enable = s3c2443_clkcon_enable_p, 312 .ctrlbit = S3C2443_PCLKCON_SPI1, 313 } 314}; 315 316static struct clk init_clocks[] = { 317}; 318 319/* clocks to add straight away */ 320 321static struct clksrc_clk *clksrcs[] __initdata = { 322 &clk_arm, 323 &clk_i2s_eplldiv, 324 &clk_i2s, 325 &clk_hsspi, 326 &clk_hsmmc_div, 327}; 328 329static struct clk *clks[] __initdata = { 330 &clk_hsmmc, 331 &clk_armdiv, 332}; 333 334void __init_or_cpufreq s3c2443_setup_clocks(void) 335{ 336 s3c2443_common_setup_clocks(s3c2443_get_mpll, s3c2443_fclk_div); 337} 338 339void __init s3c2443_init_clocks(int xtal) 340{ 341 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); 342 int ptr; 343 344 clk_epll.rate = s3c2443_get_epll(epllcon, xtal); 345 clk_epll.parent = &clk_epllref.clk; 346 347 s3c2443_common_init_clocks(xtal, s3c2443_get_mpll, s3c2443_fclk_div); 348 349 s3c2443_setup_clocks(); 350 351 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); 352 353 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 354 s3c_register_clksrc(clksrcs[ptr], 1); 355 356 /* register clocks from clock array */ 357 358 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 359 360 /* We must be careful disabling the clocks we are not intending to 361 * be using at boot time, as subsystems such as the LCD which do 362 * their own DMA requests to the bus can cause the system to lockup 363 * if they where in the middle of requesting bus access. 364 * 365 * Disabling the LCD clock if the LCD is active is very dangerous, 366 * and therefore the bootloader should be careful to not enable 367 * the LCD clock if it is not needed. 368 */ 369 370 /* install (and disable) the clocks we do not need immediately */ 371 372 s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 373 s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); 374 375 s3c_pwmclk_init(); 376} 377