ti_prcm.c revision 239281
1239281Sgonzo/*
2239281Sgonzo * Copyright (c) 2010
3239281Sgonzo *	Ben Gray <ben.r.gray@gmail.com>.
4239281Sgonzo * All rights reserved.
5239281Sgonzo *
6239281Sgonzo * Redistribution and use in source and binary forms, with or without
7239281Sgonzo * modification, are permitted provided that the following conditions
8239281Sgonzo * are met:
9239281Sgonzo * 1. Redistributions of source code must retain the above copyright
10239281Sgonzo *    notice, this list of conditions and the following disclaimer.
11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
13239281Sgonzo *    documentation and/or other materials provided with the distribution.
14239281Sgonzo * 3. All advertising materials mentioning features or use of this software
15239281Sgonzo *    must display the following acknowledgement:
16239281Sgonzo *	This product includes software developed by Ben Gray.
17239281Sgonzo * 4. The name of the company nor the name of the author may be used to
18239281Sgonzo *    endorse or promote products derived from this software without specific
19239281Sgonzo *    prior written permission.
20239281Sgonzo *
21239281Sgonzo * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
22239281Sgonzo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23239281Sgonzo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24239281Sgonzo * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25239281Sgonzo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26239281Sgonzo * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27239281Sgonzo * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28239281Sgonzo * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29239281Sgonzo * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
30239281Sgonzo * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31239281Sgonzo */
32239281Sgonzo
33239281Sgonzo/**
34239281Sgonzo * Power, Reset and Clock Managment Module
35239281Sgonzo *
36239281Sgonzo * This is a very simple driver wrapper around the PRCM set of registers in
37239281Sgonzo * the OMAP3 chip. It allows you to turn on and off things like the functional
38239281Sgonzo * and interface clocks to the various on-chip modules.
39239281Sgonzo *
40239281Sgonzo */
41239281Sgonzo#include <sys/cdefs.h>
42239281Sgonzo__FBSDID("$FreeBSD: head/sys/arm/ti/ti_prcm.c 239281 2012-08-15 06:31:32Z gonzo $");
43239281Sgonzo
44239281Sgonzo#include <sys/param.h>
45239281Sgonzo#include <sys/systm.h>
46239281Sgonzo#include <sys/kernel.h>
47239281Sgonzo#include <sys/module.h>
48239281Sgonzo#include <sys/bus.h>
49239281Sgonzo#include <sys/resource.h>
50239281Sgonzo#include <sys/rman.h>
51239281Sgonzo#include <sys/lock.h>
52239281Sgonzo#include <sys/mutex.h>
53239281Sgonzo
54239281Sgonzo#include <machine/bus.h>
55239281Sgonzo#include <machine/cpu.h>
56239281Sgonzo#include <machine/cpufunc.h>
57239281Sgonzo#include <machine/frame.h>
58239281Sgonzo#include <machine/resource.h>
59239281Sgonzo#include <machine/intr.h>
60239281Sgonzo
61239281Sgonzo#include <arm/ti/ti_prcm.h>
62239281Sgonzo
63239281Sgonzo/**
64239281Sgonzo *	ti_clk_devmap - Array of clock devices, should be defined one per SoC
65239281Sgonzo *
66239281Sgonzo *	This array is typically defined in one of the targeted *_prcm_clk.c
67239281Sgonzo *	files and is specific to the given SoC platform.  Each entry in the array
68239281Sgonzo *	corresponds to an individual clock device.
69239281Sgonzo */
70239281Sgonzoextern struct ti_clock_dev ti_clk_devmap[];
71239281Sgonzo
72239281Sgonzo/**
73239281Sgonzo *	ti_prcm_clk_dev - returns a pointer to the clock device with given id
74239281Sgonzo *	@clk: the ID of the clock device to get
75239281Sgonzo *
76239281Sgonzo *	Simply iterates through the clk_devmap global array and returns a pointer
77239281Sgonzo *	to the clock device if found.
78239281Sgonzo *
79239281Sgonzo *	LOCKING:
80239281Sgonzo *	None
81239281Sgonzo *
82239281Sgonzo *	RETURNS:
83239281Sgonzo *	The pointer to the clock device on success, on failure NULL is returned.
84239281Sgonzo */
85239281Sgonzostatic struct ti_clock_dev *
86239281Sgonzoti_prcm_clk_dev(clk_ident_t clk)
87239281Sgonzo{
88239281Sgonzo	struct ti_clock_dev *clk_dev;
89239281Sgonzo
90239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
91239281Sgonzo	 * loop for this, but this function should only called when a driver is
92239281Sgonzo	 * being activated so IMHO not a big issue.
93239281Sgonzo	 */
94239281Sgonzo	clk_dev = &(ti_clk_devmap[0]);
95239281Sgonzo	while (clk_dev->id != INVALID_CLK_IDENT) {
96239281Sgonzo		if (clk_dev->id == clk) {
97239281Sgonzo			return (clk_dev);
98239281Sgonzo		}
99239281Sgonzo		clk_dev++;
100239281Sgonzo	}
101239281Sgonzo
102239281Sgonzo	/* Sanity check we managed to find the clock */
103239281Sgonzo	printf("ti_prcm: Failed to find clock device (%d)\n", clk);
104239281Sgonzo	return (NULL);
105239281Sgonzo}
106239281Sgonzo
107239281Sgonzo/**
108239281Sgonzo *	ti_prcm_clk_valid - enables a clock for a particular module
109239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
110239281Sgonzo *	      of possible modules.
111239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
112239281Sgonzo *
113239281Sgonzo *	This function can enable either a functional or interface clock.
114239281Sgonzo *
115239281Sgonzo *	The real work done to enable the clock is really done in the callback
116239281Sgonzo *	function associated with the clock, this function is simply a wrapper
117239281Sgonzo *	around that.
118239281Sgonzo *
119239281Sgonzo *	LOCKING:
120239281Sgonzo *	Internally locks the driver context.
121239281Sgonzo *
122239281Sgonzo *	RETURNS:
123239281Sgonzo *	Returns 0 on success or positive error code on failure.
124239281Sgonzo */
125239281Sgonzoint
126239281Sgonzoti_prcm_clk_valid(clk_ident_t clk)
127239281Sgonzo{
128239281Sgonzo	int ret = 0;
129239281Sgonzo
130239281Sgonzo	if (ti_prcm_clk_dev(clk) == NULL)
131239281Sgonzo		ret = EINVAL;
132239281Sgonzo
133239281Sgonzo	return (ret);
134239281Sgonzo}
135239281Sgonzo
136239281Sgonzo
137239281Sgonzo/**
138239281Sgonzo *	ti_prcm_clk_enable - enables a clock for a particular module
139239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
140239281Sgonzo *	      of possible modules.
141239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
142239281Sgonzo *
143239281Sgonzo *	This function can enable either a functional or interface clock.
144239281Sgonzo *
145239281Sgonzo *	The real work done to enable the clock is really done in the callback
146239281Sgonzo *	function associated with the clock, this function is simply a wrapper
147239281Sgonzo *	around that.
148239281Sgonzo *
149239281Sgonzo *	LOCKING:
150239281Sgonzo *	Internally locks the driver context.
151239281Sgonzo *
152239281Sgonzo *	RETURNS:
153239281Sgonzo *	Returns 0 on success or positive error code on failure.
154239281Sgonzo */
155239281Sgonzoint
156239281Sgonzoti_prcm_clk_enable(clk_ident_t clk)
157239281Sgonzo{
158239281Sgonzo	struct ti_clock_dev *clk_dev;
159239281Sgonzo	int ret;
160239281Sgonzo
161239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
162239281Sgonzo	 * loop for this, but this function should only called when a driver is
163239281Sgonzo	 * being activated so IMHO not a big issue.
164239281Sgonzo	 */
165239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
166239281Sgonzo
167239281Sgonzo	/* Sanity check we managed to find the clock */
168239281Sgonzo	if (clk_dev == NULL)
169239281Sgonzo		return (EINVAL);
170239281Sgonzo
171239281Sgonzo	/* Activate the clock */
172239281Sgonzo	if (clk_dev->clk_activate)
173239281Sgonzo		ret = clk_dev->clk_activate(clk_dev);
174239281Sgonzo	else
175239281Sgonzo		ret = EINVAL;
176239281Sgonzo
177239281Sgonzo	return (ret);
178239281Sgonzo}
179239281Sgonzo
180239281Sgonzo
181239281Sgonzo/**
182239281Sgonzo *	ti_prcm_clk_disable - disables a clock for a particular module
183239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
184239281Sgonzo *	      of possible modules.
185239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
186239281Sgonzo *
187239281Sgonzo *	This function can enable either a functional or interface clock.
188239281Sgonzo *
189239281Sgonzo *	The real work done to enable the clock is really done in the callback
190239281Sgonzo *	function associated with the clock, this function is simply a wrapper
191239281Sgonzo *	around that.
192239281Sgonzo *
193239281Sgonzo *	LOCKING:
194239281Sgonzo *	Internally locks the driver context.
195239281Sgonzo *
196239281Sgonzo *	RETURNS:
197239281Sgonzo *	Returns 0 on success or positive error code on failure.
198239281Sgonzo */
199239281Sgonzoint
200239281Sgonzoti_prcm_clk_disable(clk_ident_t clk)
201239281Sgonzo{
202239281Sgonzo	struct ti_clock_dev *clk_dev;
203239281Sgonzo	int ret;
204239281Sgonzo
205239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
206239281Sgonzo	 * loop for this, but this function should only called when a driver is
207239281Sgonzo	 * being activated so IMHO not a big issue.
208239281Sgonzo	 */
209239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
210239281Sgonzo
211239281Sgonzo	/* Sanity check we managed to find the clock */
212239281Sgonzo	if (clk_dev == NULL)
213239281Sgonzo		return (EINVAL);
214239281Sgonzo
215239281Sgonzo	/* Activate the clock */
216239281Sgonzo	if (clk_dev->clk_deactivate)
217239281Sgonzo		ret = clk_dev->clk_deactivate(clk_dev);
218239281Sgonzo	else
219239281Sgonzo		ret = EINVAL;
220239281Sgonzo
221239281Sgonzo	return (ret);
222239281Sgonzo}
223239281Sgonzo
224239281Sgonzo/**
225239281Sgonzo *	ti_prcm_clk_set_source - sets the source
226239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
227239281Sgonzo *	      of possible modules.
228239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
229239281Sgonzo *
230239281Sgonzo *	This function can enable either a functional or interface clock.
231239281Sgonzo *
232239281Sgonzo *	The real work done to enable the clock is really done in the callback
233239281Sgonzo *	function associated with the clock, this function is simply a wrapper
234239281Sgonzo *	around that.
235239281Sgonzo *
236239281Sgonzo *	LOCKING:
237239281Sgonzo *	Internally locks the driver context.
238239281Sgonzo *
239239281Sgonzo *	RETURNS:
240239281Sgonzo *	Returns 0 on success or positive error code on failure.
241239281Sgonzo */
242239281Sgonzoint
243239281Sgonzoti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
244239281Sgonzo{
245239281Sgonzo	struct ti_clock_dev *clk_dev;
246239281Sgonzo	int ret;
247239281Sgonzo
248239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
249239281Sgonzo	 * loop for this, but this function should only called when a driver is
250239281Sgonzo	 * being activated so IMHO not a big issue.
251239281Sgonzo	 */
252239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
253239281Sgonzo
254239281Sgonzo	/* Sanity check we managed to find the clock */
255239281Sgonzo	if (clk_dev == NULL)
256239281Sgonzo		return (EINVAL);
257239281Sgonzo
258239281Sgonzo	/* Activate the clock */
259239281Sgonzo	if (clk_dev->clk_set_source)
260239281Sgonzo		ret = clk_dev->clk_set_source(clk_dev, clksrc);
261239281Sgonzo	else
262239281Sgonzo		ret = EINVAL;
263239281Sgonzo
264239281Sgonzo	return (ret);
265239281Sgonzo}
266239281Sgonzo
267239281Sgonzo
268239281Sgonzo/**
269239281Sgonzo *	ti_prcm_clk_get_source_freq - gets the source clock frequency
270239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
271239281Sgonzo *	      of possible modules.
272239281Sgonzo *	@freq: pointer to an integer that upon return will contain the src freq
273239281Sgonzo *
274239281Sgonzo *	This function returns the frequency of the source clock.
275239281Sgonzo *
276239281Sgonzo *	The real work done to enable the clock is really done in the callback
277239281Sgonzo *	function associated with the clock, this function is simply a wrapper
278239281Sgonzo *	around that.
279239281Sgonzo *
280239281Sgonzo *	LOCKING:
281239281Sgonzo *	Internally locks the driver context.
282239281Sgonzo *
283239281Sgonzo *	RETURNS:
284239281Sgonzo *	Returns 0 on success or positive error code on failure.
285239281Sgonzo */
286239281Sgonzoint
287239281Sgonzoti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
288239281Sgonzo{
289239281Sgonzo	struct ti_clock_dev *clk_dev;
290239281Sgonzo	int ret;
291239281Sgonzo
292239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
293239281Sgonzo	 * loop for this, but this function should only called when a driver is
294239281Sgonzo	 * being activated so IMHO not a big issue.
295239281Sgonzo	 */
296239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
297239281Sgonzo
298239281Sgonzo	/* Sanity check we managed to find the clock */
299239281Sgonzo	if (clk_dev == NULL)
300239281Sgonzo		return (EINVAL);
301239281Sgonzo
302239281Sgonzo	/* Get the source frequency of the clock */
303239281Sgonzo	if (clk_dev->clk_get_source_freq)
304239281Sgonzo		ret = clk_dev->clk_get_source_freq(clk_dev, freq);
305239281Sgonzo	else
306239281Sgonzo		ret = EINVAL;
307239281Sgonzo
308239281Sgonzo	return (ret);
309239281Sgonzo}
310