]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/ti/ti_prcm.c
Remove kernel config for IMX53-QSB (quickstart board). It was just
[FreeBSD/FreeBSD.git] / sys / arm / ti / ti_prcm.c
1 /*
2  * Copyright (c) 2010
3  *      Ben Gray <ben.r.gray@gmail.com>.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Ben Gray.
17  * 4. The name of the company nor the name of the author may be used to
18  *    endorse or promote products derived from this software without specific
19  *    prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 /**
34  * Power, Reset and Clock Management Module
35  *
36  * This is a very simple driver wrapper around the PRCM set of registers in
37  * the OMAP3 chip. It allows you to turn on and off things like the functional
38  * and interface clocks to the various on-chip modules.
39  *
40  */
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/module.h>
48 #include <sys/bus.h>
49 #include <sys/resource.h>
50 #include <sys/rman.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53
54 #include <machine/bus.h>
55 #include <machine/resource.h>
56 #include <machine/intr.h>
57
58 #include <arm/ti/ti_cpuid.h>
59 #include <arm/ti/ti_prcm.h>
60
61 /**
62  *      ti_*_clk_devmap - Array of clock devices, should be defined one per SoC 
63  *
64  *      This array is typically defined in one of the targeted *_prcm_clk.c
65  *      files and is specific to the given SoC platform.  Each entry in the array
66  *      corresponds to an individual clock device.
67  */
68 extern struct ti_clock_dev ti_omap4_clk_devmap[];
69 extern struct ti_clock_dev ti_am335x_clk_devmap[];
70
71 /**
72  *      ti_prcm_clk_dev - returns a pointer to the clock device with given id
73  *      @clk: the ID of the clock device to get
74  *
75  *      Simply iterates through the clk_devmap global array and returns a pointer
76  *      to the clock device if found. 
77  *
78  *      LOCKING:
79  *      None
80  *
81  *      RETURNS:
82  *      The pointer to the clock device on success, on failure NULL is returned.
83  */
84 static struct ti_clock_dev *
85 ti_prcm_clk_dev(clk_ident_t clk)
86 {
87         struct ti_clock_dev *clk_dev;
88         
89         /* Find the clock within the devmap - it's a bit inefficent having a for 
90          * loop for this, but this function should only called when a driver is 
91          * being activated so IMHO not a big issue.
92          */
93         clk_dev = NULL;
94         switch(ti_chip()) {
95 #ifdef SOC_OMAP4
96         case CHIP_OMAP_4:
97                 clk_dev = &(ti_omap4_clk_devmap[0]);
98                 break;
99 #endif
100 #ifdef SOC_TI_AM335X
101         case CHIP_AM335X:
102                 clk_dev = &(ti_am335x_clk_devmap[0]);
103                 break;
104 #endif
105         }
106         if (clk_dev == NULL)
107                 panic("No clock devmap found");
108         while (clk_dev->id != INVALID_CLK_IDENT) {
109                 if (clk_dev->id == clk) {
110                         return (clk_dev);
111                 }
112                 clk_dev++;
113         }
114
115         /* Sanity check we managed to find the clock */
116         printf("ti_prcm: Failed to find clock device (%d)\n", clk);
117         return (NULL);
118 }
119
120 /**
121  *      ti_prcm_clk_valid - enables a clock for a particular module
122  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
123  *            of possible modules.
124  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
125  *      
126  *      This function can enable either a functional or interface clock.
127  *
128  *      The real work done to enable the clock is really done in the callback
129  *      function associated with the clock, this function is simply a wrapper
130  *      around that.
131  *
132  *      LOCKING:
133  *      Internally locks the driver context.
134  *
135  *      RETURNS:
136  *      Returns 0 on success or positive error code on failure.
137  */
138 int
139 ti_prcm_clk_valid(clk_ident_t clk)
140 {
141         int ret = 0;
142
143         if (ti_prcm_clk_dev(clk) == NULL)
144                 ret = EINVAL;
145         
146         return (ret);
147 }
148
149
150 /**
151  *      ti_prcm_clk_enable - enables a clock for a particular module
152  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
153  *            of possible modules.
154  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
155  *      
156  *      This function can enable either a functional or interface clock.
157  *
158  *      The real work done to enable the clock is really done in the callback
159  *      function associated with the clock, this function is simply a wrapper
160  *      around that.
161  *
162  *      LOCKING:
163  *      Internally locks the driver context.
164  *
165  *      RETURNS:
166  *      Returns 0 on success or positive error code on failure.
167  */
168 int
169 ti_prcm_clk_enable(clk_ident_t clk)
170 {
171         struct ti_clock_dev *clk_dev;
172         int ret;
173
174         /* Find the clock within the devmap - it's a bit inefficent having a for 
175          * loop for this, but this function should only called when a driver is 
176          * being activated so IMHO not a big issue.
177          */
178         clk_dev = ti_prcm_clk_dev(clk);
179
180         /* Sanity check we managed to find the clock */
181         if (clk_dev == NULL)
182                 return (EINVAL);
183
184         /* Activate the clock */
185         if (clk_dev->clk_activate)
186                 ret = clk_dev->clk_activate(clk_dev);
187         else
188                 ret = EINVAL;
189
190         return (ret);
191 }
192
193
194 /**
195  *      ti_prcm_clk_disable - disables a clock for a particular module
196  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
197  *            of possible modules.
198  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
199  *      
200  *      This function can enable either a functional or interface clock.
201  *
202  *      The real work done to enable the clock is really done in the callback
203  *      function associated with the clock, this function is simply a wrapper
204  *      around that.
205  *
206  *      LOCKING:
207  *      Internally locks the driver context.
208  *
209  *      RETURNS:
210  *      Returns 0 on success or positive error code on failure.
211  */
212 int
213 ti_prcm_clk_disable(clk_ident_t clk)
214 {
215         struct ti_clock_dev *clk_dev;
216         int ret;
217
218         /* Find the clock within the devmap - it's a bit inefficent having a for 
219          * loop for this, but this function should only called when a driver is 
220          * being activated so IMHO not a big issue.
221          */
222         clk_dev = ti_prcm_clk_dev(clk);
223
224         /* Sanity check we managed to find the clock */
225         if (clk_dev == NULL)
226                 return (EINVAL);
227
228         /* Activate the clock */
229         if (clk_dev->clk_deactivate)
230                 ret = clk_dev->clk_deactivate(clk_dev);
231         else
232                 ret = EINVAL;
233         
234         return (ret);
235 }
236
237 /**
238  *      ti_prcm_clk_set_source - sets the source 
239  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
240  *            of possible modules.
241  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
242  *      
243  *      This function can enable either a functional or interface clock.
244  *
245  *      The real work done to enable the clock is really done in the callback
246  *      function associated with the clock, this function is simply a wrapper
247  *      around that.
248  *
249  *      LOCKING:
250  *      Internally locks the driver context.
251  *
252  *      RETURNS:
253  *      Returns 0 on success or positive error code on failure.
254  */
255 int
256 ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
257 {
258         struct ti_clock_dev *clk_dev;
259         int ret;
260
261         /* Find the clock within the devmap - it's a bit inefficent having a for 
262          * loop for this, but this function should only called when a driver is 
263          * being activated so IMHO not a big issue.
264          */
265         clk_dev = ti_prcm_clk_dev(clk);
266
267         /* Sanity check we managed to find the clock */
268         if (clk_dev == NULL)
269                 return (EINVAL);
270
271         /* Activate the clock */
272         if (clk_dev->clk_set_source)
273                 ret = clk_dev->clk_set_source(clk_dev, clksrc);
274         else
275                 ret = EINVAL;
276
277         return (ret);
278 }
279
280
281 /**
282  *      ti_prcm_clk_get_source_freq - gets the source clock frequency
283  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
284  *            of possible modules.
285  *      @freq: pointer to an integer that upon return will contain the src freq
286  *
287  *      This function returns the frequency of the source clock.
288  *
289  *      The real work done to enable the clock is really done in the callback
290  *      function associated with the clock, this function is simply a wrapper
291  *      around that.
292  *
293  *      LOCKING:
294  *      Internally locks the driver context.
295  *
296  *      RETURNS:
297  *      Returns 0 on success or positive error code on failure.
298  */
299 int
300 ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
301 {
302         struct ti_clock_dev *clk_dev;
303         int ret;
304
305         /* Find the clock within the devmap - it's a bit inefficent having a for 
306          * loop for this, but this function should only called when a driver is 
307          * being activated so IMHO not a big issue.
308          */
309         clk_dev = ti_prcm_clk_dev(clk);
310
311         /* Sanity check we managed to find the clock */
312         if (clk_dev == NULL)
313                 return (EINVAL);
314
315         /* Get the source frequency of the clock */
316         if (clk_dev->clk_get_source_freq)
317                 ret = clk_dev->clk_get_source_freq(clk_dev, freq);
318         else
319                 ret = EINVAL;
320
321         return (ret);
322 }
323
324 /**
325  *      ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible
326  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
327  *            of possible modules.
328  *      @freq: requested freq
329  *
330  *      LOCKING:
331  *      Internally locks the driver context.
332  *
333  *      RETURNS:
334  *      Returns 0 on success or positive error code on failure.
335  */
336 int
337 ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq)
338 {
339         struct ti_clock_dev *clk_dev;
340         int ret;
341
342         clk_dev = ti_prcm_clk_dev(clk);
343
344         /* Sanity check we managed to find the clock */
345         if (clk_dev == NULL)
346                 return (EINVAL);
347
348         /* Get the source frequency of the clock */
349         if (clk_dev->clk_set_source_freq)
350                 ret = clk_dev->clk_set_source_freq(clk_dev, freq);
351         else
352                 ret = EINVAL;
353
354         return (ret);
355 }