GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / tidspbridge / core / dsp-clock.c
blob6f73a094d690fe978937ecc350b752163e5229c2
1 /*
2 * clk.c
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
6 * Clock and Timer services.
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
10 * This package is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 #include <linux/types.h>
21 /* ----------------------------------- Host OS */
22 #include <dspbridge/host_os.h>
23 #include <plat/dmtimer.h>
24 #include <plat/mcbsp.h>
26 /* ----------------------------------- DSP/BIOS Bridge */
27 #include <dspbridge/dbdefs.h>
28 #include <dspbridge/cfg.h>
29 #include <dspbridge/drv.h>
30 #include <dspbridge/dev.h>
31 #include "_tiomap.h"
33 /* ----------------------------------- Trace & Debug */
34 #include <dspbridge/dbc.h>
36 /* ----------------------------------- This */
37 #include <dspbridge/clk.h>
39 /* ----------------------------------- Defines, Data Structures, Typedefs */
41 #define OMAP_SSI_OFFSET 0x58000
42 #define OMAP_SSI_SIZE 0x1000
43 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
45 #define SSI_AUTOIDLE (1 << 0)
46 #define SSI_SIDLE_SMARTIDLE (2 << 3)
47 #define SSI_MIDLE_NOIDLE (1 << 12)
49 /* Clk types requested by the dsp */
50 #define IVA2_CLK 0
51 #define GPT_CLK 1
52 #define WDT_CLK 2
53 #define MCBSP_CLK 3
54 #define SSI_CLK 4
56 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
57 #define DMT_ID(id) ((id) + 4)
59 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
60 #define MCBSP_ID(id) ((id) - 6)
62 static struct omap_dm_timer *timer[4];
64 struct clk *iva2_clk;
66 struct dsp_ssi {
67 struct clk *sst_fck;
68 struct clk *ssr_fck;
69 struct clk *ick;
72 static struct dsp_ssi ssi;
74 static u32 dsp_clocks;
76 static inline u32 is_dsp_clk_active(u32 clk, u8 id)
78 return clk & (1 << id);
81 static inline void set_dsp_clk_active(u32 *clk, u8 id)
83 *clk |= (1 << id);
86 static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
88 *clk &= ~(1 << id);
91 static s8 get_clk_type(u8 id)
93 s8 type;
95 if (id == DSP_CLK_IVA2)
96 type = IVA2_CLK;
97 else if (id <= DSP_CLK_GPT8)
98 type = GPT_CLK;
99 else if (id == DSP_CLK_WDT3)
100 type = WDT_CLK;
101 else if (id <= DSP_CLK_MCBSP5)
102 type = MCBSP_CLK;
103 else if (id == DSP_CLK_SSI)
104 type = SSI_CLK;
105 else
106 type = -1;
108 return type;
112 * ======== dsp_clk_exit ========
113 * Purpose:
114 * Cleanup CLK module.
116 void dsp_clk_exit(void)
118 dsp_clock_disable_all(dsp_clocks);
120 clk_put(iva2_clk);
121 clk_put(ssi.sst_fck);
122 clk_put(ssi.ssr_fck);
123 clk_put(ssi.ick);
127 * ======== dsp_clk_init ========
128 * Purpose:
129 * Initialize CLK module.
131 void dsp_clk_init(void)
133 static struct platform_device dspbridge_device;
135 dspbridge_device.dev.bus = &platform_bus_type;
137 iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
138 if (IS_ERR(iva2_clk))
139 dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
141 ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
142 ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
143 ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
145 if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
146 dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
147 ssi.sst_fck, ssi.ssr_fck, ssi.ick);
150 #ifdef CONFIG_OMAP_MCBSP
151 static void mcbsp_clk_prepare(bool flag, u8 id)
153 struct cfg_hostres *resources;
154 struct dev_object *hdev_object = NULL;
155 struct bridge_dev_context *bridge_context = NULL;
156 u32 val;
158 hdev_object = (struct dev_object *)drv_get_first_dev_object();
159 if (!hdev_object)
160 return;
162 dev_get_bridge_context(hdev_object, &bridge_context);
163 if (!bridge_context)
164 return;
166 resources = bridge_context->resources;
167 if (!resources)
168 return;
170 if (flag) {
171 if (id == DSP_CLK_MCBSP1) {
172 /* set MCBSP1_CLKS, on McBSP1 ON */
173 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
174 val |= 1 << 2;
175 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
176 } else if (id == DSP_CLK_MCBSP2) {
177 /* set MCBSP2_CLKS, on McBSP2 ON */
178 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
179 val |= 1 << 6;
180 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
182 } else {
183 if (id == DSP_CLK_MCBSP1) {
184 /* clear MCBSP1_CLKS, on McBSP1 OFF */
185 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
186 val &= ~(1 << 2);
187 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
188 } else if (id == DSP_CLK_MCBSP2) {
189 /* clear MCBSP2_CLKS, on McBSP2 OFF */
190 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
191 val &= ~(1 << 6);
192 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
196 #endif
199 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
200 * @clk_id: GP Timer clock id.
201 * @load: Overflow value.
203 * Sets an overflow interrupt for the desired GPT waiting for a timeout
204 * of 5 msecs for the interrupt to occur.
206 void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
208 struct omap_dm_timer *gpt = timer[clk_id - 1];
209 unsigned long timeout;
211 if (!gpt)
212 return;
214 /* Enable overflow interrupt */
215 omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
218 * Set counter value to overflow counter after
219 * one tick and start timer.
221 omap_dm_timer_set_load_start(gpt, 0, load);
223 /* Wait 80us for timer to overflow */
224 udelay(80);
226 timeout = msecs_to_jiffies(5);
227 /* Check interrupt status and wait for interrupt */
228 while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
229 if (time_is_after_jiffies(timeout)) {
230 pr_err("%s: GPTimer interrupt failed\n", __func__);
231 break;
237 * ======== dsp_clk_enable ========
238 * Purpose:
239 * Enable Clock .
242 int dsp_clk_enable(enum dsp_clk_id clk_id)
244 int status = 0;
246 if (is_dsp_clk_active(dsp_clocks, clk_id)) {
247 dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
248 goto out;
251 switch (get_clk_type(clk_id)) {
252 case IVA2_CLK:
253 clk_enable(iva2_clk);
254 break;
255 case GPT_CLK:
256 timer[clk_id - 1] =
257 omap_dm_timer_request_specific(DMT_ID(clk_id));
258 break;
259 #ifdef CONFIG_OMAP_MCBSP
260 case MCBSP_CLK:
261 mcbsp_clk_prepare(true, clk_id);
262 omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
263 omap_mcbsp_request(MCBSP_ID(clk_id));
264 break;
265 #endif
266 case WDT_CLK:
267 dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
268 break;
269 case SSI_CLK:
270 clk_enable(ssi.sst_fck);
271 clk_enable(ssi.ssr_fck);
272 clk_enable(ssi.ick);
275 * The SSI module need to configured not to have the Forced
276 * idle for master interface. If it is set to forced idle,
277 * the SSI module is transitioning to standby thereby causing
278 * the client in the DSP hang waiting for the SSI module to
279 * be active after enabling the clocks
281 ssi_clk_prepare(true);
282 break;
283 default:
284 dev_err(bridge, "Invalid clock id for enable\n");
285 status = -EPERM;
288 if (!status)
289 set_dsp_clk_active(&dsp_clocks, clk_id);
291 out:
292 return status;
296 * dsp_clock_enable_all - Enable clocks used by the DSP
297 * @dev_context Driver's device context strucure
299 * This function enables all the peripheral clocks that were requested by DSP.
301 u32 dsp_clock_enable_all(u32 dsp_per_clocks)
303 u32 clk_id;
304 u32 status = -EPERM;
306 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
307 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
308 status = dsp_clk_enable(clk_id);
311 return status;
315 * ======== dsp_clk_disable ========
316 * Purpose:
317 * Disable the clock.
320 int dsp_clk_disable(enum dsp_clk_id clk_id)
322 int status = 0;
324 if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
325 dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
326 goto out;
329 switch (get_clk_type(clk_id)) {
330 case IVA2_CLK:
331 clk_disable(iva2_clk);
332 break;
333 case GPT_CLK:
334 omap_dm_timer_free(timer[clk_id - 1]);
335 break;
336 #ifdef CONFIG_OMAP_MCBSP
337 case MCBSP_CLK:
338 mcbsp_clk_prepare(false, clk_id);
339 omap_mcbsp_free(MCBSP_ID(clk_id));
340 break;
341 #endif
342 case WDT_CLK:
343 dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
344 break;
345 case SSI_CLK:
346 ssi_clk_prepare(false);
347 ssi_clk_prepare(false);
348 clk_disable(ssi.sst_fck);
349 clk_disable(ssi.ssr_fck);
350 clk_disable(ssi.ick);
351 break;
352 default:
353 dev_err(bridge, "Invalid clock id for disable\n");
354 status = -EPERM;
357 if (!status)
358 set_dsp_clk_inactive(&dsp_clocks, clk_id);
360 out:
361 return status;
365 * dsp_clock_disable_all - Disable all active clocks
366 * @dev_context Driver's device context structure
368 * This function disables all the peripheral clocks that were enabled by DSP.
369 * It is meant to be called only when DSP is entering hibernation or when DSP
370 * is in error state.
372 u32 dsp_clock_disable_all(u32 dsp_per_clocks)
374 u32 clk_id;
375 u32 status = -EPERM;
377 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
378 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
379 status = dsp_clk_disable(clk_id);
382 return status;
385 u32 dsp_clk_get_iva2_rate(void)
387 u32 clk_speed_khz;
389 clk_speed_khz = clk_get_rate(iva2_clk);
390 clk_speed_khz /= 1000;
391 dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
393 return clk_speed_khz;
396 void ssi_clk_prepare(bool FLAG)
398 void __iomem *ssi_base;
399 unsigned int value;
401 ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
402 if (!ssi_base) {
403 pr_err("%s: error, SSI not configured\n", __func__);
404 return;
407 if (FLAG) {
408 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
409 * no idle
411 value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
412 } else {
413 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
414 * forced idle
416 value = SSI_AUTOIDLE;
419 __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
420 iounmap(ssi_base);