blob: 680bde99a26c3bf8ad314549b8d7ee16cbcdbfe0 [file] [log] [blame]
Gabor Juhosd4a67d92011-01-04 21:28:14 +01001/*
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
25struct clk {
26 unsigned long rate;
27};
28
29static struct clk ath79_ref_clk;
30static struct clk ath79_cpu_clk;
31static struct clk ath79_ddr_clk;
32static struct clk ath79_ahb_clk;
33static struct clk ath79_wdt_clk;
34static struct clk ath79_uart_clk;
35
36static 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
62static 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
89static 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
113void __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 */
139struct 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}
161EXPORT_SYMBOL(clk_get);
162
163int clk_enable(struct clk *clk)
164{
165 return 0;
166}
167EXPORT_SYMBOL(clk_enable);
168
169void clk_disable(struct clk *clk)
170{
171}
172EXPORT_SYMBOL(clk_disable);
173
174unsigned long clk_get_rate(struct clk *clk)
175{
176 return clk->rate;
177}
178EXPORT_SYMBOL(clk_get_rate);
179
180void clk_put(struct clk *clk)
181{
182}
183EXPORT_SYMBOL(clk_put);