• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, 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 #include <linux/io.h>
25 
26 #include <mach/hardware.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  */
imx_decode_pll(unsigned int pll,u32 f_ref)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 
imx_get_system_clk(void)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 
imx_get_mcu_clk(void)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  */
imx_get_perclk1(void)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  */
imx_get_perclk2(void)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  */
imx_get_perclk3(void)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  */
imx_get_hclk(void)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 
clk_get(struct device * dev,const char * id)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 EXPORT_SYMBOL(clk_get);
176 
clk_put(struct clk * clk)177 void clk_put(struct clk *clk)
178 {
179 }
180 EXPORT_SYMBOL(clk_put);
181 
clk_enable(struct clk * clk)182 int clk_enable(struct clk *clk)
183 {
184 	return 0;
185 }
186 EXPORT_SYMBOL(clk_enable);
187 
clk_disable(struct clk * clk)188 void clk_disable(struct clk *clk)
189 {
190 }
191 EXPORT_SYMBOL(clk_disable);
192 
clk_get_rate(struct clk * clk)193 unsigned long clk_get_rate(struct clk *clk)
194 {
195 	return clk->get_rate();
196 }
197 EXPORT_SYMBOL(clk_get_rate);
198 
imx_clocks_init(void)199 int imx_clocks_init(void)
200 {
201 	int i;
202 
203 	mutex_lock(&clocks_mutex);
204 	for (i = 0; i < ARRAY_SIZE(clks); i++)
205 		list_add(&clks[i]->node, &clocks);
206 	mutex_unlock(&clocks_mutex);
207 
208 	return 0;
209 }
210 
211