Commit | Line | Data |
---|---|---|
d4a67d9d GJ |
1 | /* |
2 | * Atheros AR71XX/AR724X/AR913X common routines | |
3 | * | |
4 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License version 2 as published | |
8 | * by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/init.h> | |
14 | #include <linux/err.h> | |
15 | #include <linux/clk.h> | |
16 | ||
17 | #include <asm/mach-ath79/ath79.h> | |
18 | #include <asm/mach-ath79/ar71xx_regs.h> | |
19 | #include "common.h" | |
20 | ||
21 | #define AR71XX_BASE_FREQ 40000000 | |
22 | #define AR724X_BASE_FREQ 5000000 | |
23 | #define AR913X_BASE_FREQ 5000000 | |
24 | ||
25 | struct clk { | |
26 | unsigned long rate; | |
27 | }; | |
28 | ||
29 | static struct clk ath79_ref_clk; | |
30 | static struct clk ath79_cpu_clk; | |
31 | static struct clk ath79_ddr_clk; | |
32 | static struct clk ath79_ahb_clk; | |
33 | static struct clk ath79_wdt_clk; | |
34 | static struct clk ath79_uart_clk; | |
35 | ||
36 | static void __init ar71xx_clocks_init(void) | |
37 | { | |
38 | u32 pll; | |
39 | u32 freq; | |
40 | u32 div; | |
41 | ||
42 | ath79_ref_clk.rate = AR71XX_BASE_FREQ; | |
43 | ||
44 | pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); | |
45 | ||
46 | div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; | |
47 | freq = div * ath79_ref_clk.rate; | |
48 | ||
49 | div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; | |
50 | ath79_cpu_clk.rate = freq / div; | |
51 | ||
52 | div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; | |
53 | ath79_ddr_clk.rate = freq / div; | |
54 | ||
55 | div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; | |
56 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
57 | ||
58 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
59 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
60 | } | |
61 | ||
62 | static void __init ar724x_clocks_init(void) | |
63 | { | |
64 | u32 pll; | |
65 | u32 freq; | |
66 | u32 div; | |
67 | ||
68 | ath79_ref_clk.rate = AR724X_BASE_FREQ; | |
69 | pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); | |
70 | ||
71 | div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); | |
72 | freq = div * ath79_ref_clk.rate; | |
73 | ||
74 | div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); | |
75 | freq *= div; | |
76 | ||
77 | ath79_cpu_clk.rate = freq; | |
78 | ||
79 | div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; | |
80 | ath79_ddr_clk.rate = freq / div; | |
81 | ||
82 | div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; | |
83 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
84 | ||
85 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
86 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
87 | } | |
88 | ||
89 | static void __init ar913x_clocks_init(void) | |
90 | { | |
91 | u32 pll; | |
92 | u32 freq; | |
93 | u32 div; | |
94 | ||
95 | ath79_ref_clk.rate = AR913X_BASE_FREQ; | |
96 | pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); | |
97 | ||
98 | div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); | |
99 | freq = div * ath79_ref_clk.rate; | |
100 | ||
101 | ath79_cpu_clk.rate = freq; | |
102 | ||
103 | div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; | |
104 | ath79_ddr_clk.rate = freq / div; | |
105 | ||
106 | div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; | |
107 | ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; | |
108 | ||
109 | ath79_wdt_clk.rate = ath79_ahb_clk.rate; | |
110 | ath79_uart_clk.rate = ath79_ahb_clk.rate; | |
111 | } | |
112 | ||
113 | void __init ath79_clocks_init(void) | |
114 | { | |
115 | if (soc_is_ar71xx()) | |
116 | ar71xx_clocks_init(); | |
117 | else if (soc_is_ar724x()) | |
118 | ar724x_clocks_init(); | |
119 | else if (soc_is_ar913x()) | |
120 | ar913x_clocks_init(); | |
121 | else | |
122 | BUG(); | |
123 | ||
124 | pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " | |
125 | "Ref:%lu.%03luMHz", | |
126 | ath79_cpu_clk.rate / 1000000, | |
127 | (ath79_cpu_clk.rate / 1000) % 1000, | |
128 | ath79_ddr_clk.rate / 1000000, | |
129 | (ath79_ddr_clk.rate / 1000) % 1000, | |
130 | ath79_ahb_clk.rate / 1000000, | |
131 | (ath79_ahb_clk.rate / 1000) % 1000, | |
132 | ath79_ref_clk.rate / 1000000, | |
133 | (ath79_ref_clk.rate / 1000) % 1000); | |
134 | } | |
135 | ||
136 | /* | |
137 | * Linux clock API | |
138 | */ | |
139 | struct clk *clk_get(struct device *dev, const char *id) | |
140 | { | |
141 | if (!strcmp(id, "ref")) | |
142 | return &ath79_ref_clk; | |
143 | ||
144 | if (!strcmp(id, "cpu")) | |
145 | return &ath79_cpu_clk; | |
146 | ||
147 | if (!strcmp(id, "ddr")) | |
148 | return &ath79_ddr_clk; | |
149 | ||
150 | if (!strcmp(id, "ahb")) | |
151 | return &ath79_ahb_clk; | |
152 | ||
153 | if (!strcmp(id, "wdt")) | |
154 | return &ath79_wdt_clk; | |
155 | ||
156 | if (!strcmp(id, "uart")) | |
157 | return &ath79_uart_clk; | |
158 | ||
159 | return ERR_PTR(-ENOENT); | |
160 | } | |
161 | EXPORT_SYMBOL(clk_get); | |
162 | ||
163 | int clk_enable(struct clk *clk) | |
164 | { | |
165 | return 0; | |
166 | } | |
167 | EXPORT_SYMBOL(clk_enable); | |
168 | ||
169 | void clk_disable(struct clk *clk) | |
170 | { | |
171 | } | |
172 | EXPORT_SYMBOL(clk_disable); | |
173 | ||
174 | unsigned long clk_get_rate(struct clk *clk) | |
175 | { | |
176 | return clk->rate; | |
177 | } | |
178 | EXPORT_SYMBOL(clk_get_rate); | |
179 | ||
180 | void clk_put(struct clk *clk) | |
181 | { | |
182 | } | |
183 | EXPORT_SYMBOL(clk_put); |