]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/arm/ti/ti_prcm.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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 Managment 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/cpu.h>
56 #include <machine/cpufunc.h>
57 #include <machine/frame.h>
58 #include <machine/resource.h>
59 #include <machine/intr.h>
60
61 #include <arm/ti/ti_prcm.h>
62
63 /**
64  *      ti_clk_devmap - Array of clock devices, should be defined one per SoC 
65  *
66  *      This array is typically defined in one of the targeted *_prcm_clk.c
67  *      files and is specific to the given SoC platform.  Each entry in the array
68  *      corresponds to an individual clock device.
69  */
70 extern struct ti_clock_dev ti_clk_devmap[];
71
72 /**
73  *      ti_prcm_clk_dev - returns a pointer to the clock device with given id
74  *      @clk: the ID of the clock device to get
75  *
76  *      Simply iterates through the clk_devmap global array and returns a pointer
77  *      to the clock device if found. 
78  *
79  *      LOCKING:
80  *      None
81  *
82  *      RETURNS:
83  *      The pointer to the clock device on success, on failure NULL is returned.
84  */
85 static struct ti_clock_dev *
86 ti_prcm_clk_dev(clk_ident_t clk)
87 {
88         struct ti_clock_dev *clk_dev;
89         
90         /* Find the clock within the devmap - it's a bit inefficent having a for 
91          * loop for this, but this function should only called when a driver is 
92          * being activated so IMHO not a big issue.
93          */
94         clk_dev = &(ti_clk_devmap[0]);
95         while (clk_dev->id != INVALID_CLK_IDENT) {
96                 if (clk_dev->id == clk) {
97                         return (clk_dev);
98                 }
99                 clk_dev++;
100         }
101
102         /* Sanity check we managed to find the clock */
103         printf("ti_prcm: Failed to find clock device (%d)\n", clk);
104         return (NULL);
105 }
106
107 /**
108  *      ti_prcm_clk_valid - enables a clock for a particular module
109  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
110  *            of possible modules.
111  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
112  *      
113  *      This function can enable either a functional or interface clock.
114  *
115  *      The real work done to enable the clock is really done in the callback
116  *      function associated with the clock, this function is simply a wrapper
117  *      around that.
118  *
119  *      LOCKING:
120  *      Internally locks the driver context.
121  *
122  *      RETURNS:
123  *      Returns 0 on success or positive error code on failure.
124  */
125 int
126 ti_prcm_clk_valid(clk_ident_t clk)
127 {
128         int ret = 0;
129
130         if (ti_prcm_clk_dev(clk) == NULL)
131                 ret = EINVAL;
132         
133         return (ret);
134 }
135
136
137 /**
138  *      ti_prcm_clk_enable - enables a clock for a particular module
139  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
140  *            of possible modules.
141  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
142  *      
143  *      This function can enable either a functional or interface clock.
144  *
145  *      The real work done to enable the clock is really done in the callback
146  *      function associated with the clock, this function is simply a wrapper
147  *      around that.
148  *
149  *      LOCKING:
150  *      Internally locks the driver context.
151  *
152  *      RETURNS:
153  *      Returns 0 on success or positive error code on failure.
154  */
155 int
156 ti_prcm_clk_enable(clk_ident_t clk)
157 {
158         struct ti_clock_dev *clk_dev;
159         int ret;
160
161         /* Find the clock within the devmap - it's a bit inefficent having a for 
162          * loop for this, but this function should only called when a driver is 
163          * being activated so IMHO not a big issue.
164          */
165         clk_dev = ti_prcm_clk_dev(clk);
166
167         /* Sanity check we managed to find the clock */
168         if (clk_dev == NULL)
169                 return (EINVAL);
170
171         /* Activate the clock */
172         if (clk_dev->clk_activate)
173                 ret = clk_dev->clk_activate(clk_dev);
174         else
175                 ret = EINVAL;
176
177         return (ret);
178 }
179
180
181 /**
182  *      ti_prcm_clk_disable - disables a clock for a particular module
183  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
184  *            of possible modules.
185  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
186  *      
187  *      This function can enable either a functional or interface clock.
188  *
189  *      The real work done to enable the clock is really done in the callback
190  *      function associated with the clock, this function is simply a wrapper
191  *      around that.
192  *
193  *      LOCKING:
194  *      Internally locks the driver context.
195  *
196  *      RETURNS:
197  *      Returns 0 on success or positive error code on failure.
198  */
199 int
200 ti_prcm_clk_disable(clk_ident_t clk)
201 {
202         struct ti_clock_dev *clk_dev;
203         int ret;
204
205         /* Find the clock within the devmap - it's a bit inefficent having a for 
206          * loop for this, but this function should only called when a driver is 
207          * being activated so IMHO not a big issue.
208          */
209         clk_dev = ti_prcm_clk_dev(clk);
210
211         /* Sanity check we managed to find the clock */
212         if (clk_dev == NULL)
213                 return (EINVAL);
214
215         /* Activate the clock */
216         if (clk_dev->clk_deactivate)
217                 ret = clk_dev->clk_deactivate(clk_dev);
218         else
219                 ret = EINVAL;
220         
221         return (ret);
222 }
223
224 /**
225  *      ti_prcm_clk_set_source - sets the source 
226  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
227  *            of possible modules.
228  *               Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
229  *      
230  *      This function can enable either a functional or interface clock.
231  *
232  *      The real work done to enable the clock is really done in the callback
233  *      function associated with the clock, this function is simply a wrapper
234  *      around that.
235  *
236  *      LOCKING:
237  *      Internally locks the driver context.
238  *
239  *      RETURNS:
240  *      Returns 0 on success or positive error code on failure.
241  */
242 int
243 ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
244 {
245         struct ti_clock_dev *clk_dev;
246         int ret;
247
248         /* Find the clock within the devmap - it's a bit inefficent having a for 
249          * loop for this, but this function should only called when a driver is 
250          * being activated so IMHO not a big issue.
251          */
252         clk_dev = ti_prcm_clk_dev(clk);
253
254         /* Sanity check we managed to find the clock */
255         if (clk_dev == NULL)
256                 return (EINVAL);
257
258         /* Activate the clock */
259         if (clk_dev->clk_set_source)
260                 ret = clk_dev->clk_set_source(clk_dev, clksrc);
261         else
262                 ret = EINVAL;
263
264         return (ret);
265 }
266
267
268 /**
269  *      ti_prcm_clk_get_source_freq - gets the source clock frequency
270  *      @clk: identifier for the module to enable, see ti_prcm.h for a list
271  *            of possible modules.
272  *      @freq: pointer to an integer that upon return will contain the src freq
273  *      
274  *      This function returns the frequency of the source clock.
275  *
276  *      The real work done to enable the clock is really done in the callback
277  *      function associated with the clock, this function is simply a wrapper
278  *      around that.
279  *
280  *      LOCKING:
281  *      Internally locks the driver context.
282  *
283  *      RETURNS:
284  *      Returns 0 on success or positive error code on failure.
285  */
286 int
287 ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
288 {
289         struct ti_clock_dev *clk_dev;
290         int ret;
291
292         /* Find the clock within the devmap - it's a bit inefficent having a for 
293          * loop for this, but this function should only called when a driver is 
294          * being activated so IMHO not a big issue.
295          */
296         clk_dev = ti_prcm_clk_dev(clk);
297
298         /* Sanity check we managed to find the clock */
299         if (clk_dev == NULL)
300                 return (EINVAL);
301
302         /* Get the source frequency of the clock */
303         if (clk_dev->clk_get_source_freq)
304                 ret = clk_dev->clk_get_source_freq(clk_dev, freq);
305         else
306                 ret = EINVAL;
307         
308         return (ret);
309 }