3 * Ben Gray <ben.r.gray@gmail.com>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
34 * Power, Reset and Clock Management Module
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.
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/module.h>
49 #include <sys/resource.h>
52 #include <sys/mutex.h>
54 #include <machine/bus.h>
55 #include <machine/cpu.h>
56 #include <machine/cpufunc.h>
57 #include <machine/resource.h>
58 #include <machine/intr.h>
60 #include <arm/ti/ti_cpuid.h>
61 #include <arm/ti/ti_prcm.h>
64 * ti_*_clk_devmap - Array of clock devices, should be defined one per SoC
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.
70 extern struct ti_clock_dev ti_omap4_clk_devmap[];
71 extern struct ti_clock_dev ti_am335x_clk_devmap[];
74 * ti_prcm_clk_dev - returns a pointer to the clock device with given id
75 * @clk: the ID of the clock device to get
77 * Simply iterates through the clk_devmap global array and returns a pointer
78 * to the clock device if found.
84 * The pointer to the clock device on success, on failure NULL is returned.
86 static struct ti_clock_dev *
87 ti_prcm_clk_dev(clk_ident_t clk)
89 struct ti_clock_dev *clk_dev;
91 /* Find the clock within the devmap - it's a bit inefficent having a for
92 * loop for this, but this function should only called when a driver is
93 * being activated so IMHO not a big issue.
99 clk_dev = &(ti_omap4_clk_devmap[0]);
104 clk_dev = &(ti_am335x_clk_devmap[0]);
109 panic("No clock devmap found");
110 while (clk_dev->id != INVALID_CLK_IDENT) {
111 if (clk_dev->id == clk) {
117 /* Sanity check we managed to find the clock */
118 printf("ti_prcm: Failed to find clock device (%d)\n", clk);
123 * ti_prcm_clk_valid - enables a clock for a particular module
124 * @clk: identifier for the module to enable, see ti_prcm.h for a list
125 * of possible modules.
126 * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
128 * This function can enable either a functional or interface clock.
130 * The real work done to enable the clock is really done in the callback
131 * function associated with the clock, this function is simply a wrapper
135 * Internally locks the driver context.
138 * Returns 0 on success or positive error code on failure.
141 ti_prcm_clk_valid(clk_ident_t clk)
145 if (ti_prcm_clk_dev(clk) == NULL)
153 * ti_prcm_clk_enable - enables a clock for a particular module
154 * @clk: identifier for the module to enable, see ti_prcm.h for a list
155 * of possible modules.
156 * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
158 * This function can enable either a functional or interface clock.
160 * The real work done to enable the clock is really done in the callback
161 * function associated with the clock, this function is simply a wrapper
165 * Internally locks the driver context.
168 * Returns 0 on success or positive error code on failure.
171 ti_prcm_clk_enable(clk_ident_t clk)
173 struct ti_clock_dev *clk_dev;
176 /* Find the clock within the devmap - it's a bit inefficent having a for
177 * loop for this, but this function should only called when a driver is
178 * being activated so IMHO not a big issue.
180 clk_dev = ti_prcm_clk_dev(clk);
182 /* Sanity check we managed to find the clock */
186 /* Activate the clock */
187 if (clk_dev->clk_activate)
188 ret = clk_dev->clk_activate(clk_dev);
197 * ti_prcm_clk_disable - disables a clock for a particular module
198 * @clk: identifier for the module to enable, see ti_prcm.h for a list
199 * of possible modules.
200 * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
202 * This function can enable either a functional or interface clock.
204 * The real work done to enable the clock is really done in the callback
205 * function associated with the clock, this function is simply a wrapper
209 * Internally locks the driver context.
212 * Returns 0 on success or positive error code on failure.
215 ti_prcm_clk_disable(clk_ident_t clk)
217 struct ti_clock_dev *clk_dev;
220 /* Find the clock within the devmap - it's a bit inefficent having a for
221 * loop for this, but this function should only called when a driver is
222 * being activated so IMHO not a big issue.
224 clk_dev = ti_prcm_clk_dev(clk);
226 /* Sanity check we managed to find the clock */
230 /* Activate the clock */
231 if (clk_dev->clk_deactivate)
232 ret = clk_dev->clk_deactivate(clk_dev);
240 * ti_prcm_clk_set_source - sets the source
241 * @clk: identifier for the module to enable, see ti_prcm.h for a list
242 * of possible modules.
243 * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
245 * This function can enable either a functional or interface clock.
247 * The real work done to enable the clock is really done in the callback
248 * function associated with the clock, this function is simply a wrapper
252 * Internally locks the driver context.
255 * Returns 0 on success or positive error code on failure.
258 ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
260 struct ti_clock_dev *clk_dev;
263 /* Find the clock within the devmap - it's a bit inefficent having a for
264 * loop for this, but this function should only called when a driver is
265 * being activated so IMHO not a big issue.
267 clk_dev = ti_prcm_clk_dev(clk);
269 /* Sanity check we managed to find the clock */
273 /* Activate the clock */
274 if (clk_dev->clk_set_source)
275 ret = clk_dev->clk_set_source(clk_dev, clksrc);
284 * ti_prcm_clk_get_source_freq - gets the source clock frequency
285 * @clk: identifier for the module to enable, see ti_prcm.h for a list
286 * of possible modules.
287 * @freq: pointer to an integer that upon return will contain the src freq
289 * This function returns the frequency of the source clock.
291 * The real work done to enable the clock is really done in the callback
292 * function associated with the clock, this function is simply a wrapper
296 * Internally locks the driver context.
299 * Returns 0 on success or positive error code on failure.
302 ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
304 struct ti_clock_dev *clk_dev;
307 /* Find the clock within the devmap - it's a bit inefficent having a for
308 * loop for this, but this function should only called when a driver is
309 * being activated so IMHO not a big issue.
311 clk_dev = ti_prcm_clk_dev(clk);
313 /* Sanity check we managed to find the clock */
317 /* Get the source frequency of the clock */
318 if (clk_dev->clk_get_source_freq)
319 ret = clk_dev->clk_get_source_freq(clk_dev, freq);
327 * ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible
328 * @clk: identifier for the module to enable, see ti_prcm.h for a list
329 * of possible modules.
330 * @freq: requested freq
333 * Internally locks the driver context.
336 * Returns 0 on success or positive error code on failure.
339 ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq)
341 struct ti_clock_dev *clk_dev;
344 clk_dev = ti_prcm_clk_dev(clk);
346 /* Sanity check we managed to find the clock */
350 /* Get the source frequency of the clock */
351 if (clk_dev->clk_set_source_freq)
352 ret = clk_dev->clk_set_source_freq(clk_dev, freq);