Blame view

arch/arm/mach-s3c2443/clock.c 5.83 KB
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
1
2
  /* linux/arch/arm/mach-s3c2443/clock.c
   *
4bed36b2c   Ben Dooks   ARM: S3C2443: Fur...
3
   * Copyright (c) 2007, 2010 Simtec Electronics
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
   *	Ben Dooks <ben@simtec.co.uk>
   *
   * S3C2443 Clock control support
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  
  #include <linux/init.h>
af337f3e6   Ben Dooks   ARM: S3C2443: Mov...
24

e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
25
26
27
28
29
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/list.h>
  #include <linux/errno.h>
  #include <linux/err.h>
edbaa603e   Kay Sievers   driver-core: remo...
30
  #include <linux/device.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
31
32
  #include <linux/clk.h>
  #include <linux/mutex.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
33
  #include <linux/serial_core.h>
fced80c73   Russell King   [ARM] Convert asm...
34
  #include <linux/io.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
35
36
  
  #include <asm/mach/map.h>
a09e64fbc   Russell King   [ARM] Move includ...
37
  #include <mach/hardware.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
38

a09e64fbc   Russell King   [ARM] Move includ...
39
  #include <mach/regs-s3c2443-clock.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
40

e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
41
  #include <plat/cpu-freq.h>
a2b7ba9ca   Ben Dooks   [ARM] S3C24XX: Mo...
42
  #include <plat/s3c2443.h>
d5120ae72   Ben Dooks   [ARM] S3C24XX: Ad...
43
  #include <plat/clock.h>
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
44
  #include <plat/clock-clksrc.h>
a2b7ba9ca   Ben Dooks   [ARM] S3C24XX: Mo...
45
  #include <plat/cpu.h>
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
46
47
48
49
50
51
52
53
54
  
  /* We currently have to assume that the system is running
   * from the XTPll input, and that all ***REFCLKs are being
   * fed from it, as we cannot read the state of OM[4] from
   * software.
   *
   * It would be possible for each board initialisation to
   * set the correct muxing at initialisation
  */
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
55
  /* clock selections */
ba7622a19   Ben Dooks   [ARM] S3C2443: Ad...
56
57
58
59
  /* armdiv
   *
   * this clock is sourced from msysclk and can have a number of
   * divider values applied to it to then be fed into armclk.
aab08eebd   Heiko St?bner   ARM: S3C2443: Mov...
60
61
   * The real clock definition is done in s3c2443-clock.c,
   * only the armdiv divisor table must be defined here.
ba7622a19   Ben Dooks   [ARM] S3C2443: Ad...
62
  */
