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