staging: ti dspbridge: add core driver sources
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / tidspbridge / core / dsp-clock.c
blobabaa5950fb95b93020c379a45217d307846767d4
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 /* ----------------------------------- Host OS */
20 #include <dspbridge/host_os.h>
21 #include <plat/dmtimer.h>
22 #include <plat/mcbsp.h>
24 /* ----------------------------------- DSP/BIOS Bridge */
25 #include <dspbridge/std.h>
26 #include <dspbridge/dbdefs.h>
27 #include <dspbridge/cfg.h>
28 #include <dspbridge/drv.h>
29 #include <dspbridge/dev.h>
30 #include "_tiomap.h"
32 /* ----------------------------------- Trace & Debug */
33 #include <dspbridge/dbc.h>
35 /* ----------------------------------- This */
36 #include <dspbridge/clk.h>
38 /* ----------------------------------- Defines, Data Structures, Typedefs */
40 #define OMAP_SSI_OFFSET 0x58000
41 #define OMAP_SSI_SIZE 0x1000
42 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
44 #define SSI_AUTOIDLE (1 << 0)
45 #define SSI_SIDLE_SMARTIDLE (2 << 3)
46 #define SSI_MIDLE_NOIDLE (1 << 12)
48 /* Clk types requested by the dsp */
49 #define IVA2_CLK 0
50 #define GPT_CLK 1
51 #define WDT_CLK 2
52 #define MCBSP_CLK 3
53 #define SSI_CLK 4
55 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
56 #define DMT_ID(id) ((id) + 4)
58 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
59 #define MCBSP_ID(id) ((id) - 6)
61 static struct omap_dm_timer *timer[4];
63 struct clk *iva2_clk;
65 struct dsp_ssi {
66 struct clk *sst_fck;
67 struct clk *ssr_fck;
68 struct clk *ick;
71 static struct dsp_ssi ssi;
73 static u32 dsp_clocks;
75 static inline u32 is_dsp_clk_active(u32 clk, u8 id)
77 return clk & (1 << id);
80 static inline void set_dsp_clk_active(u32 *clk, u8 id)
82 *clk |= (1 << id);
85 static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
87 *clk &= ~(1 << id);
90 static s8 get_clk_type(u8 id)
92 s8 type;
94 if (id == DSP_CLK_IVA2)
95 type = IVA2_CLK;
96 else if (id <= DSP_CLK_GPT8)
97 type = GPT_CLK;
98 else if (id == DSP_CLK_WDT3)
99 type = WDT_CLK;
100 else if (id <= DSP_CLK_MCBSP5)
101 type = MCBSP_CLK;
102 else if (id == DSP_CLK_SSI)
103 type = SSI_CLK;
104 else
105 type = -1;
107 return type;
111 * ======== dsp_clk_exit ========
112 * Purpose:
113 * Cleanup CLK module.
115 void dsp_clk_exit(void)
117 dsp_clock_disable_all(dsp_clocks);
119 clk_put(iva2_clk);
120 clk_put(ssi.sst_fck);
121 clk_put(ssi.ssr_fck);
122 clk_put(ssi.ick);
126 * ======== dsp_clk_init ========
127 * Purpose:
128 * Initialize CLK module.
130 void dsp_clk_init(void)
132 static struct platform_device dspbridge_device;
134 dspbridge_device.dev.bus = &platform_bus_type;
136 iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
137 if (IS_ERR(iva2_clk))
138 dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
140 ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
141 ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
142 ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
144 if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
145 dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
146 ssi.sst_fck, ssi.ssr_fck, ssi.ick);
149 #ifdef CONFIG_OMAP_MCBSP
150 static void mcbsp_clk_prepare(bool flag, u8 id)
152 struct cfg_hostres *resources;
153 struct dev_object *hdev_object = NULL;
154 struct bridge_dev_context *bridge_context = NULL;
155 u32 val;
157 hdev_object = (struct dev_object *)drv_get_first_dev_object();
158 if (!hdev_object)
159 return;
161 dev_get_bridge_context(hdev_object, &bridge_context);
162 if (!bridge_context)
163 return;
165 resources = bridge_context->resources;
166 if (!resources)
167 return;
169 if (flag) {
170 if (id == DSP_CLK_MCBSP1) {
171 /* set MCBSP1_CLKS, on McBSP1 ON */
172 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
173 val |= 1 << 2;
174 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
175 } else if (id == DSP_CLK_MCBSP2) {
176 /* set MCBSP2_CLKS, on McBSP2 ON */
177 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
178 val |= 1 << 6;
179 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
181 } else {
182 if (id == DSP_CLK_MCBSP1) {
183 /* clear MCBSP1_CLKS, on McBSP1 OFF */
184 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
185 val &= ~(1 << 2);
186 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
187 } else if (id == DSP_CLK_MCBSP2) {
188 /* clear MCBSP2_CLKS, on McBSP2 OFF */
189 val = __raw_readl(resources->dw_sys_ctrl_base + 0x274);
190 val &= ~(1 << 6);
191 __raw_writel(val, resources->dw_sys_ctrl_base + 0x274);
195 #endif
198 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
199 * @clk_id: GP Timer clock id.
200 * @load: Overflow value.
202 * Sets an overflow interrupt for the desired GPT waiting for a timeout
203 * of 5 msecs for the interrupt to occur.
205 void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
207 struct omap_dm_timer *gpt = timer[clk_id - 1];
208 unsigned long timeout;
210 if (!gpt)
211 return;
213 /* Enable overflow interrupt */
214 omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
217 * Set counter value to overflow counter after
218 * one tick and start timer.
220 omap_dm_timer_set_load_start(gpt, 0, load);
222 /* Wait 80us for timer to overflow */
223 udelay(80);
225 timeout = msecs_to_jiffies(5);
226 /* Check interrupt status and wait for interrupt */
227 while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
228 if (time_is_after_jiffies(timeout)) {
229 pr_err("%s: GPTimer interrupt failed\n", __func__);
230 break;
236 * ======== dsp_clk_enable ========
237 * Purpose:
238 * Enable Clock .
241 int dsp_clk_enable(IN enum dsp_clk_id clk_id)
243 int status = 0;
245 if (is_dsp_clk_active(dsp_clocks, clk_id)) {
246 dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
247 goto out;
250 switch (get_clk_type(clk_id)) {
251 case IVA2_CLK:
252 clk_enable(iva2_clk);
253 break;
254 case GPT_CLK:
255 timer[clk_id - 1] =
256 omap_dm_timer_request_specific(DMT_ID(clk_id));
257 break;
258 #ifdef CONFIG_OMAP_MCBSP
259 case MCBSP_CLK:
260 mcbsp_clk_prepare(true, clk_id);
261 omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
262 omap_mcbsp_request(MCBSP_ID(clk_id));
263 break;
264 #endif
265 case WDT_CLK:
266 dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
267 break;
268 case SSI_CLK:
269 clk_enable(ssi.sst_fck);
270 clk_enable(ssi.ssr_fck);
271 clk_enable(ssi.ick);
274 * The SSI module need to configured not to have the Forced
275 * idle for master interface. If it is set to forced idle,
276 * the SSI module is transitioning to standby thereby causing
277 * the client in the DSP hang waiting for the SSI module to
278 * be active after enabling the clocks
280 ssi_clk_prepare(true);
281 break;
282 default:
283 dev_err(bridge, "Invalid clock id for enable\n");
284 status = -EPERM;
287 if (DSP_SUCCEEDED(status))
288 set_dsp_clk_active(&dsp_clocks, clk_id);
290 out:
291 return status;
295 * dsp_clock_enable_all - Enable clocks used by the DSP
296 * @dev_context Driver's device context strucure
298 * This function enables all the peripheral clocks that were requested by DSP.
300 u32 dsp_clock_enable_all(u32 dsp_per_clocks)
302 u32 clk_id;
303 u32 status = -EPERM;
305 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
306 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
307 status = dsp_clk_enable(clk_id);
310 return status;
314 * ======== dsp_clk_disable ========
315 * Purpose:
316 * Disable the clock.
319 int dsp_clk_disable(IN enum dsp_clk_id clk_id)
321 int status = 0;
323 if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
324 dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
325 goto out;
328 switch (get_clk_type(clk_id)) {
329 case IVA2_CLK:
330 clk_disable(iva2_clk);
331 break;
332 case GPT_CLK:
333 omap_dm_timer_free(timer[clk_id - 1]);
334 break;
335 #ifdef CONFIG_OMAP_MCBSP
336 case MCBSP_CLK:
337 mcbsp_clk_prepare(false, clk_id);
338 omap_mcbsp_free(MCBSP_ID(clk_id));
339 break;
340 #endif
341 case WDT_CLK:
342 dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
343 break;
344 case SSI_CLK:
345 ssi_clk_prepare(false);
346 ssi_clk_prepare(false);
347 clk_disable(ssi.sst_fck);
348 clk_disable(ssi.ssr_fck);
349 clk_disable(ssi.ick);
350 break;
351 default:
352 dev_err(bridge, "Invalid clock id for disable\n");
353 status = -EPERM;
356 if (DSP_SUCCEEDED(status))
357 set_dsp_clk_inactive(&dsp_clocks, clk_id);
359 out:
360 return status;
364 * dsp_clock_disable_all - Disable all active clocks
365 * @dev_context Driver's device context structure
367 * This function disables all the peripheral clocks that were enabled by DSP.
368 * It is meant to be called only when DSP is entering hibernation or when DSP
369 * is in error state.
371 u32 dsp_clock_disable_all(u32 dsp_per_clocks)
373 u32 clk_id;
374 u32 status = -EPERM;
376 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
377 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
378 status = dsp_clk_disable(clk_id);
381 return status;
384 u32 dsp_clk_get_iva2_rate(void)
386 u32 clk_speed_khz;
388 clk_speed_khz = clk_get_rate(iva2_clk);
389 clk_speed_khz /= 1000;
390 dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
392 return clk_speed_khz;
395 void ssi_clk_prepare(bool FLAG)
397 void __iomem *ssi_base;
398 unsigned int value;
400 ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
401 if (!ssi_base) {
402 pr_err("%s: error, SSI not configured\n", __func__);
403 return;
406 if (FLAG) {
407 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
408 * no idle
410 value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
411 } else {
412 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
413 * forced idle
415 value = SSI_AUTOIDLE;
418 __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
419 iounmap(ssi_base);