Skip to content

Commit 38a41fd

Browse files
saschahauerrschwebel
authored andcommitted
IMX: introduce clock API
This patch introduces the clock API for i.MX and converts all in-Kernel drivers to use it. Signed-off-by: Sascha Hauer <[email protected]>
1 parent dbff4e9 commit 38a41fd

File tree

9 files changed

+307
-109
lines changed

9 files changed

+307
-109
lines changed

arch/arm/mach-imx/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# Object file lists.
66

7-
obj-y += irq.o time.o dma.o generic.o
7+
obj-y += irq.o time.o dma.o generic.o clock.o
88

99
obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o
1010

arch/arm/mach-imx/clock.c

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright (C) 2008 Sascha Hauer <[email protected]>, Pengutronix
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17+
*/
18+
19+
#include <linux/kernel.h>
20+
#include <linux/device.h>
21+
#include <linux/list.h>
22+
#include <linux/math64.h>
23+
#include <linux/err.h>
24+
25+
#include <asm/io.h>
26+
#include <asm/arch/imx-regs.h>
27+
28+
/*
29+
* Very simple approach: We can't disable clocks, so we do
30+
* not need refcounting
31+
*/
32+
33+
struct clk {
34+
struct list_head node;
35+
const char *name;
36+
unsigned long (*get_rate)(void);
37+
};
38+
39+
/*
40+
* get the system pll clock in Hz
41+
*
42+
* mfi + mfn / (mfd +1)
43+
* f = 2 * f_ref * --------------------
44+
* pd + 1
45+
*/
46+
static unsigned long imx_decode_pll(unsigned int pll, u32 f_ref)
47+
{
48+
unsigned long long ll;
49+
unsigned long quot;
50+
51+
u32 mfi = (pll >> 10) & 0xf;
52+
u32 mfn = pll & 0x3ff;
53+
u32 mfd = (pll >> 16) & 0x3ff;
54+
u32 pd = (pll >> 26) & 0xf;
55+
56+
mfi = mfi <= 5 ? 5 : mfi;
57+
58+
ll = 2 * (unsigned long long)f_ref *
59+
((mfi << 16) + (mfn << 16) / (mfd + 1));
60+
quot = (pd + 1) * (1 << 16);
61+
ll += quot / 2;
62+
do_div(ll, quot);
63+
return (unsigned long)ll;
64+
}
65+
66+
static unsigned long imx_get_system_clk(void)
67+
{
68+
u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
69+
70+
return imx_decode_pll(SPCTL0, f_ref);
71+
}
72+
73+
static unsigned long imx_get_mcu_clk(void)
74+
{
75+
return imx_decode_pll(MPCTL0, CLK32 * 512);
76+
}
77+
78+
/*
79+
* get peripheral clock 1 ( UART[12], Timer[12], PWM )
80+
*/
81+
static unsigned long imx_get_perclk1(void)
82+
{
83+
return imx_get_system_clk() / (((PCDR) & 0xf)+1);
84+
}
85+
86+
/*
87+
* get peripheral clock 2 ( LCD, SD, SPI[12] )
88+
*/
89+
static unsigned long imx_get_perclk2(void)
90+
{
91+
return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
92+
}
93+
94+
/*
95+
* get peripheral clock 3 ( SSI )
96+
*/
97+
static unsigned long imx_get_perclk3(void)
98+
{
99+
return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
100+
}
101+
102+
/*
103+
* get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
104+
*/
105+
static unsigned long imx_get_hclk(void)
106+
{
107+
return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
108+
}
109+
110+
static struct clk clk_system_clk = {
111+
.name = "system_clk",
112+
.get_rate = imx_get_system_clk,
113+
};
114+
115+
static struct clk clk_hclk = {
116+
.name = "hclk",
117+
.get_rate = imx_get_hclk,
118+
};
119+
120+
static struct clk clk_mcu_clk = {
121+
.name = "mcu_clk",
122+
.get_rate = imx_get_mcu_clk,
123+
};
124+
125+
static struct clk clk_perclk1 = {
126+
.name = "perclk1",
127+
.get_rate = imx_get_perclk1,
128+
};
129+
130+
static struct clk clk_uart_clk = {
131+
.name = "uart_clk",
132+
.get_rate = imx_get_perclk1,
133+
};
134+
135+
static struct clk clk_perclk2 = {
136+
.name = "perclk2",
137+
.get_rate = imx_get_perclk2,
138+
};
139+
140+
static struct clk clk_perclk3 = {
141+
.name = "perclk3",
142+
.get_rate = imx_get_perclk3,
143+
};
144+
145+
static struct clk *clks[] = {
146+
&clk_perclk1,
147+
&clk_perclk2,
148+
&clk_perclk3,
149+
&clk_system_clk,
150+
&clk_hclk,
151+
&clk_mcu_clk,
152+
&clk_uart_clk,
153+
};
154+
155+
static LIST_HEAD(clocks);
156+
static DEFINE_MUTEX(clocks_mutex);
157+
158+
struct clk *clk_get(struct device *dev, const char *id)
159+
{
160+
struct clk *p, *clk = ERR_PTR(-ENOENT);
161+
162+
mutex_lock(&clocks_mutex);
163+
list_for_each_entry(p, &clocks, node) {
164+
if (!strcmp(p->name, id)) {
165+
clk = p;
166+
goto found;
167+
}
168+
}
169+
170+
found:
171+
mutex_unlock(&clocks_mutex);
172+
173+
return clk;
174+
}
175+
176+
void clk_put(struct clk *clk)
177+
{
178+
}
179+
180+
int clk_enable(struct clk *clk)
181+
{
182+
return 0;
183+
}
184+
185+
void clk_disable(struct clk *clk)
186+
{
187+
}
188+
189+
unsigned long clk_get_rate(struct clk *clk)
190+
{
191+
return clk->get_rate();
192+
}
193+
194+
int imx_clocks_init(void)
195+
{
196+
int i;
197+
198+
mutex_lock(&clocks_mutex);
199+
for (i = 0; i < ARRAY_SIZE(clks); i++)
200+
list_add(&clks[i]->node, &clocks);
201+
mutex_unlock(&clocks_mutex);
202+
203+
return 0;
204+
}
205+

