diff options
Diffstat (limited to 'arch/arm/mach-shmobile/clock-r8a7791.c')
-rw-r--r-- | arch/arm/mach-shmobile/clock-r8a7791.c | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c new file mode 100644 index 000000000000..c9a26f16ce5b --- /dev/null +++ b/arch/arm/mach-shmobile/clock-r8a7791.c | |||
@@ -0,0 +1,237 @@ | |||
1 | /* | ||
2 | * r8a7791 clock framework support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Electronics Corporation | ||
5 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
6 | * Copyright (C) 2013 Magnus Damm | ||
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; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
20 | */ | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/sh_clk.h> | ||
25 | #include <linux/clkdev.h> | ||
26 | #include <mach/clock.h> | ||
27 | #include <mach/common.h> | ||
28 | |||
29 | /* | ||
30 | * MD EXTAL PLL0 PLL1 PLL3 | ||
31 | * 14 13 19 (MHz) *1 *1 | ||
32 | *--------------------------------------------------- | ||
33 | * 0 0 0 15 x 1 x172/2 x208/2 x106 | ||
34 | * 0 0 1 15 x 1 x172/2 x208/2 x88 | ||
35 | * 0 1 0 20 x 1 x130/2 x156/2 x80 | ||
36 | * 0 1 1 20 x 1 x130/2 x156/2 x66 | ||
37 | * 1 0 0 26 / 2 x200/2 x240/2 x122 | ||
38 | * 1 0 1 26 / 2 x200/2 x240/2 x102 | ||
39 | * 1 1 0 30 / 2 x172/2 x208/2 x106 | ||
40 | * 1 1 1 30 / 2 x172/2 x208/2 x88 | ||
41 | * | ||
42 | * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) | ||
43 | * see "p1 / 2" on R8A7791_CLOCK_ROOT() below | ||
44 | */ | ||
45 | |||
46 | #define MD(nr) (1 << nr) | ||
47 | |||
48 | #define CPG_BASE 0xe6150000 | ||
49 | #define CPG_LEN 0x1000 | ||
50 | |||
51 | #define SMSTPCR0 0xE6150130 | ||
52 | #define SMSTPCR1 0xE6150134 | ||
53 | #define SMSTPCR2 0xe6150138 | ||
54 | #define SMSTPCR3 0xE615013C | ||
55 | #define SMSTPCR5 0xE6150144 | ||
56 | #define SMSTPCR7 0xe615014c | ||
57 | #define SMSTPCR8 0xE6150990 | ||
58 | #define SMSTPCR9 0xE6150994 | ||
59 | #define SMSTPCR10 0xE6150998 | ||
60 | #define SMSTPCR11 0xE615099C | ||
61 | |||
62 | #define MODEMR 0xE6160060 | ||
63 | #define SDCKCR 0xE6150074 | ||
64 | #define SD2CKCR 0xE6150078 | ||
65 | #define SD3CKCR 0xE615007C | ||
66 | #define MMC0CKCR 0xE6150240 | ||
67 | #define MMC1CKCR 0xE6150244 | ||
68 | #define SSPCKCR 0xE6150248 | ||
69 | #define SSPRSCKCR 0xE615024C | ||
70 | |||
71 | static struct clk_mapping cpg_mapping = { | ||
72 | .phys = CPG_BASE, | ||
73 | .len = CPG_LEN, | ||
74 | }; | ||
75 | |||
76 | static struct clk extal_clk = { | ||
77 | /* .rate will be updated on r8a7791_clock_init() */ | ||
78 | .mapping = &cpg_mapping, | ||
79 | }; | ||
80 | |||
81 | static struct sh_clk_ops followparent_clk_ops = { | ||
82 | .recalc = followparent_recalc, | ||
83 | }; | ||
84 | |||
85 | static struct clk main_clk = { | ||
86 | /* .parent will be set r8a73a4_clock_init */ | ||
87 | .ops = &followparent_clk_ops, | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * clock ratio of these clock will be updated | ||
92 | * on r8a7791_clock_init() | ||
93 | */ | ||
94 | SH_FIXED_RATIO_CLK_SET(pll1_clk, main_clk, 1, 1); | ||
95 | SH_FIXED_RATIO_CLK_SET(pll3_clk, main_clk, 1, 1); | ||
96 | |||
97 | /* fixed ratio clock */ | ||
98 | SH_FIXED_RATIO_CLK_SET(extal_div2_clk, extal_clk, 1, 2); | ||
99 | SH_FIXED_RATIO_CLK_SET(cp_clk, extal_clk, 1, 2); | ||
100 | |||
101 | SH_FIXED_RATIO_CLK_SET(pll1_div2_clk, pll1_clk, 1, 2); | ||
102 | SH_FIXED_RATIO_CLK_SET(hp_clk, pll1_clk, 1, 12); | ||
103 | SH_FIXED_RATIO_CLK_SET(p_clk, pll1_clk, 1, 24); | ||
104 | SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024)); | ||
105 | SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15); | ||
106 | |||
107 | static struct clk *main_clks[] = { | ||
108 | &extal_clk, | ||
109 | &extal_div2_clk, | ||
110 | &main_clk, | ||
111 | &pll1_clk, | ||
112 | &pll1_div2_clk, | ||
113 | &pll3_clk, | ||
114 | &hp_clk, | ||
115 | &p_clk, | ||
116 | &rclk_clk, | ||
117 | &mp_clk, | ||
118 | &cp_clk, | ||
119 | }; | ||
120 | |||
121 | /* MSTP */ | ||
122 | enum { | ||
123 | MSTP721, MSTP720, | ||
124 | MSTP719, MSTP718, MSTP715, MSTP714, | ||
125 | MSTP216, MSTP207, MSTP206, | ||
126 | MSTP204, MSTP203, MSTP202, MSTP1105, MSTP1106, MSTP1107, | ||
127 | MSTP124, | ||
128 | MSTP_NR | ||
129 | }; | ||
130 | |||
131 | static struct clk mstp_clks[MSTP_NR] = { | ||
132 | [MSTP721] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 21, 0), /* SCIF0 */ | ||
133 | [MSTP720] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 20, 0), /* SCIF1 */ | ||
134 | [MSTP719] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 19, 0), /* SCIF2 */ | ||
135 | [MSTP718] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 18, 0), /* SCIF3 */ | ||
136 | [MSTP715] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 15, 0), /* SCIF4 */ | ||
137 | [MSTP714] = SH_CLK_MSTP32(&p_clk, SMSTPCR7, 14, 0), /* SCIF5 */ | ||
138 | [MSTP216] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 16, 0), /* SCIFB2 */ | ||
139 | [MSTP207] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 7, 0), /* SCIFB1 */ | ||
140 | [MSTP206] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 6, 0), /* SCIFB0 */ | ||
141 | [MSTP204] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 4, 0), /* SCIFA0 */ | ||
142 | [MSTP203] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 3, 0), /* SCIFA1 */ | ||
143 | [MSTP202] = SH_CLK_MSTP32(&mp_clk, SMSTPCR2, 2, 0), /* SCIFA2 */ | ||
144 | [MSTP1105] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 5, 0), /* SCIFA3 */ | ||
145 | [MSTP1106] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 6, 0), /* SCIFA4 */ | ||
146 | [MSTP1107] = SH_CLK_MSTP32(&mp_clk, SMSTPCR11, 7, 0), /* SCIFA5 */ | ||
147 | [MSTP124] = SH_CLK_MSTP32(&rclk_clk, SMSTPCR1, 24, 0), /* CMT0 */ | ||
148 | }; | ||
149 | |||
150 | static struct clk_lookup lookups[] = { | ||
151 | |||
152 | /* main clocks */ | ||
153 | CLKDEV_CON_ID("extal", &extal_clk), | ||
154 | CLKDEV_CON_ID("extal_div2", &extal_div2_clk), | ||
155 | CLKDEV_CON_ID("main", &main_clk), | ||
156 | CLKDEV_CON_ID("pll1", &pll1_clk), | ||
157 | CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk), | ||
158 | CLKDEV_CON_ID("pll3", &pll3_clk), | ||
159 | CLKDEV_CON_ID("hp", &hp_clk), | ||
160 | CLKDEV_CON_ID("p", &p_clk), | ||
161 | CLKDEV_CON_ID("rclk", &rclk_clk), | ||
162 | CLKDEV_CON_ID("mp", &mp_clk), | ||
163 | CLKDEV_CON_ID("cp", &cp_clk), | ||
164 | CLKDEV_CON_ID("peripheral_clk", &hp_clk), | ||
165 | |||
166 | /* MSTP */ | ||
167 | CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */ | ||
168 | CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */ | ||
169 | CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP206]), /* SCIFB0 */ | ||
170 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP207]), /* SCIFB1 */ | ||
171 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP216]), /* SCIFB2 */ | ||
172 | CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP202]), /* SCIFA2 */ | ||
173 | CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP721]), /* SCIF0 */ | ||
174 | CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP720]), /* SCIF1 */ | ||
175 | CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP719]), /* SCIF2 */ | ||
176 | CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP718]), /* SCIF3 */ | ||
177 | CLKDEV_DEV_ID("sh-sci.10", &mstp_clks[MSTP715]), /* SCIF4 */ | ||
178 | CLKDEV_DEV_ID("sh-sci.11", &mstp_clks[MSTP714]), /* SCIF5 */ | ||
179 | CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1105]), /* SCIFA3 */ | ||
180 | CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1106]), /* SCIFA4 */ | ||
181 | CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1107]), /* SCIFA5 */ | ||
182 | CLKDEV_DEV_ID("sh_cmt.0", &mstp_clks[MSTP124]), | ||
183 | }; | ||
184 | |||
185 | #define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \ | ||
186 | extal_clk.rate = e * 1000 * 1000; \ | ||
187 | main_clk.parent = m; \ | ||
188 | SH_CLK_SET_RATIO(&pll1_clk_ratio, p1 / 2, 1); \ | ||
189 | if (mode & MD(19)) \ | ||
190 | SH_CLK_SET_RATIO(&pll3_clk_ratio, p31, 1); \ | ||
191 | else \ | ||
192 | SH_CLK_SET_RATIO(&pll3_clk_ratio, p30, 1) | ||
193 | |||
194 | |||
195 | void __init r8a7791_clock_init(void) | ||
196 | { | ||
197 | void __iomem *modemr = ioremap_nocache(MODEMR, PAGE_SIZE); | ||
198 | u32 mode; | ||
199 | int k, ret = 0; | ||
200 | |||
201 | BUG_ON(!modemr); | ||
202 | mode = ioread32(modemr); | ||
203 | iounmap(modemr); | ||
204 | |||
205 | switch (mode & (MD(14) | MD(13))) { | ||
206 | case 0: | ||
207 | R8A7791_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88); | ||
208 | break; | ||
209 | case MD(13): | ||
210 | R8A7791_CLOCK_ROOT(20, &extal_clk, 130, 156, 80, 66); | ||
211 | break; | ||
212 | case MD(14): | ||
213 | R8A7791_CLOCK_ROOT(26, &extal_div2_clk, 200, 240, 122, 102); | ||
214 | break; | ||
215 | case MD(13) | MD(14): | ||
216 | R8A7791_CLOCK_ROOT(30, &extal_div2_clk, 172, 208, 106, 88); | ||
217 | break; | ||
218 | } | ||
219 | |||
220 | for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++) | ||
221 | ret = clk_register(main_clks[k]); | ||
222 | |||
223 | if (!ret) | ||
224 | ret = sh_clk_mstp_register(mstp_clks, MSTP_NR); | ||
225 | |||
226 | clkdev_add_table(lookups, ARRAY_SIZE(lookups)); | ||
227 | |||
228 | if (!ret) | ||
229 | shmobile_clk_init(); | ||
230 | else | ||
231 | goto epanic; | ||
232 | |||
233 | return; | ||
234 | |||
235 | epanic: | ||
236 | panic("failed to setup r8a7791 clocks\n"); | ||
237 | } | ||