Merge branches 'for-3.7/upstream-fixes', 'for-3.8/hidraw', 'for-3.8/i2c-hid', 'for...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / tidspbridge / core / dsp-clock.c
1 /*
2 * clk.c
3 *
4 * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5 *
6 * Clock and Timer services.
7 *
8 * Copyright (C) 2005-2006 Texas Instruments, Inc.
9 *
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.
13 *
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.
17 */
18
19 #define L4_34XX_BASE 0x48000000
20
21 #include <linux/types.h>
22
23 /* ----------------------------------- Host OS */
24 #include <dspbridge/host_os.h>
25 #include <plat/dmtimer.h>
26 #include <linux/platform_data/asoc-ti-mcbsp.h>
27
28 /* ----------------------------------- DSP/BIOS Bridge */
29 #include <dspbridge/dbdefs.h>
30 #include <dspbridge/drv.h>
31 #include <dspbridge/dev.h>
32 #include "_tiomap.h"
33
34 /* ----------------------------------- This */
35 #include <dspbridge/clk.h>
36
37 /* ----------------------------------- Defines, Data Structures, Typedefs */
38
39 #define OMAP_SSI_OFFSET 0x58000
40 #define OMAP_SSI_SIZE 0x1000
41 #define OMAP_SSI_SYSCONFIG_OFFSET 0x10
42
43 #define SSI_AUTOIDLE (1 << 0)
44 #define SSI_SIDLE_SMARTIDLE (2 << 3)
45 #define SSI_MIDLE_NOIDLE (1 << 12)
46
47 /* Clk types requested by the dsp */
48 #define IVA2_CLK 0
49 #define GPT_CLK 1
50 #define WDT_CLK 2
51 #define MCBSP_CLK 3
52 #define SSI_CLK 4
53
54 /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */
55 #define DMT_ID(id) ((id) + 4)
56 #define DM_TIMER_CLOCKS 4
57
58 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */
59 #define MCBSP_ID(id) ((id) - 6)
60
61 static struct omap_dm_timer *timer[4];
62
63 struct clk *iva2_clk;
64
65 struct dsp_ssi {
66 struct clk *sst_fck;
67 struct clk *ssr_fck;
68 struct clk *ick;
69 };
70
71 static struct dsp_ssi ssi;
72
73 static u32 dsp_clocks;
74
75 static inline u32 is_dsp_clk_active(u32 clk, u8 id)
76 {
77 return clk & (1 << id);
78 }
79
80 static inline void set_dsp_clk_active(u32 *clk, u8 id)
81 {
82 *clk |= (1 << id);
83 }
84
85 static inline void set_dsp_clk_inactive(u32 *clk, u8 id)
86 {
87 *clk &= ~(1 << id);
88 }
89
90 static s8 get_clk_type(u8 id)
91 {
92 s8 type;
93
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;
106
107 return type;
108 }
109
110 /*
111 * ======== dsp_clk_exit ========
112 * Purpose:
113 * Cleanup CLK module.
114 */
115 void dsp_clk_exit(void)
116 {
117 int i;
118
119 dsp_clock_disable_all(dsp_clocks);
120
121 for (i = 0; i < DM_TIMER_CLOCKS; i++)
122 omap_dm_timer_free(timer[i]);
123
124 clk_put(iva2_clk);
125 clk_put(ssi.sst_fck);
126 clk_put(ssi.ssr_fck);
127 clk_put(ssi.ick);
128 }
129
130 /*
131 * ======== dsp_clk_init ========
132 * Purpose:
133 * Initialize CLK module.
134 */
135 void dsp_clk_init(void)
136 {
137 static struct platform_device dspbridge_device;
138 int i, id;
139
140 dspbridge_device.dev.bus = &platform_bus_type;
141
142 for (i = 0, id = 5; i < DM_TIMER_CLOCKS; i++, id++)
143 timer[i] = omap_dm_timer_request_specific(id);
144
145 iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck");
146 if (IS_ERR(iva2_clk))
147 dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk);
148
149 ssi.sst_fck = clk_get(&dspbridge_device.dev, "ssi_sst_fck");
150 ssi.ssr_fck = clk_get(&dspbridge_device.dev, "ssi_ssr_fck");
151 ssi.ick = clk_get(&dspbridge_device.dev, "ssi_ick");
152
153 if (IS_ERR(ssi.sst_fck) || IS_ERR(ssi.ssr_fck) || IS_ERR(ssi.ick))
154 dev_err(bridge, "failed to get ssi: sst %p, ssr %p, ick %p\n",
155 ssi.sst_fck, ssi.ssr_fck, ssi.ick);
156 }
157
158 /**
159 * dsp_gpt_wait_overflow - set gpt overflow and wait for fixed timeout
160 * @clk_id: GP Timer clock id.
161 * @load: Overflow value.
162 *
163 * Sets an overflow interrupt for the desired GPT waiting for a timeout
164 * of 5 msecs for the interrupt to occur.
165 */
166 void dsp_gpt_wait_overflow(short int clk_id, unsigned int load)
167 {
168 struct omap_dm_timer *gpt = timer[clk_id - 1];
169 unsigned long timeout;
170
171 if (!gpt)
172 return;
173
174 /* Enable overflow interrupt */
175 omap_dm_timer_set_int_enable(gpt, OMAP_TIMER_INT_OVERFLOW);
176
177 /*
178 * Set counter value to overflow counter after
179 * one tick and start timer.
180 */
181 omap_dm_timer_set_load_start(gpt, 0, load);
182
183 /* Wait 80us for timer to overflow */
184 udelay(80);
185
186 timeout = msecs_to_jiffies(5);
187 /* Check interrupt status and wait for interrupt */
188 while (!(omap_dm_timer_read_status(gpt) & OMAP_TIMER_INT_OVERFLOW)) {
189 if (time_is_after_jiffies(timeout)) {
190 pr_err("%s: GPTimer interrupt failed\n", __func__);
191 break;
192 }
193 }
194 }
195
196 /*
197 * ======== dsp_clk_enable ========
198 * Purpose:
199 * Enable Clock .
200 *
201 */
202 int dsp_clk_enable(enum dsp_clk_id clk_id)
203 {
204 int status = 0;
205
206 if (is_dsp_clk_active(dsp_clocks, clk_id)) {
207 dev_err(bridge, "WARN: clock id %d already enabled\n", clk_id);
208 goto out;
209 }
210
211 switch (get_clk_type(clk_id)) {
212 case IVA2_CLK:
213 clk_enable(iva2_clk);
214 break;
215 case GPT_CLK:
216 status = omap_dm_timer_start(timer[clk_id - 1]);
217 break;
218 #ifdef CONFIG_OMAP_MCBSP
219 case MCBSP_CLK:
220 omap_mcbsp_request(MCBSP_ID(clk_id));
221 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
222 break;
223 #endif
224 case WDT_CLK:
225 dev_err(bridge, "ERROR: DSP requested to enable WDT3 clk\n");
226 break;
227 case SSI_CLK:
228 clk_enable(ssi.sst_fck);
229 clk_enable(ssi.ssr_fck);
230 clk_enable(ssi.ick);
231
232 /*
233 * The SSI module need to configured not to have the Forced
234 * idle for master interface. If it is set to forced idle,
235 * the SSI module is transitioning to standby thereby causing
236 * the client in the DSP hang waiting for the SSI module to
237 * be active after enabling the clocks
238 */
239 ssi_clk_prepare(true);
240 break;
241 default:
242 dev_err(bridge, "Invalid clock id for enable\n");
243 status = -EPERM;
244 }
245
246 if (!status)
247 set_dsp_clk_active(&dsp_clocks, clk_id);
248
249 out:
250 return status;
251 }
252
253 /**
254 * dsp_clock_enable_all - Enable clocks used by the DSP
255 * @dev_context Driver's device context strucure
256 *
257 * This function enables all the peripheral clocks that were requested by DSP.
258 */
259 u32 dsp_clock_enable_all(u32 dsp_per_clocks)
260 {
261 u32 clk_id;
262 u32 status = -EPERM;
263
264 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
265 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
266 status = dsp_clk_enable(clk_id);
267 }
268
269 return status;
270 }
271
272 /*
273 * ======== dsp_clk_disable ========
274 * Purpose:
275 * Disable the clock.
276 *
277 */
278 int dsp_clk_disable(enum dsp_clk_id clk_id)
279 {
280 int status = 0;
281
282 if (!is_dsp_clk_active(dsp_clocks, clk_id)) {
283 dev_err(bridge, "ERR: clock id %d already disabled\n", clk_id);
284 goto out;
285 }
286
287 switch (get_clk_type(clk_id)) {
288 case IVA2_CLK:
289 clk_disable(iva2_clk);
290 break;
291 case GPT_CLK:
292 status = omap_dm_timer_stop(timer[clk_id - 1]);
293 break;
294 #ifdef CONFIG_OMAP_MCBSP
295 case MCBSP_CLK:
296 omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PRCM_SRC);
297 omap_mcbsp_free(MCBSP_ID(clk_id));
298 break;
299 #endif
300 case WDT_CLK:
301 dev_err(bridge, "ERROR: DSP requested to disable WDT3 clk\n");
302 break;
303 case SSI_CLK:
304 ssi_clk_prepare(false);
305 ssi_clk_prepare(false);
306 clk_disable(ssi.sst_fck);
307 clk_disable(ssi.ssr_fck);
308 clk_disable(ssi.ick);
309 break;
310 default:
311 dev_err(bridge, "Invalid clock id for disable\n");
312 status = -EPERM;
313 }
314
315 if (!status)
316 set_dsp_clk_inactive(&dsp_clocks, clk_id);
317
318 out:
319 return status;
320 }
321
322 /**
323 * dsp_clock_disable_all - Disable all active clocks
324 * @dev_context Driver's device context structure
325 *
326 * This function disables all the peripheral clocks that were enabled by DSP.
327 * It is meant to be called only when DSP is entering hibernation or when DSP
328 * is in error state.
329 */
330 u32 dsp_clock_disable_all(u32 dsp_per_clocks)
331 {
332 u32 clk_id;
333 u32 status = -EPERM;
334
335 for (clk_id = 0; clk_id < DSP_CLK_NOT_DEFINED; clk_id++) {
336 if (is_dsp_clk_active(dsp_per_clocks, clk_id))
337 status = dsp_clk_disable(clk_id);
338 }
339
340 return status;
341 }
342
343 u32 dsp_clk_get_iva2_rate(void)
344 {
345 u32 clk_speed_khz;
346
347 clk_speed_khz = clk_get_rate(iva2_clk);
348 clk_speed_khz /= 1000;
349 dev_dbg(bridge, "%s: clk speed Khz = %d\n", __func__, clk_speed_khz);
350
351 return clk_speed_khz;
352 }
353
354 void ssi_clk_prepare(bool FLAG)
355 {
356 void __iomem *ssi_base;
357 unsigned int value;
358
359 ssi_base = ioremap(L4_34XX_BASE + OMAP_SSI_OFFSET, OMAP_SSI_SIZE);
360 if (!ssi_base) {
361 pr_err("%s: error, SSI not configured\n", __func__);
362 return;
363 }
364
365 if (FLAG) {
366 /* Set Autoidle, SIDLEMode to smart idle, and MIDLEmode to
367 * no idle
368 */
369 value = SSI_AUTOIDLE | SSI_SIDLE_SMARTIDLE | SSI_MIDLE_NOIDLE;
370 } else {
371 /* Set Autoidle, SIDLEMode to forced idle, and MIDLEmode to
372 * forced idle
373 */
374 value = SSI_AUTOIDLE;
375 }
376
377 __raw_writel(value, ssi_base + OMAP_SSI_SYSCONFIG_OFFSET);
378 iounmap(ssi_base);
379 }
380