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: releng/10.2/sys/arm/ti/ti_prcm.c 259329 2013-12-13 20:43:11Z ian $");
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/resource.h>
58239281Sgonzo#include <machine/intr.h>
59239281Sgonzo
60239281Sgonzo#include <arm/ti/ti_prcm.h>
61239281Sgonzo
62239281Sgonzo/**
63239281Sgonzo *	ti_clk_devmap - Array of clock devices, should be defined one per SoC
64239281Sgonzo *
65239281Sgonzo *	This array is typically defined in one of the targeted *_prcm_clk.c
66239281Sgonzo *	files and is specific to the given SoC platform.  Each entry in the array
67239281Sgonzo *	corresponds to an individual clock device.
68239281Sgonzo */
69239281Sgonzoextern struct ti_clock_dev ti_clk_devmap[];
70239281Sgonzo
71239281Sgonzo/**
72239281Sgonzo *	ti_prcm_clk_dev - returns a pointer to the clock device with given id
73239281Sgonzo *	@clk: the ID of the clock device to get
74239281Sgonzo *
75239281Sgonzo *	Simply iterates through the clk_devmap global array and returns a pointer
76239281Sgonzo *	to the clock device if found.
77239281Sgonzo *
78239281Sgonzo *	LOCKING:
79239281Sgonzo *	None
80239281Sgonzo *
81239281Sgonzo *	RETURNS:
82239281Sgonzo *	The pointer to the clock device on success, on failure NULL is returned.
83239281Sgonzo */
84239281Sgonzostatic struct ti_clock_dev *
85239281Sgonzoti_prcm_clk_dev(clk_ident_t clk)
86239281Sgonzo{
87239281Sgonzo	struct ti_clock_dev *clk_dev;
88239281Sgonzo
89239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
90239281Sgonzo	 * loop for this, but this function should only called when a driver is
91239281Sgonzo	 * being activated so IMHO not a big issue.
92239281Sgonzo	 */
93239281Sgonzo	clk_dev = &(ti_clk_devmap[0]);
94239281Sgonzo	while (clk_dev->id != INVALID_CLK_IDENT) {
95239281Sgonzo		if (clk_dev->id == clk) {
96239281Sgonzo			return (clk_dev);
97239281Sgonzo		}
98239281Sgonzo		clk_dev++;
99239281Sgonzo	}
100239281Sgonzo
101239281Sgonzo	/* Sanity check we managed to find the clock */
102239281Sgonzo	printf("ti_prcm: Failed to find clock device (%d)\n", clk);
103239281Sgonzo	return (NULL);
104239281Sgonzo}
105239281Sgonzo
106239281Sgonzo/**
107239281Sgonzo *	ti_prcm_clk_valid - enables a clock for a particular module
108239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
109239281Sgonzo *	      of possible modules.
110239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
111239281Sgonzo *
112239281Sgonzo *	This function can enable either a functional or interface clock.
113239281Sgonzo *
114239281Sgonzo *	The real work done to enable the clock is really done in the callback
115239281Sgonzo *	function associated with the clock, this function is simply a wrapper
116239281Sgonzo *	around that.
117239281Sgonzo *
118239281Sgonzo *	LOCKING:
119239281Sgonzo *	Internally locks the driver context.
120239281Sgonzo *
121239281Sgonzo *	RETURNS:
122239281Sgonzo *	Returns 0 on success or positive error code on failure.
123239281Sgonzo */
124239281Sgonzoint
125239281Sgonzoti_prcm_clk_valid(clk_ident_t clk)
126239281Sgonzo{
127239281Sgonzo	int ret = 0;
128239281Sgonzo
129239281Sgonzo	if (ti_prcm_clk_dev(clk) == NULL)
130239281Sgonzo		ret = EINVAL;
131239281Sgonzo
132239281Sgonzo	return (ret);
133239281Sgonzo}
134239281Sgonzo
135239281Sgonzo
136239281Sgonzo/**
137239281Sgonzo *	ti_prcm_clk_enable - enables a clock for a particular module
138239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
139239281Sgonzo *	      of possible modules.
140239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
141239281Sgonzo *
142239281Sgonzo *	This function can enable either a functional or interface clock.
143239281Sgonzo *
144239281Sgonzo *	The real work done to enable the clock is really done in the callback
145239281Sgonzo *	function associated with the clock, this function is simply a wrapper
146239281Sgonzo *	around that.
147239281Sgonzo *
148239281Sgonzo *	LOCKING:
149239281Sgonzo *	Internally locks the driver context.
150239281Sgonzo *
151239281Sgonzo *	RETURNS:
152239281Sgonzo *	Returns 0 on success or positive error code on failure.
153239281Sgonzo */
154239281Sgonzoint
155239281Sgonzoti_prcm_clk_enable(clk_ident_t clk)
156239281Sgonzo{
157239281Sgonzo	struct ti_clock_dev *clk_dev;
158239281Sgonzo	int ret;
159239281Sgonzo
160239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
161239281Sgonzo	 * loop for this, but this function should only called when a driver is
162239281Sgonzo	 * being activated so IMHO not a big issue.
163239281Sgonzo	 */
164239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
165239281Sgonzo
166239281Sgonzo	/* Sanity check we managed to find the clock */
167239281Sgonzo	if (clk_dev == NULL)
168239281Sgonzo		return (EINVAL);
169239281Sgonzo
170239281Sgonzo	/* Activate the clock */
171239281Sgonzo	if (clk_dev->clk_activate)
172239281Sgonzo		ret = clk_dev->clk_activate(clk_dev);
173239281Sgonzo	else
174239281Sgonzo		ret = EINVAL;
175239281Sgonzo
176239281Sgonzo	return (ret);
177239281Sgonzo}
178239281Sgonzo
179239281Sgonzo
180239281Sgonzo/**
181239281Sgonzo *	ti_prcm_clk_disable - disables a clock for a particular module
182239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
183239281Sgonzo *	      of possible modules.
184239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
185239281Sgonzo *
186239281Sgonzo *	This function can enable either a functional or interface clock.
187239281Sgonzo *
188239281Sgonzo *	The real work done to enable the clock is really done in the callback
189239281Sgonzo *	function associated with the clock, this function is simply a wrapper
190239281Sgonzo *	around that.
191239281Sgonzo *
192239281Sgonzo *	LOCKING:
193239281Sgonzo *	Internally locks the driver context.
194239281Sgonzo *
195239281Sgonzo *	RETURNS:
196239281Sgonzo *	Returns 0 on success or positive error code on failure.
197239281Sgonzo */
198239281Sgonzoint
199239281Sgonzoti_prcm_clk_disable(clk_ident_t clk)
200239281Sgonzo{
201239281Sgonzo	struct ti_clock_dev *clk_dev;
202239281Sgonzo	int ret;
203239281Sgonzo
204239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
205239281Sgonzo	 * loop for this, but this function should only called when a driver is
206239281Sgonzo	 * being activated so IMHO not a big issue.
207239281Sgonzo	 */
208239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
209239281Sgonzo
210239281Sgonzo	/* Sanity check we managed to find the clock */
211239281Sgonzo	if (clk_dev == NULL)
212239281Sgonzo		return (EINVAL);
213239281Sgonzo
214239281Sgonzo	/* Activate the clock */
215239281Sgonzo	if (clk_dev->clk_deactivate)
216239281Sgonzo		ret = clk_dev->clk_deactivate(clk_dev);
217239281Sgonzo	else
218239281Sgonzo		ret = EINVAL;
219239281Sgonzo
220239281Sgonzo	return (ret);
221239281Sgonzo}
222239281Sgonzo
223239281Sgonzo/**
224239281Sgonzo *	ti_prcm_clk_set_source - sets the source
225239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
226239281Sgonzo *	      of possible modules.
227239281Sgonzo *	         Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
228239281Sgonzo *
229239281Sgonzo *	This function can enable either a functional or interface clock.
230239281Sgonzo *
231239281Sgonzo *	The real work done to enable the clock is really done in the callback
232239281Sgonzo *	function associated with the clock, this function is simply a wrapper
233239281Sgonzo *	around that.
234239281Sgonzo *
235239281Sgonzo *	LOCKING:
236239281Sgonzo *	Internally locks the driver context.
237239281Sgonzo *
238239281Sgonzo *	RETURNS:
239239281Sgonzo *	Returns 0 on success or positive error code on failure.
240239281Sgonzo */
241239281Sgonzoint
242239281Sgonzoti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
243239281Sgonzo{
244239281Sgonzo	struct ti_clock_dev *clk_dev;
245239281Sgonzo	int ret;
246239281Sgonzo
247239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
248239281Sgonzo	 * loop for this, but this function should only called when a driver is
249239281Sgonzo	 * being activated so IMHO not a big issue.
250239281Sgonzo	 */
251239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
252239281Sgonzo
253239281Sgonzo	/* Sanity check we managed to find the clock */
254239281Sgonzo	if (clk_dev == NULL)
255239281Sgonzo		return (EINVAL);
256239281Sgonzo
257239281Sgonzo	/* Activate the clock */
258239281Sgonzo	if (clk_dev->clk_set_source)
259239281Sgonzo		ret = clk_dev->clk_set_source(clk_dev, clksrc);
260239281Sgonzo	else
261239281Sgonzo		ret = EINVAL;
262239281Sgonzo
263239281Sgonzo	return (ret);
264239281Sgonzo}
265239281Sgonzo
266239281Sgonzo
267239281Sgonzo/**
268239281Sgonzo *	ti_prcm_clk_get_source_freq - gets the source clock frequency
269239281Sgonzo *	@clk: identifier for the module to enable, see ti_prcm.h for a list
270239281Sgonzo *	      of possible modules.
271239281Sgonzo *	@freq: pointer to an integer that upon return will contain the src freq
272239281Sgonzo *
273239281Sgonzo *	This function returns the frequency of the source clock.
274239281Sgonzo *
275239281Sgonzo *	The real work done to enable the clock is really done in the callback
276239281Sgonzo *	function associated with the clock, this function is simply a wrapper
277239281Sgonzo *	around that.
278239281Sgonzo *
279239281Sgonzo *	LOCKING:
280239281Sgonzo *	Internally locks the driver context.
281239281Sgonzo *
282239281Sgonzo *	RETURNS:
283239281Sgonzo *	Returns 0 on success or positive error code on failure.
284239281Sgonzo */
285239281Sgonzoint
286239281Sgonzoti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq)
287239281Sgonzo{
288239281Sgonzo	struct ti_clock_dev *clk_dev;
289239281Sgonzo	int ret;
290239281Sgonzo
291239281Sgonzo	/* Find the clock within the devmap - it's a bit inefficent having a for
292239281Sgonzo	 * loop for this, but this function should only called when a driver is
293239281Sgonzo	 * being activated so IMHO not a big issue.
294239281Sgonzo	 */
295239281Sgonzo	clk_dev = ti_prcm_clk_dev(clk);
296239281Sgonzo
297239281Sgonzo	/* Sanity check we managed to find the clock */
298239281Sgonzo	if (clk_dev == NULL)
299239281Sgonzo		return (EINVAL);
300239281Sgonzo
301239281Sgonzo	/* Get the source frequency of the clock */
302239281Sgonzo	if (clk_dev->clk_get_source_freq)
303239281Sgonzo		ret = clk_dev->clk_get_source_freq(clk_dev, freq);
304239281Sgonzo	else
305239281Sgonzo		ret = EINVAL;
306239281Sgonzo
307239281Sgonzo	return (ret);
308239281Sgonzo}
309