aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2010-07-21 06:13:14 -0400
committerPaul Mundt <lethal@linux-sh.org>2010-08-04 03:12:06 -0400
commitb90884c886696a67a4c7832b4e627f341a860b3d (patch)
treebadcea9298541009150fff8abc278980b542ae4c /arch/arm/mach-shmobile
parentb3dd51a8a6ce2e618e8a1be8fa0e7d3d4733c300 (diff)
ARM: mach-shmobile: extend clock definitions on sh7372
Add definitions for DV_CLKI and HDMI clocks, extend support for PLLC2 and some other clocks. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Acked-by: Magnus Damm <damm@opensource.se> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c171
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h6
2 files changed, 172 insertions, 5 deletions
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 26521a737735..a653d12a11a7 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -50,6 +50,10 @@
50#define SMSTPCR3 0xe615013c 50#define SMSTPCR3 0xe615013c
51#define SMSTPCR4 0xe6150140 51#define SMSTPCR4 0xe6150140
52 52
53/* Platforms must set frequency on their DV_CLKI pin */
54struct clk dv_clki_clk = {
55};
56
53/* Fixed 32 KHz root clock from EXTALR pin */ 57/* Fixed 32 KHz root clock from EXTALR pin */
54static struct clk r_clk = { 58static struct clk r_clk = {
55 .rate = 32768, 59 .rate = 32768,
@@ -81,6 +85,12 @@ static struct clk_ops div2_clk_ops = {
81 .recalc = div2_recalc, 85 .recalc = div2_recalc,
82}; 86};
83 87
88/* Divide dv_clki by two */
89struct clk dv_clki_div2_clk = {
90 .ops = &div2_clk_ops,
91 .parent = &dv_clki_clk,
92};
93
84/* Divide extal1 by two */ 94/* Divide extal1 by two */
85static struct clk extal1_div2_clk = { 95static struct clk extal1_div2_clk = {
86 .ops = &div2_clk_ops, 96 .ops = &div2_clk_ops,
@@ -135,30 +145,160 @@ static struct clk pllc1_div2_clk = {
135}; 145};
136 146
137/* PLLC2 */ 147/* PLLC2 */
148
149/* Indices are important - they are the actual src selecting values */
150static struct clk *pllc2_parent[] = {
151 [0] = &extal1_div2_clk,
152 [1] = &extal2_div2_clk,
153 [2] = &dv_clki_div2_clk,
154};
155
156/* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */
157static struct cpufreq_frequency_table pllc2_freq_table[29];
158
159static void pllc2_table_rebuild(struct clk *clk)
160{
161 int i;
162
163 /* Initialise PLLC2 frequency table */
164 for (i = 0; i < ARRAY_SIZE(pllc2_freq_table) - 2; i++) {
165 pllc2_freq_table[i].frequency = clk->parent->rate * (i + 20) * 2;
166 pllc2_freq_table[i].index = i;
167 }
168
169 /* This is a special entry - switching PLL off makes it a repeater */
170 pllc2_freq_table[i].frequency = clk->parent->rate;
171 pllc2_freq_table[i].index = i;
172
173 pllc2_freq_table[++i].frequency = CPUFREQ_TABLE_END;
174 pllc2_freq_table[i].index = i;
175}
176
138static unsigned long pllc2_recalc(struct clk *clk) 177static unsigned long pllc2_recalc(struct clk *clk)
139{ 178{
140 unsigned long mult = 1; 179 unsigned long mult = 1;
141 180
181 pllc2_table_rebuild(clk);
182
183 /*
184 * If the PLL is off, mult == 1, clk->rate will be updated in
185 * pllc2_enable().
186 */
142 if (__raw_readl(PLLC2CR) & (1 << 31)) 187 if (__raw_readl(PLLC2CR) & (1 << 31))
143 mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2; 188 mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
144 189
145 return clk->parent->rate * mult; 190 return clk->parent->rate * mult;
146} 191}
147 192
193static long pllc2_round_rate(struct clk *clk, unsigned long rate)
194{
195 return clk_rate_table_round(clk, clk->freq_table, rate);
196}
197
198static int pllc2_enable(struct clk *clk)
199{
200 int i;
201
202 __raw_writel(__raw_readl(PLLC2CR) | 0x80000000, PLLC2CR);
203
204 for (i = 0; i < 100; i++)
205 if (__raw_readl(PLLC2CR) & 0x80000000) {
206 clk->rate = pllc2_recalc(clk);
207 return 0;
208 }
209
210 pr_err("%s(): timeout!\n", __func__);
211
212 return -ETIMEDOUT;
213}
214
215static void pllc2_disable(struct clk *clk)
216{
217 __raw_writel(__raw_readl(PLLC2CR) & ~0x80000000, PLLC2CR);
218}
219
220static int pllc2_set_rate(struct clk *clk,
221 unsigned long rate, int algo_id)
222{
223 unsigned long value;
224 int idx;
225
226 idx = clk_rate_table_find(clk, clk->freq_table, rate);
227 if (idx < 0)
228 return idx;
229
230 if (rate == clk->parent->rate) {
231 pllc2_disable(clk);
232 return 0;
233 }
234
235 value = __raw_readl(PLLC2CR) & ~(0x3f << 24);
236
237 if (value & 0x80000000)
238 pllc2_disable(clk);
239
240 __raw_writel((value & ~0x80000000) | ((idx + 19) << 24), PLLC2CR);
241
242 if (value & 0x80000000)
243 return pllc2_enable(clk);
244
245 return 0;
246}
247
248static int pllc2_set_parent(struct clk *clk, struct clk *parent)
249{
250 u32 value;
251 int ret, i;
252
253 if (!clk->parent_table || !clk->parent_num)
254 return -EINVAL;
255
256 /* Search the parent */
257 for (i = 0; i < clk->parent_num; i++)
258 if (clk->parent_table[i] == parent)
259 break;
260
261 if (i == clk->parent_num)
262 return -ENODEV;
263
264 ret = clk_reparent(clk, parent);
265 if (ret < 0)
266 return ret;
267
268 value = __raw_readl(PLLC2CR) & ~(3 << 6);
269
270 __raw_writel(value | (i << 6), PLLC2CR);
271
272 /* Rebiuld the frequency table */
273 pllc2_table_rebuild(clk);
274
275 return 0;
276}
277
148static struct clk_ops pllc2_clk_ops = { 278static struct clk_ops pllc2_clk_ops = {
149 .recalc = pllc2_recalc, 279 .recalc = pllc2_recalc,
280 .round_rate = pllc2_round_rate,
281 .set_rate = pllc2_set_rate,
282 .enable = pllc2_enable,
283 .disable = pllc2_disable,
284 .set_parent = pllc2_set_parent,
150}; 285};
151 286
152static struct clk pllc2_clk = { 287struct clk pllc2_clk = {
153 .ops = &pllc2_clk_ops, 288 .ops = &pllc2_clk_ops,
154 .flags = CLK_ENABLE_ON_INIT, 289 .flags = CLK_ENABLE_ON_INIT,
155 .parent = &extal1_div2_clk, 290 .parent = &extal1_div2_clk,
291 .freq_table = pllc2_freq_table,
292 .parent_table = pllc2_parent,
293 .parent_num = ARRAY_SIZE(pllc2_parent),
156}; 294};
157 295
158static struct clk *main_clks[] = { 296static struct clk *main_clks[] = {
297 &dv_clki_clk,
159 &r_clk, 298 &r_clk,
160 &sh7372_extal1_clk, 299 &sh7372_extal1_clk,
161 &sh7372_extal2_clk, 300 &sh7372_extal2_clk,
301 &dv_clki_div2_clk,
162 &extal1_div2_clk, 302 &extal1_div2_clk,
163 &extal2_div2_clk, 303 &extal2_div2_clk,
164 &extal2_div4_clk, 304 &extal2_div4_clk,
@@ -219,7 +359,7 @@ static struct clk div4_clks[DIV4_NR] = {
219 359
220enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, 360enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
221 DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU, 361 DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
222 DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, 362 DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
223 DIV6_NR }; 363 DIV6_NR };
224 364
225static struct clk div6_clks[DIV6_NR] = { 365static struct clk div6_clks[DIV6_NR] = {
@@ -233,12 +373,26 @@ static struct clk div6_clks[DIV6_NR] = {
233 [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), 373 [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0),
234 [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), 374 [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
235 [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), 375 [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
236 [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
237 [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0), 376 [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
238 [DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0), 377 [DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0),
239 [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), 378 [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
240}; 379};
241 380
381enum { DIV6_HDMI, DIV6_REPARENT_NR };
382
383/* Indices are important - they are the actual src selecting values */
384static struct clk *hdmi_parent[] = {
385 [0] = &pllc1_div2_clk,
386 [1] = &pllc2_clk,
387 [2] = &dv_clki_clk,
388 [3] = NULL, /* pllc2_div4 not implemented yet */
389};
390
391static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = {
392 [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0,
393 hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2),
394};
395
242enum { MSTP001, 396enum { MSTP001,
243 MSTP131, MSTP130, 397 MSTP131, MSTP130,
244 MSTP129, MSTP128, 398 MSTP129, MSTP128,
@@ -247,7 +401,7 @@ enum { MSTP001,
247 MSTP223, 401 MSTP223,
248 MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200, 402 MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
249 MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312, 403 MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
250 MSTP415, MSTP410, MSTP411, MSTP406, MSTP403, 404 MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
251 MSTP_NR }; 405 MSTP_NR };
252 406
253#define MSTP(_parent, _reg, _bit, _flags) \ 407#define MSTP(_parent, _reg, _bit, _flags) \
@@ -281,6 +435,7 @@ static struct clk mstp_clks[MSTP_NR] = {
281 [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */ 435 [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
282 [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */ 436 [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
283 [MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */ 437 [MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
438 [MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */
284 [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */ 439 [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
285 [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */ 440 [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
286 [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */ 441 [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
@@ -292,6 +447,7 @@ static struct clk mstp_clks[MSTP_NR] = {
292 447
293static struct clk_lookup lookups[] = { 448static struct clk_lookup lookups[] = {
294 /* main clocks */ 449 /* main clocks */
450 CLKDEV_CON_ID("dv_clki_div2_clk", &dv_clki_div2_clk),
295 CLKDEV_CON_ID("r_clk", &r_clk), 451 CLKDEV_CON_ID("r_clk", &r_clk),
296 CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), 452 CLKDEV_CON_ID("extal1", &sh7372_extal1_clk),
297 CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), 453 CLKDEV_CON_ID("extal2", &sh7372_extal2_clk),
@@ -331,7 +487,7 @@ static struct clk_lookup lookups[] = {
331 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), 487 CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
332 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), 488 CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
333 CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), 489 CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
334 CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]), 490 CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]),
335 CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]), 491 CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
336 CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]), 492 CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
337 CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]), 493 CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),
@@ -366,11 +522,13 @@ static struct clk_lookup lookups[] = {
366 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */ 522 CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
367 CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */ 523 CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
368 CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */ 524 CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
525 CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
369 CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */ 526 CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
370 CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */ 527 CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
371 CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ 528 CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
372 CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ 529 CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
373 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ 530 CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
531 {.con_id = "ick", .dev_id = "sh-mobile-hdmi", .clk = &div6_reparent_clks[DIV6_HDMI]},
374}; 532};
375 533
376void __init sh7372_clock_init(void) 534void __init sh7372_clock_init(void)
@@ -387,6 +545,9 @@ void __init sh7372_clock_init(void)
387 ret = sh_clk_div6_register(div6_clks, DIV6_NR); 545 ret = sh_clk_div6_register(div6_clks, DIV6_NR);
388 546
389 if (!ret) 547 if (!ret)
548 ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_NR);
549
550 if (!ret)
390 ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); 551 ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
391 552
392 clkdev_add_table(lookups, ARRAY_SIZE(lookups)); 553 clkdev_add_table(lookups, ARRAY_SIZE(lookups));
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index c2d2d811059c..33e9700ded7e 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -11,6 +11,8 @@
11#ifndef __ASM_SH7372_H__ 11#ifndef __ASM_SH7372_H__
12#define __ASM_SH7372_H__ 12#define __ASM_SH7372_H__
13 13
14#include <linux/sh_clk.h>
15
14/* 16/*
15 * Pin Function Controller: 17 * Pin Function Controller:
16 * GPIO_FN_xx - GPIO used to select pin function 18 * GPIO_FN_xx - GPIO used to select pin function
@@ -455,4 +457,8 @@ enum {
455 SHDMA_SLAVE_SDHI2_TX, 457 SHDMA_SLAVE_SDHI2_TX,
456}; 458};
457 459
460extern struct clk dv_clki_clk;
461extern struct clk dv_clki_div2_clk;
462extern struct clk pllc2_clk;
463
458#endif /* __ASM_SH7372_H__ */ 464#endif /* __ASM_SH7372_H__ */