2 * Atheros AR71XX/AR724X/AR913X common routines
4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
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.
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>
17 #include <asm/mach-ath79/ath79.h>
18 #include <asm/mach-ath79/ar71xx_regs.h>
21 #define AR71XX_BASE_FREQ 40000000
22 #define AR724X_BASE_FREQ 5000000
23 #define AR913X_BASE_FREQ 5000000
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
;
36 static void __init
ar71xx_clocks_init(void)
42 ath79_ref_clk
.rate
= AR71XX_BASE_FREQ
;
44 pll
= ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG
);
46 div
= ((pll
>> AR71XX_PLL_DIV_SHIFT
) & AR71XX_PLL_DIV_MASK
) + 1;
47 freq
= div
* ath79_ref_clk
.rate
;
49 div
= ((pll
>> AR71XX_CPU_DIV_SHIFT
) & AR71XX_CPU_DIV_MASK
) + 1;
50 ath79_cpu_clk
.rate
= freq
/ div
;
52 div
= ((pll
>> AR71XX_DDR_DIV_SHIFT
) & AR71XX_DDR_DIV_MASK
) + 1;
53 ath79_ddr_clk
.rate
= freq
/ div
;
55 div
= (((pll
>> AR71XX_AHB_DIV_SHIFT
) & AR71XX_AHB_DIV_MASK
) + 1) * 2;
56 ath79_ahb_clk
.rate
= ath79_cpu_clk
.rate
/ div
;
58 ath79_wdt_clk
.rate
= ath79_ahb_clk
.rate
;
59 ath79_uart_clk
.rate
= ath79_ahb_clk
.rate
;
62 static void __init
ar724x_clocks_init(void)
68 ath79_ref_clk
.rate
= AR724X_BASE_FREQ
;
69 pll
= ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG
);
71 div
= ((pll
>> AR724X_PLL_DIV_SHIFT
) & AR724X_PLL_DIV_MASK
);
72 freq
= div
* ath79_ref_clk
.rate
;
74 div
= ((pll
>> AR724X_PLL_REF_DIV_SHIFT
) & AR724X_PLL_REF_DIV_MASK
);
77 ath79_cpu_clk
.rate
= freq
;
79 div
= ((pll
>> AR724X_DDR_DIV_SHIFT
) & AR724X_DDR_DIV_MASK
) + 1;
80 ath79_ddr_clk
.rate
= freq
/ div
;
82 div
= (((pll
>> AR724X_AHB_DIV_SHIFT
) & AR724X_AHB_DIV_MASK
) + 1) * 2;
83 ath79_ahb_clk
.rate
= ath79_cpu_clk
.rate
/ div
;
85 ath79_wdt_clk
.rate
= ath79_ahb_clk
.rate
;
86 ath79_uart_clk
.rate
= ath79_ahb_clk
.rate
;
89 static void __init
ar913x_clocks_init(void)
95 ath79_ref_clk
.rate
= AR913X_BASE_FREQ
;
96 pll
= ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG
);
98 div
= ((pll
>> AR913X_PLL_DIV_SHIFT
) & AR913X_PLL_DIV_MASK
);
99 freq
= div
* ath79_ref_clk
.rate
;
101 ath79_cpu_clk
.rate
= freq
;
103 div
= ((pll
>> AR913X_DDR_DIV_SHIFT
) & AR913X_DDR_DIV_MASK
) + 1;
104 ath79_ddr_clk
.rate
= freq
/ div
;
106 div
= (((pll
>> AR913X_AHB_DIV_SHIFT
) & AR913X_AHB_DIV_MASK
) + 1) * 2;
107 ath79_ahb_clk
.rate
= ath79_cpu_clk
.rate
/ div
;
109 ath79_wdt_clk
.rate
= ath79_ahb_clk
.rate
;
110 ath79_uart_clk
.rate
= ath79_ahb_clk
.rate
;
113 static void __init
ar933x_clocks_init(void)
120 t
= ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP
);
121 if (t
& AR933X_BOOTSTRAP_REF_CLK_40
)
122 ath79_ref_clk
.rate
= (40 * 1000 * 1000);
124 ath79_ref_clk
.rate
= (25 * 1000 * 1000);
126 clock_ctrl
= ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG
);
127 if (clock_ctrl
& AR933X_PLL_CLOCK_CTRL_BYPASS
) {
128 ath79_cpu_clk
.rate
= ath79_ref_clk
.rate
;
129 ath79_ahb_clk
.rate
= ath79_ref_clk
.rate
;
130 ath79_ddr_clk
.rate
= ath79_ref_clk
.rate
;
132 cpu_config
= ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG
);
134 t
= (cpu_config
>> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT
) &
135 AR933X_PLL_CPU_CONFIG_REFDIV_MASK
;
136 freq
= ath79_ref_clk
.rate
/ t
;
138 t
= (cpu_config
>> AR933X_PLL_CPU_CONFIG_NINT_SHIFT
) &
139 AR933X_PLL_CPU_CONFIG_NINT_MASK
;
142 t
= (cpu_config
>> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT
) &
143 AR933X_PLL_CPU_CONFIG_OUTDIV_MASK
;
149 t
= ((clock_ctrl
>> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT
) &
150 AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK
) + 1;
151 ath79_cpu_clk
.rate
= freq
/ t
;
153 t
= ((clock_ctrl
>> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT
) &
154 AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK
) + 1;
155 ath79_ddr_clk
.rate
= freq
/ t
;
157 t
= ((clock_ctrl
>> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT
) &
158 AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK
) + 1;
159 ath79_ahb_clk
.rate
= freq
/ t
;
162 ath79_wdt_clk
.rate
= ath79_ref_clk
.rate
;
163 ath79_uart_clk
.rate
= ath79_ref_clk
.rate
;
166 void __init
ath79_clocks_init(void)
169 ar71xx_clocks_init();
170 else if (soc_is_ar724x())
171 ar724x_clocks_init();
172 else if (soc_is_ar913x())
173 ar913x_clocks_init();
174 else if (soc_is_ar933x())
175 ar933x_clocks_init();
179 pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
181 ath79_cpu_clk
.rate
/ 1000000,
182 (ath79_cpu_clk
.rate
/ 1000) % 1000,
183 ath79_ddr_clk
.rate
/ 1000000,
184 (ath79_ddr_clk
.rate
/ 1000) % 1000,
185 ath79_ahb_clk
.rate
/ 1000000,
186 (ath79_ahb_clk
.rate
/ 1000) % 1000,
187 ath79_ref_clk
.rate
/ 1000000,
188 (ath79_ref_clk
.rate
/ 1000) % 1000);
194 struct clk
*clk_get(struct device
*dev
, const char *id
)
196 if (!strcmp(id
, "ref"))
197 return &ath79_ref_clk
;
199 if (!strcmp(id
, "cpu"))
200 return &ath79_cpu_clk
;
202 if (!strcmp(id
, "ddr"))
203 return &ath79_ddr_clk
;
205 if (!strcmp(id
, "ahb"))
206 return &ath79_ahb_clk
;
208 if (!strcmp(id
, "wdt"))
209 return &ath79_wdt_clk
;
211 if (!strcmp(id
, "uart"))
212 return &ath79_uart_clk
;
214 return ERR_PTR(-ENOENT
);
216 EXPORT_SYMBOL(clk_get
);
218 int clk_enable(struct clk
*clk
)
222 EXPORT_SYMBOL(clk_enable
);
224 void clk_disable(struct clk
*clk
)
227 EXPORT_SYMBOL(clk_disable
);
229 unsigned long clk_get_rate(struct clk
*clk
)
233 EXPORT_SYMBOL(clk_get_rate
);
235 void clk_put(struct clk
*clk
)
238 EXPORT_SYMBOL(clk_put
);