asoc: tegra: WAR: Check AVP id before setting DMA
[linux-2.6.git] / sound / soc / tegra / tegra_asoc_utils.c
1 /*
2  * tegra_asoc_utils.c - Harmony machine ASoC driver
3  *
4  * Author: Stephen Warren <swarren@nvidia.com>
5  * Copyright (c) 2010-12, NVIDIA CORPORATION. All rights reserved.
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  */
21
22 #include <linux/clk.h>
23 #include <linux/device.h>
24 #include <linux/err.h>
25 #include <linux/kernel.h>
26
27 #include <mach/clk.h>
28
29 #include <sound/soc.h>
30
31 #include "tegra_pcm.h"
32 #include "tegra_asoc_utils.h"
33
34 int g_is_call_mode;
35
36 bool tegra_is_voice_call_active(void)
37 {
38         if (g_is_call_mode)
39                 return true;
40         else
41                 return false;
42 }
43 EXPORT_SYMBOL_GPL(tegra_is_voice_call_active);
44
45 static int tegra_get_avp_device(struct snd_kcontrol *kcontrol,
46                                 struct snd_ctl_elem_value *ucontrol)
47 {
48         struct  tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
49
50         ucontrol->value.integer.value[0] = data->avp_device_id;
51         return 0;
52 }
53
54 static int tegra_set_avp_device(struct snd_kcontrol *kcontrol,
55                                 struct snd_ctl_elem_value *ucontrol)
56 {
57         struct  tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
58         struct snd_soc_card *card = data->card;
59         struct snd_soc_pcm_runtime *rtd;
60         struct snd_pcm_substream *substream;
61         struct tegra_runtime_data *prtd;
62         int id, old_id = data->avp_device_id;
63
64         id = ucontrol->value.integer.value[0];
65         if ((id >= card->num_rtd) || (id < 0))
66                 id = -1;
67
68         if (old_id >= 0) {
69                 rtd = &card->rtd[old_id];
70                 substream =
71                         rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
72                 if (substream && substream->runtime) {
73                         prtd = substream->runtime->private_data;
74                         if (prtd->running)
75                                 return -EBUSY;
76                         if (prtd)
77                                 prtd->disable_intr = false;
78                 }
79         }
80
81         if (id >= 0) {
82                 rtd = &card->rtd[id];
83                 substream =
84                         rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
85                 if (substream && substream->runtime) {
86                         prtd = substream->runtime->private_data;
87                         if (prtd->running)
88                                 return -EBUSY;
89                         if (prtd) {
90                                 prtd->disable_intr = true;
91                                 if (data->avp_dma_addr || prtd->avp_dma_addr)
92                                         prtd->avp_dma_addr = data->avp_dma_addr;
93                         }
94                 }
95         }
96         data->avp_device_id = id;
97         return 1;
98 }
99
100 static int tegra_get_dma_ch_id(struct snd_kcontrol *kcontrol,
101                                struct snd_ctl_elem_value *ucontrol)
102 {
103         struct  tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
104         struct snd_soc_card *card = data->card;
105         struct snd_soc_pcm_runtime *rtd;
106         struct snd_pcm_substream *substream;
107         struct tegra_runtime_data *prtd;
108
109         ucontrol->value.integer.value[0] = -1;
110         if (data->avp_device_id < 0)
111                 return 0;
112
113         rtd = &card->rtd[data->avp_device_id];
114         substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
115         if (!substream || !substream->runtime)
116                 return 0;
117
118         prtd = substream->runtime->private_data;
119         if (!prtd || !prtd->dma_chan)
120                 return 0;
121
122         ucontrol->value.integer.value[0] =
123                 tegra_dma_get_channel_id(prtd->dma_chan);
124         return 0;
125 }
126
127 static int tegra_set_dma_addr(struct snd_kcontrol *kcontrol,
128                               struct snd_ctl_elem_value *ucontrol)
129 {
130         struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
131         struct snd_soc_card *card = data->card;
132         struct snd_soc_pcm_runtime *rtd;
133         struct snd_pcm_substream *substream;
134         struct tegra_runtime_data *prtd;
135
136         if (data->avp_device_id < 0)
137                 return 0;
138
139         data->avp_dma_addr = ucontrol->value.integer.value[0];
140
141         rtd = &card->rtd[data->avp_device_id];
142         substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
143         if (!substream || !substream->runtime)
144                 return 0;
145
146         prtd = substream->runtime->private_data;
147         if (!prtd)
148                 return 0;
149
150         prtd->avp_dma_addr = data->avp_dma_addr;
151         return 1;
152 }
153
154 static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol,
155                               struct snd_ctl_elem_value *ucontrol)
156 {
157         struct  tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol);
158         struct snd_soc_card *card = data->card;
159         struct snd_soc_pcm_runtime *rtd;
160         struct snd_pcm_substream *substream;
161         struct tegra_runtime_data *prtd;
162
163         ucontrol->value.integer.value[0] = 0;
164         if (data->avp_device_id < 0)
165                 return 0;
166
167         rtd = &card->rtd[data->avp_device_id];
168         substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
169         if (!substream || !substream->runtime)
170                 return 0;
171
172         prtd = substream->runtime->private_data;
173         if (!prtd || !prtd->dma_chan)
174                 return 0;
175
176         ucontrol->value.integer.value[0] = prtd->avp_dma_addr ?
177                                            prtd->avp_dma_addr :
178                                            substream->runtime->dma_addr;
179
180         return 0;
181 }
182
183 struct snd_kcontrol_new tegra_avp_controls[] = {
184         SOC_SINGLE_EXT("AVP alsa device select", 0, 0, TEGRA_ALSA_MAX_DEVICES, \
185                         0, tegra_get_avp_device, tegra_set_avp_device),
186         SOC_SINGLE_EXT("AVP DMA channel id", 0, 0, TEGRA_DMA_MAX_CHANNELS, \
187                         0, tegra_get_dma_ch_id, NULL),
188         SOC_SINGLE_EXT("AVP DMA address", 0, 0, 0xFFFFFFFF, \
189                         0, tegra_get_dma_addr, tegra_set_dma_addr),
190 };
191
192 int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate,
193                               int mclk)
194 {
195         int new_baseclock;
196         bool clk_change;
197         int err;
198         bool reenable_clock;
199
200         switch (srate) {
201         case 11025:
202         case 22050:
203         case 44100:
204         case 88200:
205 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
206                 new_baseclock = 56448000;
207 #else
208                 new_baseclock = 564480000;
209 #endif
210                 break;
211         case 8000:
212         case 16000:
213         case 32000:
214         case 48000:
215         case 64000:
216         case 96000:
217 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
218                 new_baseclock = 73728000;
219 #else
220                 new_baseclock = 552960000;
221 #endif
222                 break;
223         default:
224                 return -EINVAL;
225         }
226
227         clk_change = ((new_baseclock != data->set_baseclock) ||
228                         (mclk != data->set_mclk));
229         if (!clk_change)
230                 return 0;
231
232         /* Don't change rate if already one dai-link is using it */
233         if (data->lock_count)
234                 return -EINVAL;
235
236         data->set_baseclock = 0;
237         data->set_mclk = 0;
238
239         reenable_clock = false;
240         if(tegra_is_clk_enabled(data->clk_pll_a)) {
241                 clk_disable(data->clk_pll_a);
242                 reenable_clock = true;
243         }
244         err = clk_set_rate(data->clk_pll_a, new_baseclock);
245         if (err) {
246                 dev_err(data->dev, "Can't set pll_a rate: %d\n", err);
247                 return err;
248         }
249         if(reenable_clock)
250                 clk_enable(data->clk_pll_a);
251
252         reenable_clock = false;
253         if(tegra_is_clk_enabled(data->clk_pll_a_out0)) {
254                 clk_disable(data->clk_pll_a_out0);
255                 reenable_clock = true;
256         }
257         err = clk_set_rate(data->clk_pll_a_out0, mclk);
258         if (err) {
259                 dev_err(data->dev, "Can't set clk_pll_a_out0 rate: %d\n", err);
260                 return err;
261         }
262         if(reenable_clock)
263                 clk_enable(data->clk_pll_a_out0);
264
265
266         data->set_baseclock = new_baseclock;
267         data->set_mclk = mclk;
268
269         return 0;
270 }
271 EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate);
272
273 void tegra_asoc_utils_lock_clk_rate(struct tegra_asoc_utils_data *data,
274                                     int lock)
275 {
276         if (lock)
277                 data->lock_count++;
278         else if (data->lock_count)
279                 data->lock_count--;
280 }
281 EXPORT_SYMBOL_GPL(tegra_asoc_utils_lock_clk_rate);
282
283 int tegra_asoc_utils_clk_enable(struct tegra_asoc_utils_data *data)
284 {
285         int err;
286
287         err = clk_enable(data->clk_cdev1);
288         if (err) {
289                 dev_err(data->dev, "Can't enable cdev1: %d\n", err);
290                 return err;
291         }
292
293         return 0;
294 }
295 EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_enable);
296
297 int tegra_asoc_utils_clk_disable(struct tegra_asoc_utils_data *data)
298 {
299         clk_disable(data->clk_cdev1);
300         return 0;
301 }
302 EXPORT_SYMBOL_GPL(tegra_asoc_utils_clk_disable);
303
304 int tegra_asoc_utils_register_ctls(struct tegra_asoc_utils_data *data)
305 {
306         int i;
307         int ret = 0;
308
309         /* Add AVP related alsa controls */
310         data->avp_device_id = -1;
311         for (i = 0; i < ARRAY_SIZE(tegra_avp_controls); i++) {
312                 ret = snd_ctl_add(data->card->snd_card,
313                                 snd_ctl_new1(&tegra_avp_controls[i], data));
314                 if (ret < 0) {
315                         dev_err(data->dev, "Can't add avp alsa controls");
316                         return ret;
317                 }
318         }
319
320         return ret;
321 }
322 EXPORT_SYMBOL_GPL(tegra_asoc_utils_register_ctls);
323
324 int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data,
325                           struct device *dev, struct snd_soc_card *card)
326 {
327         int ret;
328
329         data->dev = dev;
330         data->card = card;
331
332         data->clk_pll_p_out1 = clk_get_sys(NULL, "pll_p_out1");
333         if (IS_ERR(data->clk_pll_p_out1)) {
334                 dev_err(data->dev, "Can't retrieve clk pll_p_out1\n");
335                 ret = PTR_ERR(data->clk_pll_p_out1);
336                 goto err;
337         }
338
339         data->clk_pll_a = clk_get_sys(NULL, "pll_a");
340         if (IS_ERR(data->clk_pll_a)) {
341                 dev_err(data->dev, "Can't retrieve clk pll_a\n");
342                 ret = PTR_ERR(data->clk_pll_a);
343                 goto err_put_pll_p_out1;
344         }
345
346         data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0");
347         if (IS_ERR(data->clk_pll_a_out0)) {
348                 dev_err(data->dev, "Can't retrieve clk pll_a_out0\n");
349                 ret = PTR_ERR(data->clk_pll_a_out0);
350                 goto err_put_pll_a;
351         }
352
353         data->clk_m = clk_get_sys(NULL, "clk_m");
354         if (IS_ERR(data->clk_m)) {
355                 dev_err(data->dev, "Can't retrieve clk clk_m\n");
356                 ret = PTR_ERR(data->clk_m);
357                 goto err;
358         }
359
360 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
361         data->clk_cdev1 = clk_get_sys(NULL, "cdev1");
362 #else
363         data->clk_cdev1 = clk_get_sys("extern1", NULL);
364 #endif
365         if (IS_ERR(data->clk_cdev1)) {
366                 dev_err(data->dev, "Can't retrieve clk cdev1\n");
367                 ret = PTR_ERR(data->clk_cdev1);
368                 goto err_put_pll_a_out0;
369         }
370
371 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
372         data->clk_out1 = ERR_PTR(-ENOENT);
373 #else
374         data->clk_out1 = clk_get_sys("clk_out_1", "extern1");
375         if (IS_ERR(data->clk_out1)) {
376                 dev_err(data->dev, "Can't retrieve clk out1\n");
377                 ret = PTR_ERR(data->clk_out1);
378                 goto err_put_cdev1;
379         }
380 #endif
381
382         ret = clk_enable(data->clk_cdev1);
383         if (ret) {
384                 dev_err(data->dev, "Can't enable clk cdev1/extern1");
385                 goto err_put_out1;
386         }
387
388         if (!IS_ERR(data->clk_out1)) {
389                 ret = clk_enable(data->clk_out1);
390                 if (ret) {
391                         dev_err(data->dev, "Can't enable clk out1");
392                         goto err_put_out1;
393                 }
394         }
395
396         ret = tegra_asoc_utils_set_rate(data, 48000, 256 * 48000);
397         if (ret)
398                 goto err_put_out1;
399
400         return 0;
401
402 err_put_out1:
403         if (!IS_ERR(data->clk_out1))
404                 clk_put(data->clk_out1);
405 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
406 err_put_cdev1:
407 #endif
408         clk_put(data->clk_cdev1);
409 err_put_pll_a_out0:
410         clk_put(data->clk_pll_a_out0);
411 err_put_pll_a:
412         clk_put(data->clk_pll_a);
413 err_put_pll_p_out1:
414         clk_put(data->clk_pll_p_out1);
415 err:
416         return ret;
417 }
418 EXPORT_SYMBOL_GPL(tegra_asoc_utils_init);
419
420 #if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
421 int tegra_asoc_utils_set_parent (struct tegra_asoc_utils_data *data,
422                                 int is_i2s_master)
423 {
424         int ret = -ENODEV;
425
426         if (is_i2s_master) {
427                 ret = clk_set_parent(data->clk_cdev1, data->clk_pll_a_out0);
428                 if (ret) {
429                         dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
430                         return ret;
431                 }
432         } else {
433                 if(clk_get_rate(data->clk_m) == 26000000)
434                         clk_set_rate(data->clk_cdev1, 13000000);
435
436                 ret = clk_set_parent(data->clk_cdev1, data->clk_m);
437                 if (ret) {
438                         dev_err(data->dev, "Can't set clk cdev1/extern1 parent");
439                         return ret;
440                 }
441         }
442
443         return 0;
444 }
445 EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_parent);
446 #endif
447
448 void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data)
449 {
450         if (!IS_ERR(data->clk_out1))
451                 clk_put(data->clk_out1);
452
453         clk_put(data->clk_cdev1);
454         /* Just to make sure that clk_cdev1 should turn off in case if it is
455          * switched on by some codec whose hw switch is not registered.*/
456         if (tegra_is_clk_enabled(data->clk_cdev1))
457                 clk_disable(data->clk_cdev1);
458
459         if (!IS_ERR(data->clk_pll_a_out0))
460                 clk_put(data->clk_pll_a_out0);
461
462         if (!IS_ERR(data->clk_pll_a))
463                 clk_put(data->clk_pll_a);
464
465         if (!IS_ERR(data->clk_pll_p_out1))
466                 clk_put(data->clk_pll_p_out1);
467 }
468 EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini);
469
470 MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
471 MODULE_DESCRIPTION("Tegra ASoC utility code");
472 MODULE_LICENSE("GPL");