diff options
| -rw-r--r-- | arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h | 32 | ||||
| -rw-r--r-- | arch/arm/mach-s3c2443/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-s3c2443/clock.c | 817 |
3 files changed, 261 insertions, 589 deletions
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h index 6026d091a2fe..d87ebe0cb625 100644 --- a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h +++ b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h | |||
| @@ -42,23 +42,14 @@ | |||
| 42 | 42 | ||
| 43 | #define S3C2443_PLLCON_OFF (1<<24) | 43 | #define S3C2443_PLLCON_OFF (1<<24) |
| 44 | 44 | ||
| 45 | #define S3C2443_CLKSRC_I2S_EXT (1<<14) | ||
| 46 | #define S3C2443_CLKSRC_I2S_EPLLDIV (0<<14) | ||
| 47 | #define S3C2443_CLKSRC_I2S_EPLLREF (2<<14) | ||
| 48 | #define S3C2443_CLKSRC_I2S_EPLLREF3 (3<<14) | ||
| 49 | #define S3C2443_CLKSRC_I2S_MASK (3<<14) | ||
| 50 | |||
| 51 | #define S3C2443_CLKSRC_EPLLREF_XTAL (2<<7) | 45 | #define S3C2443_CLKSRC_EPLLREF_XTAL (2<<7) |
| 52 | #define S3C2443_CLKSRC_EPLLREF_EXTCLK (3<<7) | 46 | #define S3C2443_CLKSRC_EPLLREF_EXTCLK (3<<7) |
| 53 | #define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<7) | 47 | #define S3C2443_CLKSRC_EPLLREF_MPLLREF (0<<7) |
| 54 | #define S3C2443_CLKSRC_EPLLREF_MPLLREF2 (1<<7) | 48 | #define S3C2443_CLKSRC_EPLLREF_MPLLREF2 (1<<7) |
| 55 | #define S3C2443_CLKSRC_EPLLREF_MASK (3<<7) | 49 | #define S3C2443_CLKSRC_EPLLREF_MASK (3<<7) |
| 56 | 50 | ||
| 57 | #define S3C2443_CLKSRC_ESYSCLK_EPLL (1<<6) | ||
| 58 | #define S3C2443_CLKSRC_MSYSCLK_MPLL (1<<4) | ||
| 59 | #define S3C2443_CLKSRC_EXTCLK_DIV (1<<3) | 51 | #define S3C2443_CLKSRC_EXTCLK_DIV (1<<3) |
| 60 | 52 | ||
| 61 | #define S3C2443_CLKDIV0_DVS (1<<13) | ||
| 62 | #define S3C2443_CLKDIV0_HALF_HCLK (1<<3) | 53 | #define S3C2443_CLKDIV0_HALF_HCLK (1<<3) |
| 63 | #define S3C2443_CLKDIV0_HALF_PCLK (1<<2) | 54 | #define S3C2443_CLKDIV0_HALF_PCLK (1<<2) |
| 64 | 55 | ||
| @@ -81,28 +72,7 @@ | |||
| 81 | #define S3C2443_CLKDIV0_ARMDIV_12 (13<<9) | 72 | #define S3C2443_CLKDIV0_ARMDIV_12 (13<<9) |
| 82 | #define S3C2443_CLKDIV0_ARMDIV_16 (15<<9) | 73 | #define S3C2443_CLKDIV0_ARMDIV_16 (15<<9) |
| 83 | 74 | ||
| 84 | /* S3C2443_CLKDIV1 */ | 75 | /* S3C2443_CLKDIV1 removed, only used in clock.c code */ |
| 85 | |||
| 86 | #define S3C2443_CLKDIV1_CAMDIV_MASK (15<<26) | ||
| 87 | #define S3C2443_CLKDIV1_CAMDIV_SHIFT (26) | ||
| 88 | |||
| 89 | #define S3C2443_CLKDIV1_HSSPIDIV_MASK (3<<24) | ||
| 90 | #define S3C2443_CLKDIV1_HSSPIDIV_SHIFT (24) | ||
| 91 | |||
| 92 | #define S3C2443_CLKDIV1_DISPDIV_MASK (0xff<<16) | ||
| 93 | #define S3C2443_CLKDIV1_DISPDIV_SHIFT (16) | ||
| 94 | |||
| 95 | #define S3C2443_CLKDIV1_I2SDIV_MASK (15<<12) | ||
| 96 | #define S3C2443_CLKDIV1_I2SDIV_SHIFT (12) | ||
| 97 | |||
| 98 | #define S3C2443_CLKDIV1_UARTDIV_MASK (15<<8) | ||
| 99 | #define S3C2443_CLKDIV1_UARTDIV_SHIFT (8) | ||
| 100 | |||
| 101 | #define S3C2443_CLKDIV1_HSMMCDIV_MASK (3<<6) | ||
| 102 | #define S3C2443_CLKDIV1_HSMMCDIV_SHIFT (6) | ||
| 103 | |||
| 104 | #define S3C2443_CLKDIV1_USBHOSTDIV_MASK (3<<4) | ||
| 105 | #define S3C2443_CLKDIV1_USBHOSTDIV_SHIFT (4) | ||
| 106 | 76 | ||
| 107 | #define S3C2443_CLKCON_NAND | 77 | #define S3C2443_CLKCON_NAND |
| 108 | 78 | ||
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig index 4314c4424909..698140af247c 100644 --- a/arch/arm/mach-s3c2443/Kconfig +++ b/arch/arm/mach-s3c2443/Kconfig | |||
| @@ -7,6 +7,7 @@ config CPU_S3C2443 | |||
| 7 | depends on ARCH_S3C2410 | 7 | depends on ARCH_S3C2410 |
| 8 | select S3C2443_DMA if S3C2410_DMA | 8 | select S3C2443_DMA if S3C2410_DMA |
| 9 | select CPU_LLSERIAL_S3C2440 | 9 | select CPU_LLSERIAL_S3C2440 |
| 10 | select SAMSUNG_CLKSRC | ||
| 10 | help | 11 | help |
| 11 | Support for the S3C2443 SoC from the S3C24XX line | 12 | Support for the S3C2443 SoC from the S3C24XX line |
| 12 | 13 | ||
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c index 3eb8b935d64c..62cd4eaee01b 100644 --- a/arch/arm/mach-s3c2443/clock.c +++ b/arch/arm/mach-s3c2443/clock.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* linux/arch/arm/mach-s3c2443/clock.c | 1 | /* linux/arch/arm/mach-s3c2443/clock.c |
| 2 | * | 2 | * |
| 3 | * Copyright (c) 2007 Simtec Electronics | 3 | * Copyright (c) 2007, 2010 Simtec Electronics |
| 4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
| 5 | * | 5 | * |
| 6 | * S3C2443 Clock control support | 6 | * S3C2443 Clock control support |
| @@ -42,6 +42,7 @@ | |||
| 42 | 42 | ||
| 43 | #include <plat/s3c2443.h> | 43 | #include <plat/s3c2443.h> |
| 44 | #include <plat/clock.h> | 44 | #include <plat/clock.h> |
| 45 | #include <plat/clock-clksrc.h> | ||
| 45 | #include <plat/cpu.h> | 46 | #include <plat/cpu.h> |
| 46 | 47 | ||
| 47 | /* We currently have to assume that the system is running | 48 | /* We currently have to assume that the system is running |
| @@ -53,143 +54,69 @@ | |||
| 53 | * set the correct muxing at initialisation | 54 | * set the correct muxing at initialisation |
| 54 | */ | 55 | */ |
| 55 | 56 | ||
| 56 | static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) | 57 | static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable) |
| 57 | { | ||
| 58 | unsigned int clocks = clk->ctrlbit; | ||
| 59 | unsigned long clkcon; | ||
| 60 | |||
| 61 | clkcon = __raw_readl(S3C2443_HCLKCON); | ||
| 62 | |||
| 63 | if (enable) | ||
| 64 | clkcon |= clocks; | ||
| 65 | else | ||
| 66 | clkcon &= ~clocks; | ||
| 67 | |||
| 68 | __raw_writel(clkcon, S3C2443_HCLKCON); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) | ||
| 74 | { | ||
| 75 | unsigned int clocks = clk->ctrlbit; | ||
| 76 | unsigned long clkcon; | ||
| 77 | |||
| 78 | clkcon = __raw_readl(S3C2443_PCLKCON); | ||
| 79 | |||
| 80 | if (enable) | ||
| 81 | clkcon |= clocks; | ||
| 82 | else | ||
| 83 | clkcon &= ~clocks; | ||
| 84 | |||
| 85 | __raw_writel(clkcon, S3C2443_PCLKCON); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) | ||
| 91 | { | 58 | { |
| 92 | unsigned int clocks = clk->ctrlbit; | 59 | u32 ctrlbit = clk->ctrlbit; |
| 93 | unsigned long clkcon; | 60 | u32 con = __raw_readl(reg); |
| 94 | |||
| 95 | clkcon = __raw_readl(S3C2443_SCLKCON); | ||
| 96 | 61 | ||
| 97 | if (enable) | 62 | if (enable) |
| 98 | clkcon |= clocks; | 63 | con |= ctrlbit; |
| 99 | else | 64 | else |
| 100 | clkcon &= ~clocks; | 65 | con &= ~ctrlbit; |
| 101 | |||
| 102 | __raw_writel(clkcon, S3C2443_SCLKCON); | ||
| 103 | 66 | ||
| 67 | __raw_writel(con, reg); | ||
| 104 | return 0; | 68 | return 0; |
| 105 | } | 69 | } |
| 106 | 70 | ||
| 107 | static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, | 71 | static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) |
| 108 | unsigned long rate, | ||
| 109 | unsigned int max) | ||
| 110 | { | ||
| 111 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 112 | int div; | ||
| 113 | |||
| 114 | if (rate > parent_rate) | ||
| 115 | return parent_rate; | ||
| 116 | |||
| 117 | /* note, we remove the +/- 1 calculations as they cancel out */ | ||
| 118 | |||
| 119 | div = (rate / parent_rate); | ||
| 120 | |||
| 121 | if (div < 1) | ||
| 122 | div = 1; | ||
| 123 | else if (div > max) | ||
| 124 | div = max; | ||
| 125 | |||
| 126 | return parent_rate / div; | ||
| 127 | } | ||
| 128 | |||
| 129 | static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk, | ||
| 130 | unsigned long rate) | ||
| 131 | { | 72 | { |
| 132 | return s3c2443_roundrate_clksrc(clk, rate, 4); | 73 | return s3c2443_gate(S3C2443_HCLKCON, clk, enable); |
| 133 | } | 74 | } |
| 134 | 75 | ||
| 135 | static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, | 76 | static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) |
| 136 | unsigned long rate) | ||
| 137 | { | 77 | { |
| 138 | return s3c2443_roundrate_clksrc(clk, rate, 16); | 78 | return s3c2443_gate(S3C2443_PCLKCON, clk, enable); |
| 139 | } | 79 | } |
| 140 | 80 | ||
| 141 | static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, | 81 | static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) |
| 142 | unsigned long rate) | ||
| 143 | { | 82 | { |
| 144 | return s3c2443_roundrate_clksrc(clk, rate, 256); | 83 | return s3c2443_gate(S3C2443_SCLKCON, clk, enable); |
| 145 | } | 84 | } |
| 146 | 85 | ||
| 147 | /* clock selections */ | 86 | /* clock selections */ |
| 148 | 87 | ||
| 88 | /* mpllref is a direct descendant of clk_xtal by default, but it is not | ||
| 89 | * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as | ||
| 90 | * such directly equating the two source clocks is impossible. | ||
| 91 | */ | ||
| 149 | static struct clk clk_mpllref = { | 92 | static struct clk clk_mpllref = { |
| 150 | .name = "mpllref", | 93 | .name = "mpllref", |
| 151 | .parent = &clk_xtal, | 94 | .parent = &clk_xtal, |
| 152 | .id = -1, | 95 | .id = -1, |
| 153 | }; | 96 | }; |
| 154 | 97 | ||
| 155 | #if 0 | ||
| 156 | static struct clk clk_mpll = { | ||
| 157 | .name = "mpll", | ||
| 158 | .parent = &clk_mpllref, | ||
| 159 | .id = -1, | ||
| 160 | }; | ||
| 161 | #endif | ||
| 162 | |||
| 163 | static struct clk clk_i2s_ext = { | 98 | static struct clk clk_i2s_ext = { |
| 164 | .name = "i2s-ext", | 99 | .name = "i2s-ext", |
| 165 | .id = -1, | 100 | .id = -1, |
| 166 | }; | 101 | }; |
| 167 | 102 | ||
| 168 | static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) | 103 | static struct clk *clk_epllref_sources[] = { |
| 169 | { | 104 | [0] = &clk_mpllref, |
| 170 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 105 | [1] = &clk_mpllref, |
| 171 | 106 | [2] = &clk_xtal, | |
| 172 | clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; | 107 | [3] = &clk_ext, |
| 173 | 108 | }; | |
| 174 | if (parent == &clk_xtal) | ||
| 175 | clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL; | ||
| 176 | else if (parent == &clk_ext) | ||
| 177 | clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK; | ||
| 178 | else if (parent != &clk_mpllref) | ||
| 179 | return -EINVAL; | ||
| 180 | |||
| 181 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
| 182 | clk->parent = parent; | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | 109 | ||
| 187 | static struct clk clk_epllref = { | 110 | static struct clksrc_clk clk_epllref = { |
| 188 | .name = "epllref", | 111 | .clk = { |
| 189 | .id = -1, | 112 | .name = "epllref", |
| 190 | .ops = &(struct clk_ops) { | 113 | .id = -1, |
| 191 | .set_parent = s3c2443_setparent_epllref, | 114 | }, |
| 115 | .sources = &(struct clksrc_sources) { | ||
| 116 | .sources = clk_epllref_sources, | ||
| 117 | .nr_sources = ARRAY_SIZE(clk_epllref_sources), | ||
| 192 | }, | 118 | }, |
| 119 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, | ||
| 193 | }; | 120 | }; |
| 194 | 121 | ||
| 195 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) | 122 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) |
| @@ -212,33 +139,24 @@ static struct clk clk_mdivclk = { | |||
| 212 | }, | 139 | }, |
| 213 | }; | 140 | }; |
| 214 | 141 | ||
| 215 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) | 142 | static struct clk *clk_msysclk_sources[] = { |
| 216 | { | 143 | [0] = &clk_mpllref, |
| 217 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 144 | [1] = &clk_mpll, |
| 218 | 145 | [2] = &clk_mdivclk, | |
| 219 | clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | | 146 | [3] = &clk_mpllref, |
| 220 | S3C2443_CLKSRC_EXTCLK_DIV); | 147 | }; |
| 221 | |||
| 222 | if (parent == &clk_mpll) | ||
| 223 | clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL; | ||
| 224 | else if (parent == &clk_mdivclk) | ||
| 225 | clksrc |= S3C2443_CLKSRC_EXTCLK_DIV; | ||
| 226 | else if (parent != &clk_mpllref) | ||
| 227 | return -EINVAL; | ||
| 228 | |||
| 229 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
| 230 | clk->parent = parent; | ||
| 231 | |||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | 148 | ||
| 235 | static struct clk clk_msysclk = { | 149 | static struct clksrc_clk clk_msysclk = { |
| 236 | .name = "msysclk", | 150 | .clk = { |
| 237 | .parent = &clk_xtal, | 151 | .name = "msysclk", |
| 238 | .id = -1, | 152 | .parent = &clk_xtal, |
| 239 | .ops = &(struct clk_ops) { | 153 | .id = -1, |
| 240 | .set_parent = s3c2443_setparent_msysclk, | 154 | }, |
| 155 | .sources = &(struct clksrc_sources) { | ||
| 156 | .sources = clk_msysclk_sources, | ||
| 157 | .nr_sources = ARRAY_SIZE(clk_msysclk_sources), | ||
| 241 | }, | 158 | }, |
| 159 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, | ||
| 242 | }; | 160 | }; |
| 243 | 161 | ||
| 244 | /* armdiv | 162 | /* armdiv |
| @@ -247,72 +165,128 @@ static struct clk clk_msysclk = { | |||
| 247 | * divider values applied to it to then be fed into armclk. | 165 | * divider values applied to it to then be fed into armclk. |
| 248 | */ | 166 | */ |
| 249 | 167 | ||
| 250 | static struct clk clk_armdiv = { | 168 | /* armdiv divisor table */ |
| 251 | .name = "armdiv", | 169 | |
| 252 | .id = -1, | 170 | static unsigned int armdiv[16] = { |
| 253 | .parent = &clk_msysclk, | 171 | [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, |
| 172 | [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, | ||
| 173 | [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, | ||
| 174 | [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, | ||
| 175 | [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, | ||
| 176 | [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, | ||
| 177 | [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, | ||
| 178 | [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, | ||
| 254 | }; | 179 | }; |
| 255 | 180 | ||
| 256 | /* armclk | 181 | static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) |
| 257 | * | 182 | { |
| 258 | * this is the clock fed into the ARM core itself, either from | 183 | clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; |
| 259 | * armdiv or from hclk. | ||
| 260 | */ | ||
| 261 | 184 | ||
| 262 | static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) | 185 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; |
| 186 | } | ||
| 187 | |||
| 188 | static unsigned long s3c2443_armclk_roundrate(struct clk *clk, | ||
| 189 | unsigned long rate) | ||
| 263 | { | 190 | { |
| 264 | unsigned long clkdiv0; | 191 | unsigned long parent = clk_get_rate(clk->parent); |
| 192 | unsigned long calc; | ||
| 193 | unsigned best = 256; /* bigger than any value */ | ||
| 194 | unsigned div; | ||
| 195 | int ptr; | ||
| 265 | 196 | ||
| 266 | clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | 197 | for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) { |
| 198 | div = armdiv[ptr]; | ||
| 199 | calc = parent / div; | ||
| 200 | if (calc <= rate && div < best) | ||
| 201 | best = div; | ||
| 202 | } | ||
| 267 | 203 | ||
| 268 | if (parent == &clk_armdiv) | 204 | return parent / best; |
| 269 | clkdiv0 &= ~S3C2443_CLKDIV0_DVS; | 205 | } |
| 270 | else if (parent == &clk_h) | ||
| 271 | clkdiv0 |= S3C2443_CLKDIV0_DVS; | ||
| 272 | else | ||
| 273 | return -EINVAL; | ||
| 274 | 206 | ||
| 275 | __raw_writel(clkdiv0, S3C2443_CLKDIV0); | 207 | static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) |
| 276 | return 0; | 208 | { |
| 209 | unsigned long parent = clk_get_rate(clk->parent); | ||
| 210 | unsigned long calc; | ||
| 211 | unsigned div; | ||
| 212 | unsigned best = 256; /* bigger than any value */ | ||
| 213 | int ptr; | ||
| 214 | int val = -1; | ||
| 215 | |||
| 216 | for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) { | ||
| 217 | div = armdiv[ptr]; | ||
| 218 | calc = parent / div; | ||
| 219 | if (calc <= rate && div < best) { | ||
| 220 | best = div; | ||
| 221 | val = ptr; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | if (val >= 0) { | ||
| 226 | unsigned long clkcon0; | ||
| 227 | |||
| 228 | clkcon0 = __raw_readl(S3C2443_CLKDIV0); | ||
| 229 | clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; | ||
| 230 | clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; | ||
| 231 | __raw_writel(clkcon0, S3C2443_CLKDIV0); | ||
| 232 | } | ||
| 233 | |||
| 234 | return (val == -1) ? -EINVAL : 0; | ||
| 277 | } | 235 | } |
| 278 | 236 | ||
| 279 | static struct clk clk_arm = { | 237 | static struct clk clk_armdiv = { |
| 280 | .name = "armclk", | 238 | .name = "armdiv", |
| 281 | .id = -1, | 239 | .id = -1, |
| 240 | .parent = &clk_msysclk.clk, | ||
| 282 | .ops = &(struct clk_ops) { | 241 | .ops = &(struct clk_ops) { |
| 283 | .set_parent = s3c2443_setparent_armclk, | 242 | .round_rate = s3c2443_armclk_roundrate, |
| 243 | .set_rate = s3c2443_armclk_setrate, | ||
| 284 | }, | 244 | }, |
| 285 | }; | 245 | }; |
| 286 | 246 | ||
| 287 | /* esysclk | 247 | /* armclk |
| 288 | * | 248 | * |
| 289 | * this is sourced from either the EPLL or the EPLLref clock | 249 | * this is the clock fed into the ARM core itself, from armdiv or from hclk. |
| 290 | */ | 250 | */ |
| 291 | 251 | ||
| 292 | static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) | 252 | static struct clk *clk_arm_sources[] = { |
| 293 | { | 253 | [0] = &clk_armdiv, |
| 294 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 254 | [1] = &clk_h, |
| 255 | }; | ||
| 295 | 256 | ||
| 296 | if (parent == &clk_epll) | 257 | static struct clksrc_clk clk_arm = { |
| 297 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; | 258 | .clk = { |
| 298 | else if (parent == &clk_epllref) | 259 | .name = "armclk", |
| 299 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; | 260 | .id = -1, |
| 300 | else | 261 | }, |
| 301 | return -EINVAL; | 262 | .sources = &(struct clksrc_sources) { |
| 263 | .sources = clk_arm_sources, | ||
| 264 | .nr_sources = ARRAY_SIZE(clk_arm_sources), | ||
| 265 | }, | ||
| 266 | .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, | ||
| 267 | }; | ||
| 302 | 268 | ||
| 303 | __raw_writel(clksrc, S3C2443_CLKSRC); | 269 | /* esysclk |
| 304 | clk->parent = parent; | 270 | * |
| 271 | * this is sourced from either the EPLL or the EPLLref clock | ||
| 272 | */ | ||
| 305 | 273 | ||
| 306 | return 0; | 274 | static struct clk *clk_sysclk_sources[] = { |
| 307 | } | 275 | [0] = &clk_epllref.clk, |
| 276 | [1] = &clk_epll, | ||
| 277 | }; | ||
| 308 | 278 | ||
| 309 | static struct clk clk_esysclk = { | 279 | static struct clksrc_clk clk_esysclk = { |
| 310 | .name = "esysclk", | 280 | .clk = { |
| 311 | .parent = &clk_epll, | 281 | .name = "esysclk", |
| 312 | .id = -1, | 282 | .parent = &clk_epll, |
| 313 | .ops = &(struct clk_ops) { | 283 | .id = -1, |
| 314 | .set_parent = s3c2443_setparent_esysclk, | 284 | }, |
| 285 | .sources = &(struct clksrc_sources) { | ||
| 286 | .sources = clk_sysclk_sources, | ||
| 287 | .nr_sources = ARRAY_SIZE(clk_sysclk_sources), | ||
| 315 | }, | 288 | }, |
| 289 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, | ||
| 316 | }; | 290 | }; |
| 317 | 291 | ||
| 318 | /* uartclk | 292 | /* uartclk |
| @@ -320,87 +294,30 @@ static struct clk clk_esysclk = { | |||
| 320 | * UART baud-rate clock sourced from esysclk via a divisor | 294 | * UART baud-rate clock sourced from esysclk via a divisor |
| 321 | */ | 295 | */ |
| 322 | 296 | ||
| 323 | static unsigned long s3c2443_getrate_uart(struct clk *clk) | 297 | static struct clksrc_clk clk_uart = { |
| 324 | { | 298 | .clk = { |
| 325 | unsigned long parent_rate = clk_get_rate(clk->parent); | 299 | .name = "uartclk", |
| 326 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 300 | .id = -1, |
| 327 | 301 | .parent = &clk_esysclk.clk, | |
| 328 | div &= S3C2443_CLKDIV1_UARTDIV_MASK; | ||
| 329 | div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
| 330 | |||
| 331 | return parent_rate / (div + 1); | ||
| 332 | } | ||
| 333 | |||
| 334 | |||
| 335 | static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) | ||
| 336 | { | ||
| 337 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 338 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 339 | |||
| 340 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
| 341 | rate = parent_rate / rate; | ||
| 342 | |||
| 343 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
| 344 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
| 345 | |||
| 346 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | static struct clk clk_uart = { | ||
| 351 | .name = "uartclk", | ||
| 352 | .id = -1, | ||
| 353 | .parent = &clk_esysclk, | ||
| 354 | .ops = &(struct clk_ops) { | ||
| 355 | .get_rate = s3c2443_getrate_uart, | ||
| 356 | .set_rate = s3c2443_setrate_uart, | ||
| 357 | .round_rate = s3c2443_roundrate_clksrc16, | ||
| 358 | }, | 302 | }, |
| 303 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, | ||
| 359 | }; | 304 | }; |
| 360 | 305 | ||
| 306 | |||
| 361 | /* hsspi | 307 | /* hsspi |
| 362 | * | 308 | * |
| 363 | * high-speed spi clock, sourced from esysclk | 309 | * high-speed spi clock, sourced from esysclk |
| 364 | */ | 310 | */ |
| 365 | 311 | ||
| 366 | static unsigned long s3c2443_getrate_hsspi(struct clk *clk) | 312 | static struct clksrc_clk clk_hsspi = { |
| 367 | { | 313 | .clk = { |
| 368 | unsigned long parent_rate = clk_get_rate(clk->parent); | 314 | .name = "hsspi", |
| 369 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 315 | .id = -1, |
| 370 | 316 | .parent = &clk_esysclk.clk, | |
| 371 | div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; | 317 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, |
| 372 | div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | 318 | .enable = s3c2443_clkcon_enable_s, |
| 373 | |||
| 374 | return parent_rate / (div + 1); | ||
| 375 | } | ||
| 376 | |||
| 377 | |||
| 378 | static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate) | ||
| 379 | { | ||
| 380 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 381 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 382 | |||
| 383 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
| 384 | rate = parent_rate / rate; | ||
| 385 | |||
| 386 | clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK; | ||
| 387 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | ||
| 388 | |||
| 389 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static struct clk clk_hsspi = { | ||
| 394 | .name = "hsspi", | ||
| 395 | .id = -1, | ||
| 396 | .parent = &clk_esysclk, | ||
| 397 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, | ||
| 398 | .enable = s3c2443_clkcon_enable_s, | ||
| 399 | .ops = &(struct clk_ops) { | ||
| 400 | .get_rate = s3c2443_getrate_hsspi, | ||
| 401 | .set_rate = s3c2443_setrate_hsspi, | ||
| 402 | .round_rate = s3c2443_roundrate_clksrc4, | ||
| 403 | }, | 319 | }, |
| 320 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, | ||
| 404 | }; | 321 | }; |
| 405 | 322 | ||
| 406 | /* usbhost | 323 | /* usbhost |
| @@ -408,43 +325,15 @@ static struct clk clk_hsspi = { | |||
| 408 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | 325 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing |
| 409 | */ | 326 | */ |
| 410 | 327 | ||
| 411 | static unsigned long s3c2443_getrate_usbhost(struct clk *clk) | 328 | static struct clksrc_clk clk_usb_bus_host = { |
| 412 | { | 329 | .clk = { |
| 413 | unsigned long parent_rate = clk_get_rate(clk->parent); | 330 | .name = "usb-bus-host-parent", |
| 414 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 331 | .id = -1, |
| 415 | 332 | .parent = &clk_esysclk.clk, | |
| 416 | div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; | 333 | .ctrlbit = S3C2443_SCLKCON_USBHOST, |
| 417 | div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | 334 | .enable = s3c2443_clkcon_enable_s, |
| 418 | |||
| 419 | return parent_rate / (div + 1); | ||
| 420 | } | ||
| 421 | |||
| 422 | static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) | ||
| 423 | { | ||
| 424 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 425 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 426 | |||
| 427 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
| 428 | rate = parent_rate / rate; | ||
| 429 | |||
| 430 | clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK; | ||
| 431 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | ||
| 432 | |||
| 433 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | static struct clk clk_usb_bus_host = { | ||
| 438 | .name = "usb-bus-host-parent", | ||
| 439 | .id = -1, | ||
| 440 | .parent = &clk_esysclk, | ||
| 441 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | ||
| 442 | .enable = s3c2443_clkcon_enable_s, | ||
| 443 | .ops = &(struct clk_ops) { | ||
| 444 | .get_rate = s3c2443_getrate_usbhost, | ||
| 445 | .set_rate = s3c2443_setrate_usbhost, | ||
| 446 | .round_rate = s3c2443_roundrate_clksrc4, | ||
| 447 | }, | 335 | }, |
| 336 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, | ||
| 448 | }; | 337 | }; |
| 449 | 338 | ||
| 450 | /* clk_hsmcc_div | 339 | /* clk_hsmcc_div |
| @@ -454,41 +343,13 @@ static struct clk clk_usb_bus_host = { | |||
| 454 | * be fed to the hsmmc block | 343 | * be fed to the hsmmc block |
| 455 | */ | 344 | */ |
| 456 | 345 | ||
| 457 | static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) | 346 | static struct clksrc_clk clk_hsmmc_div = { |
| 458 | { | 347 | .clk = { |
| 459 | unsigned long parent_rate = clk_get_rate(clk->parent); | 348 | .name = "hsmmc-div", |
| 460 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 349 | .id = -1, |
| 461 | 350 | .parent = &clk_esysclk.clk, | |
| 462 | div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
| 463 | div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
| 464 | |||
| 465 | return parent_rate / (div + 1); | ||
| 466 | } | ||
| 467 | |||
| 468 | static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate) | ||
| 469 | { | ||
| 470 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 471 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 472 | |||
| 473 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
| 474 | rate = parent_rate / rate; | ||
| 475 | |||
| 476 | clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
| 477 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
| 478 | |||
| 479 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 480 | return 0; | ||
| 481 | } | ||
| 482 | |||
| 483 | static struct clk clk_hsmmc_div = { | ||
| 484 | .name = "hsmmc-div", | ||
| 485 | .id = -1, | ||
| 486 | .parent = &clk_esysclk, | ||
| 487 | .ops = &(struct clk_ops) { | ||
| 488 | .get_rate = s3c2443_getrate_hsmmc_div, | ||
| 489 | .set_rate = s3c2443_setrate_hsmmc_div, | ||
| 490 | .round_rate = s3c2443_roundrate_clksrc4, | ||
| 491 | }, | 351 | }, |
| 352 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, | ||
| 492 | }; | 353 | }; |
| 493 | 354 | ||
| 494 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) | 355 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) |
| @@ -521,7 +382,7 @@ static int s3c2443_enable_hsmmc(struct clk *clk, int enable) | |||
| 521 | static struct clk clk_hsmmc = { | 382 | static struct clk clk_hsmmc = { |
| 522 | .name = "hsmmc-if", | 383 | .name = "hsmmc-if", |
| 523 | .id = -1, | 384 | .id = -1, |
| 524 | .parent = &clk_hsmmc_div, | 385 | .parent = &clk_hsmmc_div.clk, |
| 525 | .enable = s3c2443_enable_hsmmc, | 386 | .enable = s3c2443_enable_hsmmc, |
| 526 | .ops = &(struct clk_ops) { | 387 | .ops = &(struct clk_ops) { |
| 527 | .set_parent = s3c2443_setparent_hsmmc, | 388 | .set_parent = s3c2443_setparent_hsmmc, |
| @@ -530,79 +391,46 @@ static struct clk clk_hsmmc = { | |||
| 530 | 391 | ||
| 531 | /* i2s_eplldiv | 392 | /* i2s_eplldiv |
| 532 | * | 393 | * |
| 533 | * this clock is the output from the i2s divisor of esysclk | 394 | * This clock is the output from the I2S divisor of ESYSCLK, and is seperate |
| 395 | * from the mux that comes after it (cannot merge into one single clock) | ||
| 534 | */ | 396 | */ |
| 535 | 397 | ||
| 536 | static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) | 398 | static struct clksrc_clk clk_i2s_eplldiv = { |
| 537 | { | 399 | .clk = { |
| 538 | unsigned long parent_rate = clk_get_rate(clk->parent); | 400 | .name = "i2s-eplldiv", |
| 539 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 401 | .id = -1, |
| 540 | 402 | .parent = &clk_esysclk.clk, | |
| 541 | div &= S3C2443_CLKDIV1_I2SDIV_MASK; | ||
| 542 | div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
| 543 | |||
| 544 | return parent_rate / (div + 1); | ||
| 545 | } | ||
| 546 | |||
| 547 | static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate) | ||
| 548 | { | ||
| 549 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 550 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 551 | |||
| 552 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
| 553 | rate = parent_rate / rate; | ||
| 554 | |||
| 555 | clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK; | ||
| 556 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
| 557 | |||
| 558 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 559 | return 0; | ||
| 560 | } | ||
| 561 | |||
| 562 | static struct clk clk_i2s_eplldiv = { | ||
| 563 | .name = "i2s-eplldiv", | ||
| 564 | .id = -1, | ||
| 565 | .parent = &clk_esysclk, | ||
| 566 | .ops = &(struct clk_ops) { | ||
| 567 | .get_rate = s3c2443_getrate_i2s_eplldiv, | ||
| 568 | .set_rate = s3c2443_setrate_i2s_eplldiv, | ||
| 569 | .round_rate = s3c2443_roundrate_clksrc16, | ||
| 570 | }, | 403 | }, |
| 404 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, | ||
| 571 | }; | 405 | }; |
| 572 | 406 | ||
| 573 | /* i2s-ref | 407 | /* i2s-ref |
| 574 | * | 408 | * |
| 575 | * i2s bus reference clock, selectable from external, esysclk or epllref | 409 | * i2s bus reference clock, selectable from external, esysclk or epllref |
| 410 | * | ||
| 411 | * Note, this used to be two clocks, but was compressed into one. | ||
| 576 | */ | 412 | */ |
| 577 | 413 | ||
| 578 | static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) | 414 | struct clk *clk_i2s_srclist[] = { |
| 579 | { | 415 | [0] = &clk_i2s_eplldiv.clk, |
| 580 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 416 | [1] = &clk_i2s_ext, |
| 581 | 417 | [2] = &clk_epllref.clk, | |
| 582 | clksrc &= ~S3C2443_CLKSRC_I2S_MASK; | 418 | [3] = &clk_epllref.clk, |
| 583 | 419 | }; | |
| 584 | if (parent == &clk_epllref) | ||
| 585 | clksrc |= S3C2443_CLKSRC_I2S_EPLLREF; | ||
| 586 | else if (parent == &clk_i2s_ext) | ||
| 587 | clksrc |= S3C2443_CLKSRC_I2S_EXT; | ||
| 588 | else if (parent != &clk_i2s_eplldiv) | ||
| 589 | return -EINVAL; | ||
| 590 | |||
| 591 | clk->parent = parent; | ||
| 592 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
| 593 | 420 | ||
| 594 | return 0; | 421 | static struct clksrc_clk clk_i2s = { |
| 595 | } | 422 | .clk = { |
| 423 | .name = "i2s-if", | ||
| 424 | .id = -1, | ||
| 425 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | ||
| 426 | .enable = s3c2443_clkcon_enable_s, | ||
| 596 | 427 | ||
| 597 | static struct clk clk_i2s = { | ||
| 598 | .name = "i2s-if", | ||
| 599 | .id = -1, | ||
| 600 | .parent = &clk_i2s_eplldiv, | ||
| 601 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | ||
| 602 | .enable = s3c2443_clkcon_enable_s, | ||
| 603 | .ops = &(struct clk_ops) { | ||
| 604 | .set_parent = s3c2443_setparent_i2s, | ||
| 605 | }, | 428 | }, |
| 429 | .sources = &(struct clksrc_sources) { | ||
| 430 | .sources = clk_i2s_srclist, | ||
| 431 | .nr_sources = ARRAY_SIZE(clk_i2s_srclist), | ||
| 432 | }, | ||
| 433 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, | ||
| 606 | }; | 434 | }; |
| 607 | 435 | ||
| 608 | /* cam-if | 436 | /* cam-if |
| @@ -610,43 +438,15 @@ static struct clk clk_i2s = { | |||
| 610 | * camera interface bus-clock, divided down from esysclk | 438 | * camera interface bus-clock, divided down from esysclk |
| 611 | */ | 439 | */ |
| 612 | 440 | ||
| 613 | static unsigned long s3c2443_getrate_cam(struct clk *clk) | 441 | static struct clksrc_clk clk_cam = { |
| 614 | { | 442 | .clk = { |
| 615 | unsigned long parent_rate = clk_get_rate(clk->parent); | 443 | .name = "camif-upll", /* same as 2440 name */ |
| 616 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 444 | .id = -1, |
| 617 | 445 | .parent = &clk_esysclk.clk, | |
| 618 | div &= S3C2443_CLKDIV1_CAMDIV_MASK; | 446 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, |
| 619 | div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; | 447 | .enable = s3c2443_clkcon_enable_s, |
| 620 | |||
| 621 | return parent_rate / (div + 1); | ||
| 622 | } | ||
| 623 | |||
| 624 | static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate) | ||
| 625 | { | ||
| 626 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 627 | unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1); | ||
| 628 | |||
| 629 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
| 630 | rate = parent_rate / rate; | ||
| 631 | |||
| 632 | clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK; | ||
| 633 | clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT; | ||
| 634 | |||
| 635 | __raw_writel(clkdiv1, S3C2443_CLKDIV1); | ||
| 636 | return 0; | ||
| 637 | } | ||
| 638 | |||
| 639 | static struct clk clk_cam = { | ||
| 640 | .name = "camif-upll", /* same as 2440 name */ | ||
| 641 | .id = -1, | ||
| 642 | .parent = &clk_esysclk, | ||
| 643 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | ||
| 644 | .enable = s3c2443_clkcon_enable_s, | ||
| 645 | .ops = &(struct clk_ops) { | ||
| 646 | .get_rate = s3c2443_getrate_cam, | ||
| 647 | .set_rate = s3c2443_setrate_cam, | ||
| 648 | .round_rate = s3c2443_roundrate_clksrc16, | ||
| 649 | }, | 448 | }, |
| 449 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, | ||
| 650 | }; | 450 | }; |
| 651 | 451 | ||
| 652 | /* display-if | 452 | /* display-if |
| @@ -654,43 +454,15 @@ static struct clk clk_cam = { | |||
| 654 | * display interface clock, divided from esysclk | 454 | * display interface clock, divided from esysclk |
| 655 | */ | 455 | */ |
| 656 | 456 | ||
| 657 | static unsigned long s3c2443_getrate_display(struct clk *clk) | 457 | static struct clksrc_clk clk_display = { |
| 658 | { | 458 | .clk = { |
| 659 | unsigned long parent_rate = clk_get_rate(clk->parent); | 459 | .name = "display-if", |
| 660 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 460 | .id = -1, |
| 661 | 461 | .parent = &clk_esysclk.clk, | |
| 662 | div &= S3C2443_CLKDIV1_DISPDIV_MASK; | 462 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, |
| 663 | div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; | 463 | .enable = s3c2443_clkcon_enable_s, |
| 664 | |||
| 665 | return parent_rate / (div + 1); | ||
| 666 | } | ||
| 667 | |||
| 668 | static int s3c2443_setrate_display(struct clk *clk, unsigned long rate) | ||
| 669 | { | ||
| 670 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
| 671 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
| 672 | |||
| 673 | rate = s3c2443_roundrate_clksrc256(clk, rate); | ||
| 674 | rate = parent_rate / rate; | ||
| 675 | |||
| 676 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
| 677 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
| 678 | |||
| 679 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 683 | static struct clk clk_display = { | ||
| 684 | .name = "display-if", | ||
| 685 | .id = -1, | ||
| 686 | .parent = &clk_esysclk, | ||
| 687 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | ||
| 688 | .enable = s3c2443_clkcon_enable_s, | ||
| 689 | .ops = &(struct clk_ops) { | ||
| 690 | .get_rate = s3c2443_getrate_display, | ||
| 691 | .set_rate = s3c2443_setrate_display, | ||
| 692 | .round_rate = s3c2443_roundrate_clksrc256, | ||
| 693 | }, | 464 | }, |
| 465 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, | ||
| 694 | }; | 466 | }; |
| 695 | 467 | ||
| 696 | /* prediv | 468 | /* prediv |
| @@ -712,7 +484,7 @@ static unsigned long s3c2443_prediv_getrate(struct clk *clk) | |||
| 712 | static struct clk clk_prediv = { | 484 | static struct clk clk_prediv = { |
| 713 | .name = "prediv", | 485 | .name = "prediv", |
| 714 | .id = -1, | 486 | .id = -1, |
| 715 | .parent = &clk_msysclk, | 487 | .parent = &clk_msysclk.clk, |
| 716 | .ops = &(struct clk_ops) { | 488 | .ops = &(struct clk_ops) { |
| 717 | .get_rate = s3c2443_prediv_getrate, | 489 | .get_rate = s3c2443_prediv_getrate, |
| 718 | }, | 490 | }, |
| @@ -887,7 +659,7 @@ static struct clk init_clocks[] = { | |||
| 887 | }, { | 659 | }, { |
| 888 | .name = "usb-bus-host", | 660 | .name = "usb-bus-host", |
| 889 | .id = -1, | 661 | .id = -1, |
| 890 | .parent = &clk_usb_bus_host, | 662 | .parent = &clk_usb_bus_host.clk, |
| 891 | }, { | 663 | }, { |
| 892 | .name = "ac97", | 664 | .name = "ac97", |
| 893 | .id = -1, | 665 | .id = -1, |
| @@ -898,103 +670,26 @@ static struct clk init_clocks[] = { | |||
| 898 | 670 | ||
| 899 | /* clocks to add where we need to check their parentage */ | 671 | /* clocks to add where we need to check their parentage */ |
| 900 | 672 | ||
| 901 | /* s3c2443_clk_initparents | 673 | static struct clksrc_clk __initdata *init_list[] = { |
| 902 | * | 674 | &clk_epllref, /* should be first */ |
| 903 | * Initialise the parents for the clocks that we get at start-time | 675 | &clk_esysclk, |
| 904 | */ | 676 | &clk_msysclk, |
| 905 | 677 | &clk_arm, | |
| 906 | static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) | 678 | &clk_i2s_eplldiv, |
| 907 | { | 679 | &clk_i2s, |
| 908 | printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); | 680 | &clk_cam, |
| 909 | return clk_set_parent(clk, parent); | 681 | &clk_uart, |
| 910 | } | 682 | &clk_display, |
| 911 | 683 | &clk_hsmmc_div, | |
| 912 | static void __init s3c2443_clk_initparents(void) | 684 | &clk_usb_bus_host, |
| 913 | { | ||
| 914 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | ||
| 915 | struct clk *parent; | ||
| 916 | |||
| 917 | switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) { | ||
| 918 | case S3C2443_CLKSRC_EPLLREF_EXTCLK: | ||
| 919 | parent = &clk_ext; | ||
| 920 | break; | ||
| 921 | |||
| 922 | case S3C2443_CLKSRC_EPLLREF_XTAL: | ||
| 923 | default: | ||
| 924 | parent = &clk_xtal; | ||
| 925 | break; | ||
| 926 | |||
| 927 | case S3C2443_CLKSRC_EPLLREF_MPLLREF: | ||
| 928 | case S3C2443_CLKSRC_EPLLREF_MPLLREF2: | ||
| 929 | parent = &clk_mpllref; | ||
| 930 | break; | ||
| 931 | } | ||
| 932 | |||
| 933 | clk_init_set_parent(&clk_epllref, parent); | ||
| 934 | |||
| 935 | switch (clksrc & S3C2443_CLKSRC_I2S_MASK) { | ||
| 936 | case S3C2443_CLKSRC_I2S_EXT: | ||
| 937 | parent = &clk_i2s_ext; | ||
| 938 | break; | ||
| 939 | |||
| 940 | case S3C2443_CLKSRC_I2S_EPLLDIV: | ||
| 941 | default: | ||
| 942 | parent = &clk_i2s_eplldiv; | ||
| 943 | break; | ||
| 944 | |||
| 945 | case S3C2443_CLKSRC_I2S_EPLLREF: | ||
| 946 | case S3C2443_CLKSRC_I2S_EPLLREF3: | ||
| 947 | parent = &clk_epllref; | ||
| 948 | } | ||
| 949 | |||
| 950 | clk_init_set_parent(&clk_i2s, &clk_epllref); | ||
| 951 | |||
| 952 | /* esysclk source */ | ||
| 953 | |||
| 954 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? | ||
| 955 | &clk_epll : &clk_epllref; | ||
| 956 | |||
| 957 | clk_init_set_parent(&clk_esysclk, parent); | ||
| 958 | |||
| 959 | /* msysclk source */ | ||
| 960 | |||
| 961 | if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) { | ||
| 962 | parent = &clk_mpll; | ||
| 963 | } else { | ||
| 964 | parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ? | ||
| 965 | &clk_mdivclk : &clk_mpllref; | ||
| 966 | } | ||
| 967 | |||
| 968 | clk_init_set_parent(&clk_msysclk, parent); | ||
| 969 | |||
| 970 | /* arm */ | ||
| 971 | |||
| 972 | if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS) | ||
| 973 | parent = &clk_h; | ||
| 974 | else | ||
| 975 | parent = &clk_armdiv; | ||
| 976 | |||
| 977 | clk_init_set_parent(&clk_arm, parent); | ||
| 978 | } | ||
| 979 | |||
| 980 | /* armdiv divisor table */ | ||
| 981 | |||
| 982 | static unsigned int armdiv[16] = { | ||
| 983 | [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, | ||
| 984 | [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, | ||
| 985 | [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, | ||
| 986 | [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, | ||
| 987 | [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, | ||
| 988 | [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, | ||
| 989 | [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, | ||
| 990 | [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, | ||
| 991 | }; | 685 | }; |
| 992 | 686 | ||
| 993 | static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) | 687 | static void __init s3c2443_clk_initparents(void) |
| 994 | { | 688 | { |
| 995 | clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; | 689 | int ptr; |
| 996 | 690 | ||
| 997 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; | 691 | for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++) |
| 692 | s3c_set_clksrc(init_list[ptr], true); | ||
| 998 | } | 693 | } |
| 999 | 694 | ||
| 1000 | static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) | 695 | static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) |
| @@ -1006,15 +701,12 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) | |||
| 1006 | 701 | ||
| 1007 | /* clocks to add straight away */ | 702 | /* clocks to add straight away */ |
| 1008 | 703 | ||
| 1009 | static struct clk *clks[] __initdata = { | 704 | static struct clksrc_clk *clksrcs[] __initdata = { |
| 1010 | &clk_ext, | ||
| 1011 | &clk_epll, | ||
| 1012 | &clk_usb_bus_host, | 705 | &clk_usb_bus_host, |
| 1013 | &clk_usb_bus, | ||
| 1014 | &clk_esysclk, | ||
| 1015 | &clk_epllref, | 706 | &clk_epllref, |
| 1016 | &clk_mpllref, | 707 | &clk_esysclk, |
| 1017 | &clk_msysclk, | 708 | &clk_msysclk, |
| 709 | &clk_arm, | ||
| 1018 | &clk_uart, | 710 | &clk_uart, |
| 1019 | &clk_display, | 711 | &clk_display, |
| 1020 | &clk_cam, | 712 | &clk_cam, |
| @@ -1022,9 +714,15 @@ static struct clk *clks[] __initdata = { | |||
| 1022 | &clk_i2s, | 714 | &clk_i2s, |
| 1023 | &clk_hsspi, | 715 | &clk_hsspi, |
| 1024 | &clk_hsmmc_div, | 716 | &clk_hsmmc_div, |
| 717 | }; | ||
| 718 | |||
| 719 | static struct clk *clks[] __initdata = { | ||
| 720 | &clk_ext, | ||
| 721 | &clk_epll, | ||
| 722 | &clk_usb_bus, | ||
| 723 | &clk_mpllref, | ||
| 1025 | &clk_hsmmc, | 724 | &clk_hsmmc, |
| 1026 | &clk_armdiv, | 725 | &clk_armdiv, |
| 1027 | &clk_arm, | ||
| 1028 | &clk_prediv, | 726 | &clk_prediv, |
| 1029 | }; | 727 | }; |
| 1030 | 728 | ||
| @@ -1044,7 +742,7 @@ void __init_or_cpufreq s3c2443_setup_clocks(void) | |||
| 1044 | clk_put(xtal_clk); | 742 | clk_put(xtal_clk); |
| 1045 | 743 | ||
| 1046 | pll = s3c2443_get_mpll(mpllcon, xtal); | 744 | pll = s3c2443_get_mpll(mpllcon, xtal); |
| 1047 | clk_msysclk.rate = pll; | 745 | clk_msysclk.clk.rate = pll; |
| 1048 | 746 | ||
| 1049 | fclk = pll / s3c2443_fclk_div(clkdiv0); | 747 | fclk = pll / s3c2443_fclk_div(clkdiv0); |
| 1050 | hclk = s3c2443_prediv_getrate(&clk_prediv); | 748 | hclk = s3c2443_prediv_getrate(&clk_prediv); |
| @@ -1086,15 +784,18 @@ void __init s3c2443_init_clocks(int xtal) | |||
| 1086 | } | 784 | } |
| 1087 | } | 785 | } |
| 1088 | 786 | ||
| 787 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) | ||
| 788 | s3c_register_clksrc(clksrcs[ptr], 1); | ||
| 789 | |||
| 1089 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); | 790 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); |
| 1090 | clk_epll.parent = &clk_epllref; | 791 | clk_epll.parent = &clk_epllref.clk; |
| 1091 | clk_usb_bus.parent = &clk_usb_bus_host; | 792 | clk_usb_bus.parent = &clk_usb_bus_host.clk; |
| 1092 | 793 | ||
| 1093 | /* ensure usb bus clock is within correct rate of 48MHz */ | 794 | /* ensure usb bus clock is within correct rate of 48MHz */ |
| 1094 | 795 | ||
| 1095 | if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { | 796 | if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { |
| 1096 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); | 797 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); |
| 1097 | clk_set_rate(&clk_usb_bus_host, 48*1000*1000); | 798 | clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); |
| 1098 | } | 799 | } |
| 1099 | 800 | ||
| 1100 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", | 801 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", |