41f23a09f   Ben Dooks   ARM: S3C2443: Add...
63
64
65
66
67
68
69
70
71
72
  static unsigned int armdiv[16] = {
  	[S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 1,
  	[S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 2,
  	[S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 3,
  	[S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 4,
  	[S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 6,
  	[S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 8,
  	[S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 12,
  	[S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]	= 16,
  };
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
73
74
75
76
  /* hsspi
   *
   * high-speed spi clock, sourced from esysclk
  */
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
77
78
  static struct clksrc_clk clk_hsspi = {
  	.clk	= {
8b069b770   Heiko Stuebner   ARM: S3C2443: Add...
79
  		.name		= "hsspi-if",
4bed36b2c   Ben Dooks   ARM: S3C2443: Fur...
80
  		.parent		= &clk_esysclk.clk,
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
81
82
  		.ctrlbit	= S3C2443_SCLKCON_HSSPICLK,
  		.enable		= s3c2443_clkcon_enable_s,
b3bf41be0   Ben Dooks   ARM: SAMSUNG: Red...
83
  	},
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
84
  	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
85
  };
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
86
87
88
89
90
91
92
  
  /* clk_hsmcc_div
   *
   * this clock is sourced from epll, and is fed through a divider,
   * to a mux controlled by sclkcon where either it or a extclk can
   * be fed to the hsmmc block
  */
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
93
94
95
  static struct clksrc_clk clk_hsmmc_div = {
  	.clk	= {
  		.name		= "hsmmc-div",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
96
  		.devname	= "s3c-sdhci.1",
4bed36b2c   Ben Dooks   ARM: S3C2443: Fur...
97
  		.parent		= &clk_esysclk.clk,
b3bf41be0   Ben Dooks   ARM: SAMSUNG: Red...
98
  	},
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
99
  	.reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
  };
  
  static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
  {
  	unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
  
  	clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
  		    S3C2443_SCLKCON_HSMMCCLK_EPLL);
  
  	if (parent == &clk_epll)
  		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
  	else if (parent == &clk_ext)
  		clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
  	else
  		return -EINVAL;
  
  	if (clk->usage > 0) {
  		__raw_writel(clksrc, S3C2443_SCLKCON);
  	}
  
  	clk->parent = parent;
  	return 0;
  }
  
  static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
  {
  	return s3c2443_setparent_hsmmc(clk, clk->parent);
  }
  
  static struct clk clk_hsmmc = {
  	.name		= "hsmmc-if",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
131
  	.devname	= "s3c-sdhci.1",
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
132
  	.parent		= &clk_hsmmc_div.clk,
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
133
  	.enable		= s3c2443_enable_hsmmc,
b3bf41be0   Ben Dooks   ARM: SAMSUNG: Red...
134
135
136
  	.ops		= &(struct clk_ops) {
  		.set_parent	= s3c2443_setparent_hsmmc,
  	},
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
137
  };
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
138
  /* standard clock definitions */
4e04691bc   Ben Dooks   ARM: SAMSUNG: Add...
139
  static struct clk init_clocks_off[] = {
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
140
  	{
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
141
  		.name		= "sdi",
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
142
143
144
145
  		.parent		= &clk_p,
  		.enable		= s3c2443_clkcon_enable_p,
  		.ctrlbit	= S3C2443_PCLKCON_SDI,
  	}, {
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
146
  		.name		= "spi",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
147
  		.devname	= "s3c2410-spi.0",
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
148
149
150
151
152
  		.parent		= &clk_p,
  		.enable		= s3c2443_clkcon_enable_p,
  		.ctrlbit	= S3C2443_PCLKCON_SPI0,
  	}, {
  		.name		= "spi",
e83626f2f   Thomas Abraham   ARM: S3C24XX: Add...
153
  		.devname	= "s3c2410-spi.1",
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
154
155
156
157
158
  		.parent		= &clk_p,
  		.enable		= s3c2443_clkcon_enable_p,
  		.ctrlbit	= S3C2443_PCLKCON_SPI1,
  	}
  };
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
159
  /* clocks to add straight away */
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
160
  static struct clksrc_clk *clksrcs[] __initdata = {
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
161
162
  	&clk_hsspi,
  	&clk_hsmmc_div,
9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
163
164
165
  };
  
  static struct clk *clks[] __initdata = {
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
166
167
  	&clk_hsmmc,
  };
e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
168
  void __init_or_cpufreq s3c2443_setup_clocks(void)
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
169
  {
33ccedfd1   Heiko Stuebner   ARM: S3C24XX: use...
170
  	s3c2443_common_setup_clocks(s3c2443_get_mpll);
e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
171
172
173
174
  }
  
  void __init s3c2443_init_clocks(int xtal)
  {
e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
175
  	unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
176
  	int ptr;
af337f3e6   Ben Dooks   ARM: S3C2443: Mov...
177
178
  	clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
  	clk_epll.parent = &clk_epllref.clk;
33ccedfd1   Heiko Stuebner   ARM: S3C24XX: use...
179
  	s3c2443_common_init_clocks(xtal, s3c2443_get_mpll,
d9a3bfbd7   Heiko Stuebner   ARM: S3C24XX: Add...
180
181
  				   armdiv, ARRAY_SIZE(armdiv),
  				   S3C2443_CLKDIV0_ARMDIV_MASK);
e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
182

e425382ed   Ben Dooks   [ARM] S3C24XX: Up...
183
  	s3c2443_setup_clocks();
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
184

4e04691bc   Ben Dooks   ARM: SAMSUNG: Add...
185
  	s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
186

9aa753c44   Ben Dooks   ARM: S3C2443: Cha...
187
188
  	for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
  		s3c_register_clksrc(clksrcs[ptr], 1);
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
189
  	/* We must be careful disabling the clocks we are not intending to
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
190
  	 * be using at boot time, as subsystems such as the LCD which do
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
191
192
193
194
195
196
197
198
199
  	 * their own DMA requests to the bus can cause the system to lockup
  	 * if they where in the middle of requesting bus access.
  	 *
  	 * Disabling the LCD clock if the LCD is active is very dangerous,
  	 * and therefore the bootloader should be careful to not enable
  	 * the LCD clock if it is not needed.
  	*/
  
  	/* install (and disable) the clocks we do not need immediately */
4e04691bc   Ben Dooks   ARM: SAMSUNG: Add...
200
201
  	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
9d325f234   Ben Dooks   [ARM] S3C: Update...
202
203
  
  	s3c_pwmclk_init();
e4d06e395   Ben Dooks   [ARM] 4198/2: S3C...
204
  }