arch/arm/mach-imx/cpufreq.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
#include <linux/types.h>
3333
#include <linux/init.h>
3434
#include <linux/cpufreq.h>
35+
#include <linux/clk.h>
36+
#include <linux/err.h>
3537
#include <asm/system.h>
3638

3739
#include <asm/hardware.h>
@@ -52,6 +54,8 @@
5254
static u32 mpctl0_at_boot;
5355
static u32 bclk_div_at_boot;
5456

57+
static struct clk *system_clk, *mcu_clk;
58+
5559
static void imx_set_async_mode(void)
5660
{
5761
adjust_cr(CR_920T_CLOCK_MODE, CR_920T_ASYNC_MODE);
@@ -160,10 +164,10 @@ static unsigned int imx_get_speed(unsigned int cpu)
160164
cr = get_cr();
161165

162166
if((cr & CR_920T_CLOCK_MODE) == CR_920T_FASTBUS_MODE) {
163-
freq = imx_get_system_clk();
167+
freq = clk_get_rate(system_clk);
164168
freq = (freq + bclk_div/2) / bclk_div;
165169
} else {
166-
freq = imx_get_mcu_clk();
170+
freq = clk_get_rate(mcu_clk);
167171
if (cscr & CSCR_MPU_PRESC)
168172
freq /= 2;
169173
}
@@ -201,7 +205,7 @@ static int imx_set_target(struct cpufreq_policy *policy,
201205
pr_debug(KERN_DEBUG "imx: requested frequency %ld Hz, mpctl0 at boot 0x%08x\n",
202206
freq, mpctl0_at_boot);
203207

204-
sysclk = imx_get_system_clk();
208+
sysclk = clk_get_rate(system_clk);
205209

206210
if (freq > sysclk / bclk_div_at_boot + 1000000) {
207211
freq = imx_compute_mpctl(&mpctl0, mpctl0_at_boot, CLK32 * 512, freq, relation);
@@ -290,6 +294,16 @@ static int __init imx_cpufreq_init(void)
290294
bclk_div_at_boot = __mfld2val(CSCR_BCLK_DIV, CSCR) + 1;
291295
mpctl0_at_boot = 0;
292296

297+
system_clk = clk_get(NULL, "system_clk");
298+
if (IS_ERR(system_clk))
299+
return PTR_ERR(system_clk);
300+
301+
mcu_clk = clk_get(NULL, "mcu_clk");
302+
if (IS_ERR(mcu_clk)) {
303+
clk_put(system_clk);
304+
return PTR_ERR(mcu_clk);
305+
}
306+
293307
if((CSCR & CSCR_MPEN) &&
294308
((get_cr() & CR_920T_CLOCK_MODE) != CR_920T_FASTBUS_MODE))
295309
mpctl0_at_boot = MPCTL0;

arch/arm/mach-imx/generic.c

Lines changed: 0 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -214,82 +214,6 @@ int imx_irq_to_gpio(unsigned irq)
214214

215215
EXPORT_SYMBOL(imx_irq_to_gpio);
216216

217-
/*
218-
* get the system pll clock in Hz
219-
*
220-
* mfi + mfn / (mfd +1)
221-
* f = 2 * f_ref * --------------------
222-
* pd + 1
223-
*/
224-
static unsigned int imx_decode_pll(unsigned int pll, u32 f_ref)
225-
{
226-
unsigned long long ll;
227-
unsigned long quot;
228-
229-
u32 mfi = (pll >> 10) & 0xf;
230-
u32 mfn = pll & 0x3ff;
231-
u32 mfd = (pll >> 16) & 0x3ff;
232-
u32 pd = (pll >> 26) & 0xf;
233-
234-
mfi = mfi <= 5 ? 5 : mfi;
235-
236-
ll = 2 * (unsigned long long)f_ref * ( (mfi<<16) + (mfn<<16) / (mfd+1) );
237-
quot = (pd+1) * (1<<16);
238-
ll += quot / 2;
239-
do_div(ll, quot);
240-
return (unsigned int) ll;
241-
}
242-
243-
unsigned int imx_get_system_clk(void)
244-
{
245-
u32 f_ref = (CSCR & CSCR_SYSTEM_SEL) ? 16000000 : (CLK32 * 512);
246-
247-
return imx_decode_pll(SPCTL0, f_ref);
248-
}
249-
EXPORT_SYMBOL(imx_get_system_clk);
250-
251-
unsigned int imx_get_mcu_clk(void)
252-
{
253-
return imx_decode_pll(MPCTL0, CLK32 * 512);
254-
}
255-
EXPORT_SYMBOL(imx_get_mcu_clk);
256-
257-
/*
258-
* get peripheral clock 1 ( UART[12], Timer[12], PWM )
259-
*/
260-
unsigned int imx_get_perclk1(void)
261-
{
262-
return imx_get_system_clk() / (((PCDR) & 0xf)+1);
263-
}
264-
EXPORT_SYMBOL(imx_get_perclk1);
265-
266-
/*
267-
* get peripheral clock 2 ( LCD, SD, SPI[12] )
268-
*/
269-
unsigned int imx_get_perclk2(void)
270-
{
271-
return imx_get_system_clk() / (((PCDR>>4) & 0xf)+1);
272-
}
273-
EXPORT_SYMBOL(imx_get_perclk2);
274-
275-
/*
276-
* get peripheral clock 3 ( SSI )
277-
*/
278-
unsigned int imx_get_perclk3(void)
279-
{
280-
return imx_get_system_clk() / (((PCDR>>16) & 0x7f)+1);
281-
}
282-
EXPORT_SYMBOL(imx_get_perclk3);
283-
284-
/*
285-
* get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
286-
*/
287-
unsigned int imx_get_hclk(void)
288-
{
289-
return imx_get_system_clk() / (((CSCR>>10) & 0xf)+1);
290-
}
291-
EXPORT_SYMBOL(imx_get_hclk);
292-
293217
static struct resource imx_mmc_resources[] = {
294218
[0] = {
295219
.start = 0x00214000,

0 commit comments

Comments
 (0)