blob: 965559f94c571afbfd7c1831be3aebb47bffbfb4 [file] [log] [blame]
Kiran Kandi9db678b2012-01-15 14:25:59 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/module.h>
15#include <linux/device.h>
16#include <linux/platform_device.h>
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053017#include <linux/mfd/wcd9xxx/core.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <linux/bitops.h>
19#include <linux/slab.h>
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070020#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <sound/core.h>
22#include <sound/pcm.h>
23#include <sound/soc.h>
24#include <sound/apr_audio.h>
25#include <sound/q6afe.h>
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070026#include <sound/msm-dai-q6.h>
Asish Bhattacharyab3568cf2012-03-15 07:05:46 +053027#include <sound/pcm_params.h>
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070028#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070029
30enum {
31 STATUS_PORT_STARTED, /* track if AFE port has started */
32 STATUS_MAX
33};
34
35struct msm_dai_q6_dai_data {
36 DECLARE_BITMAP(status_mask, STATUS_MAX);
37 u32 rate;
38 u32 channels;
Patrick Lai04baee942012-05-01 14:38:47 -070039 u32 bitwidth;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070040 union afe_port_config port_config;
41};
42
Patrick Lai04baee942012-05-01 14:38:47 -070043struct msm_dai_q6_mi2s_dai_data {
44 struct msm_dai_q6_dai_data tx_dai;
45 struct msm_dai_q6_dai_data rx_dai;
46 struct snd_pcm_hw_constraint_list rate_constraint;
47 struct snd_pcm_hw_constraint_list bitwidth_constraint;
48};
49
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070050static struct clk *pcm_clk;
Kiran Kandi5f4ab692012-02-23 11:23:56 -080051static DEFINE_MUTEX(aux_pcm_mutex);
52static int aux_pcm_count;
53static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070054
Kuirong Wang875d1ec2012-04-02 19:56:25 -070055static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
56 struct snd_ctl_elem_value *ucontrol)
57{
58
59 struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
60 int value = ucontrol->value.integer.value[0];
61 dai_data->port_config.mi2s.format = value;
62 pr_debug("%s: value = %d, channel = %d, line = %d\n",
63 __func__, value, dai_data->port_config.mi2s.channel,
64 dai_data->port_config.mi2s.line);
65 return 0;
66}
67
68static int msm_dai_q6_mi2s_format_get(struct snd_kcontrol *kcontrol,
69 struct snd_ctl_elem_value *ucontrol)
70{
71
72 struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
73 ucontrol->value.integer.value[0] = dai_data->port_config.mi2s.format ;
74 return 0;
75}
76
77
78/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
79 * 0: linear PCM
80 * 1: non-linear PCM
81 * 2: PCM data in IEC 60968 container
82 * 3: compressed data in IEC 60958 container
83 */
84static const char *mi2s_format[] = {
85 "LPCM",
86 "Compr",
87 "60958-LPCM",
88 "60958-Compr"};
89
90static const struct soc_enum mi2s_config_enum[] = {
91 SOC_ENUM_SINGLE_EXT(4, mi2s_format),
92};
93
94static const struct snd_kcontrol_new mi2s_config_controls[] = {
95 SOC_ENUM_EXT("MI2S RX Format", mi2s_config_enum[0],
96 msm_dai_q6_mi2s_format_get,
97 msm_dai_q6_mi2s_format_put),
98 SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
99 msm_dai_q6_mi2s_format_get,
100 msm_dai_q6_mi2s_format_put),
Kuirong Wang623b50f2012-04-16 15:51:14 -0700101 SOC_ENUM_EXT("MI2S TX Format", mi2s_config_enum[0],
102 msm_dai_q6_mi2s_format_get,
103 msm_dai_q6_mi2s_format_put),
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700104};
105
Kuirong Wang274f21a2011-12-15 21:29:08 -0800106static u8 num_of_bits_set(u8 sd_line_mask)
107{
108 u8 num_bits_set = 0;
109
110 while (sd_line_mask) {
111 num_bits_set++;
112 sd_line_mask = sd_line_mask & (sd_line_mask - 1);
113 }
114 return num_bits_set;
115}
116
Patrick Lai04baee942012-05-01 14:38:47 -0700117static int msm_dai_q6_mi2s_startup(struct snd_pcm_substream *substream,
118 struct snd_soc_dai *dai)
119{
120 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
121 dev_get_drvdata(dai->dev);
122
123 dev_dbg(dai->dev, "%s: cnst list %p\n", __func__,
124 mi2s_dai_data->rate_constraint.list);
125
126 if (mi2s_dai_data->rate_constraint.list) {
127 snd_pcm_hw_constraint_list(substream->runtime, 0,
128 SNDRV_PCM_HW_PARAM_RATE,
129 &mi2s_dai_data->rate_constraint);
130 snd_pcm_hw_constraint_list(substream->runtime, 0,
131 SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
132 &mi2s_dai_data->bitwidth_constraint);
133 }
134
135 return 0;
136}
137
138static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
139 struct snd_pcm_hw_params *params,
140 struct snd_soc_dai *dai)
141{
142 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
143 dev_get_drvdata(dai->dev);
144 struct msm_dai_q6_dai_data *dai_data =
145 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
146 &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
147
148 dai_data->channels = params_channels(params);
149 switch (dai_data->channels) {
150 case 2:
151 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
152 break;
153 case 1:
154 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
155 break;
156 default:
157 pr_warn("greater than stereo has not been validated");
158 break;
159 }
160 dai_data->rate = params_rate(params);
161 dai_data->port_config.mi2s.bitwidth = 16;
162 dai_data->bitwidth = 16;
163 if (!mi2s_dai_data->rate_constraint.list) {
164 mi2s_dai_data->rate_constraint.list = &dai_data->rate;
165 mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
166 }
167 return 0;
168}
169
170static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
171 unsigned int *ch_cnt)
172{
173 u8 num_of_sd_lines;
174
175 num_of_sd_lines = num_of_bits_set(sd_lines);
176
177 switch (num_of_sd_lines) {
178 case 0:
179 pr_debug("%s: no line is assigned\n", __func__);
180 break;
181 case 1:
182 switch (sd_lines) {
183 case MSM_MI2S_SD0:
184 *config_ptr = AFE_I2S_SD0;
185 break;
186 case MSM_MI2S_SD1:
187 *config_ptr = AFE_I2S_SD1;
188 break;
189 case MSM_MI2S_SD2:
190 *config_ptr = AFE_I2S_SD2;
191 break;
192 case MSM_MI2S_SD3:
193 *config_ptr = AFE_I2S_SD3;
194 break;
195 default:
196 pr_err("%s: invalid SD line\n",
197 __func__);
198 goto error_invalid_data;
199 }
200 break;
201 case 2:
202 switch (sd_lines) {
203 case MSM_MI2S_SD0 | MSM_MI2S_SD1:
204 *config_ptr = AFE_I2S_QUAD01;
205 break;
206 case MSM_MI2S_SD2 | MSM_MI2S_SD3:
207 *config_ptr = AFE_I2S_QUAD23;
208 break;
209 default:
210 pr_err("%s: invalid SD line\n",
211 __func__);
212 goto error_invalid_data;
213 }
214 break;
215 case 3:
216 switch (sd_lines) {
217 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
218 *config_ptr = AFE_I2S_6CHS;
219 break;
220 default:
221 pr_err("%s: invalid SD lines\n",
222 __func__);
223 goto error_invalid_data;
224 }
225 break;
226 case 4:
227 switch (sd_lines) {
228 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
229 *config_ptr = AFE_I2S_8CHS;
230 break;
231 default:
232 pr_err("%s: invalid SD lines\n",
233 __func__);
234 goto error_invalid_data;
235 }
236 break;
237 default:
238 pr_err("%s: invalid SD lines\n", __func__);
239 goto error_invalid_data;
240 }
241
242 *ch_cnt = num_of_sd_lines;
243
244 return 0;
245
246error_invalid_data:
247 return -EINVAL;
248}
249
250static int msm_dai_q6_mi2s_platform_data_validation(
251 struct platform_device *pdev, struct snd_soc_dai_driver *dai_driver)
252{
253 struct msm_dai_q6_mi2s_dai_data *dai_data = dev_get_drvdata(&pdev->dev);
254 struct msm_mi2s_pdata *mi2s_pdata =
255 (struct msm_mi2s_pdata *) pdev->dev.platform_data;
256 u16 sdline_config;
257 unsigned int ch_cnt;
258 int rc = 0;
259
260 if ((mi2s_pdata->rx_sd_lines & mi2s_pdata->tx_sd_lines) ||
261 (!mi2s_pdata->rx_sd_lines && !mi2s_pdata->tx_sd_lines)) {
262 dev_err(&pdev->dev,
263 "error sd line conflict or no line assigned\n");
264 rc = -EINVAL;
265 goto rtn;
266 }
267
268 rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->rx_sd_lines,
269 &sdline_config, &ch_cnt);
270
271 if (IS_ERR_VALUE(rc)) {
272 dev_err(&pdev->dev, "invalid MI2S RX sd line config\n");
273 goto rtn;
274 }
275
276 if (ch_cnt) {
277 dai_data->rx_dai.port_config.mi2s.line = sdline_config;
278 dai_driver->playback.channels_min = 1;
279 dai_driver->playback.channels_max = ch_cnt << 1;
280 } else {
281 dai_driver->playback.channels_min = 0;
282 dai_driver->playback.channels_max = 0;
283 }
284 rc = msm_dai_q6_mi2s_get_lineconfig(mi2s_pdata->tx_sd_lines,
285 &sdline_config, &ch_cnt);
286
287 if (IS_ERR_VALUE(rc)) {
288 dev_err(&pdev->dev, "invalid MI2S TX sd line config\n");
289 goto rtn;
290 }
291
292 if (ch_cnt) {
293 dai_data->tx_dai.port_config.mi2s.line = sdline_config;
294 dai_driver->capture.channels_min = 1;
295 dai_driver->capture.channels_max = ch_cnt << 1;
296 } else {
297 dai_driver->capture.channels_min = 0;
298 dai_driver->capture.channels_max = 0;
299 }
300
301 dev_info(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
302 __func__, dai_data->rx_dai.port_config.mi2s.line,
303 dai_data->tx_dai.port_config.mi2s.line);
304 dev_info(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
305 __func__, dai_driver->playback.channels_max,
306 dai_driver->capture.channels_max);
307rtn:
308 return rc;
309}
310
311static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
312{
313 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
314 dev_get_drvdata(dai->dev);
315
316 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) ||
317 test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
318 dev_err(dai->dev, "%s: err chg i2s mode while dai running",
319 __func__);
320 return -EPERM;
321 }
322
323 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
324 case SND_SOC_DAIFMT_CBS_CFS:
325 mi2s_dai_data->rx_dai.port_config.mi2s.ws = 1;
326 mi2s_dai_data->tx_dai.port_config.mi2s.ws = 1;
327 break;
328 case SND_SOC_DAIFMT_CBM_CFM:
329 mi2s_dai_data->rx_dai.port_config.mi2s.ws = 0;
330 mi2s_dai_data->tx_dai.port_config.mi2s.ws = 0;
331 break;
332 default:
333 return -EINVAL;
334 }
335
336 return 0;
337}
338
339static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
340 struct snd_soc_dai *dai)
341{
342 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
343 dev_get_drvdata(dai->dev);
344 struct msm_dai_q6_dai_data *dai_data =
345 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
346 &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
347 int rc = 0;
348
349 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
350 /* PORT START should be set if prepare called in active state */
351 rc = afe_q6_interface_prepare();
352 if (IS_ERR_VALUE(rc))
353 dev_err(dai->dev, "fail to open AFE APR\n");
354 }
355 return rc;
356}
357
358static int msm_dai_q6_mi2s_trigger(struct snd_pcm_substream *substream, int cmd,
359 struct snd_soc_dai *dai)
360{
361 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
362 dev_get_drvdata(dai->dev);
363 struct msm_dai_q6_dai_data *dai_data =
364 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
365 &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
366 u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
367 MI2S_RX : MI2S_TX);
368 int rc = 0;
369
370 dev_dbg(dai->dev, "%s: cmd:%d dai_data->status_mask = %ld",
371 __func__, cmd, *dai_data->status_mask);
372 switch (cmd) {
373 case SNDRV_PCM_TRIGGER_START:
374 case SNDRV_PCM_TRIGGER_RESUME:
375 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
376 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
377 afe_port_start_nowait(port_id,
378 &dai_data->port_config, dai_data->rate);
379 set_bit(STATUS_PORT_STARTED,
380 dai_data->status_mask);
381 }
382 break;
383 case SNDRV_PCM_TRIGGER_STOP:
384 case SNDRV_PCM_TRIGGER_SUSPEND:
385 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
386 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
387 afe_port_stop_nowait(port_id);
388 clear_bit(STATUS_PORT_STARTED,
389 dai_data->status_mask);
390 }
391 break;
392
393 default:
394 rc = -EINVAL;
395 }
396
397 return rc;
398}
399
400static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
401 struct snd_soc_dai *dai)
402{
403 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
404 dev_get_drvdata(dai->dev);
405 struct msm_dai_q6_dai_data *dai_data =
406 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
407 &mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
408 u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
409 MI2S_RX : MI2S_TX);
410 int rc = 0;
411
412 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
413 rc = afe_close(port_id);
414 if (IS_ERR_VALUE(rc))
415 dev_err(dai->dev, "fail to close AFE port\n");
416 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
417 }
418
419 if (!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) &&
420 !test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
421 mi2s_dai_data->rate_constraint.list = NULL;
422 mi2s_dai_data->bitwidth_constraint.list = NULL;
423 }
424
425}
426
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700427static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
428 struct snd_soc_dai *dai, int stream)
429{
430 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
431
432 dai_data->channels = params_channels(params);
433 switch (dai_data->channels) {
434 case 2:
435 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
436 break;
437 case 1:
438 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
439 break;
440 default:
441 return -EINVAL;
442 break;
443 }
444 dai_data->rate = params_rate(params);
445
446 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
447 dai_data->channels, dai_data->rate);
448
449 /* Q6 only supports 16 as now */
450 dai_data->port_config.mi2s.bitwidth = 16;
451 dai_data->port_config.mi2s.line = 1;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800452 return 0;
453}
454
Lei Zhou157c1842011-08-19 13:05:04 -0400455static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
456{
457 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
458
459 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
460 case SND_SOC_DAIFMT_CBS_CFS:
461 dai_data->port_config.mi2s.ws = 1; /* CPU is master */
462 break;
463 case SND_SOC_DAIFMT_CBM_CFM:
464 dai_data->port_config.mi2s.ws = 0; /* CPU is slave */
465 break;
466 default:
467 return -EINVAL;
468 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469
470 return 0;
471}
472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473
474static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
475 struct snd_soc_dai *dai, int stream)
476{
477 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478
479 dai_data->channels = params_channels(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 dai_data->rate = params_rate(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700482 /* Q6 only supports 16 as now */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800483 dai_data->port_config.slim_sch.bit_width = 16;
484 dai_data->port_config.slim_sch.data_format = 0;
485 dai_data->port_config.slim_sch.num_channels = dai_data->channels;
486 dai_data->port_config.slim_sch.reserved = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800488 dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
489 "num_channel %hu slave_ch_mapping[0] %hu\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700491 "slave_port_mapping[3] %hu\n sample_rate %d\n", __func__,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800492 dai_data->port_config.slim_sch.slimbus_dev_id,
493 dai_data->port_config.slim_sch.bit_width,
494 dai_data->port_config.slim_sch.data_format,
495 dai_data->port_config.slim_sch.num_channels,
496 dai_data->port_config.slim_sch.slave_ch_mapping[0],
497 dai_data->port_config.slim_sch.slave_ch_mapping[1],
498 dai_data->port_config.slim_sch.slave_ch_mapping[2],
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700499 dai_data->port_config.slim_sch.slave_ch_mapping[3],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 dai_data->rate);
501
502 return 0;
503}
504
505static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
506 struct snd_soc_dai *dai, int stream)
507{
508 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
509
510 dai_data->channels = params_channels(params);
511 dai_data->rate = params_rate(params);
512
513 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
514 dai_data->channels, dai_data->rate);
515
516 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
517
518 return 0;
519}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700520static int msm_dai_q6_auxpcm_hw_params(
521 struct snd_pcm_substream *substream,
522 struct snd_pcm_hw_params *params,
523 struct snd_soc_dai *dai)
524{
525 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
526 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
527 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
528
529 if (params_channels(params) != 1) {
530 dev_err(dai->dev, "AUX PCM supports only mono stream\n");
531 return -EINVAL;
532 }
533 dai_data->channels = params_channels(params);
534
Kuirong Wang547a9982012-05-04 18:29:11 -0700535 dai_data->rate = params_rate(params);
536 switch (dai_data->rate) {
537 case 8000:
538 dai_data->port_config.pcm.mode = auxpcm_pdata->mode_8k.mode;
539 dai_data->port_config.pcm.sync = auxpcm_pdata->mode_8k.sync;
540 dai_data->port_config.pcm.frame = auxpcm_pdata->mode_8k.frame;
541 dai_data->port_config.pcm.quant = auxpcm_pdata->mode_8k.quant;
542 dai_data->port_config.pcm.slot = auxpcm_pdata->mode_8k.slot;
543 dai_data->port_config.pcm.data = auxpcm_pdata->mode_8k.data;
544 break;
545 case 16000:
546 dai_data->port_config.pcm.mode = auxpcm_pdata->mode_16k.mode;
547 dai_data->port_config.pcm.sync = auxpcm_pdata->mode_16k.sync;
548 dai_data->port_config.pcm.frame = auxpcm_pdata->mode_16k.frame;
549 dai_data->port_config.pcm.quant = auxpcm_pdata->mode_16k.quant;
550 dai_data->port_config.pcm.slot = auxpcm_pdata->mode_16k.slot;
551 dai_data->port_config.pcm.data = auxpcm_pdata->mode_16k.data;
552 break;
553 default:
554 dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700555 return -EINVAL;
556 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700557
558 return 0;
559}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530561static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
562 struct snd_soc_dai *dai)
563{
564 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
565
566 dai_data->rate = params_rate(params);
567 dai_data->port_config.rtproxy.num_ch =
568 params_channels(params);
569
570 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
571 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
572
573 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
574 dai_data->port_config.rtproxy.interleaved = 1;
Asish Bhattacharyab3568cf2012-03-15 07:05:46 +0530575 dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530576 dai_data->port_config.rtproxy.jitter =
577 dai_data->port_config.rtproxy.frame_sz/2;
578 dai_data->port_config.rtproxy.lw_mark = 0;
579 dai_data->port_config.rtproxy.hw_mark = 0;
580 dai_data->port_config.rtproxy.rsvd = 0;
581
582 return 0;
583}
584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585/* Current implementation assumes hw_param is called once
586 * This may not be the case but what to do when ADM and AFE
587 * port are already opened and parameter changes
588 */
589static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
590 struct snd_pcm_hw_params *params,
591 struct snd_soc_dai *dai)
592{
593 int rc = 0;
594
595 switch (dai->id) {
596 case PRIMARY_I2S_TX:
597 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800598 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
600 break;
Patrick Lai04baee942012-05-01 14:38:47 -0700601
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800603 case SLIMBUS_1_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700604 case SLIMBUS_3_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800606 case SLIMBUS_1_TX:
Kiran Kandifd30c892012-05-21 23:03:26 -0700607 case SLIMBUS_2_RX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700608 case SLIMBUS_2_TX:
Helen Zeng38c3c962012-05-17 14:56:20 -0700609 case SLIMBUS_3_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800610 case SLIMBUS_4_RX:
611 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
613 substream->stream);
614 break;
615 case INT_BT_SCO_RX:
616 case INT_BT_SCO_TX:
617 case INT_FM_RX:
618 case INT_FM_TX:
619 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
620 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530621 case RT_PROXY_DAI_001_TX:
622 case RT_PROXY_DAI_001_RX:
623 case RT_PROXY_DAI_002_TX:
624 case RT_PROXY_DAI_002_RX:
625 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
626 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700627 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700628 case VOICE_RECORD_RX:
629 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700630 rc = 0;
631 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632 default:
633 dev_err(dai->dev, "invalid AFE port ID\n");
634 rc = -EINVAL;
635 break;
636 }
637
638 return rc;
639}
640
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700641static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
642 struct snd_soc_dai *dai)
643{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700644 int rc = 0;
645
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800646 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700647
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800648 if (aux_pcm_count == 0) {
649 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
650 " return\n", __func__, dai->id);
651 mutex_unlock(&aux_pcm_mutex);
652 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700653 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800654
655 aux_pcm_count--;
656
657 if (aux_pcm_count > 0) {
658 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
659 __func__, dai->id, aux_pcm_count);
660 mutex_unlock(&aux_pcm_mutex);
661 return;
662 } else if (aux_pcm_count < 0) {
663 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
664 " aux_pcm_count = %d < 0\n",
665 __func__, dai->id, aux_pcm_count);
666 aux_pcm_count = 0;
667 mutex_unlock(&aux_pcm_mutex);
668 return;
669 }
670
671 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
672 dai->id, aux_pcm_count);
673
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530674 clk_disable_unprepare(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800675 rc = afe_close(PCM_RX); /* can block */
676 if (IS_ERR_VALUE(rc))
677 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
678
679 rc = afe_close(PCM_TX);
680 if (IS_ERR_VALUE(rc))
681 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
682
683 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700684}
685
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
687 struct snd_soc_dai *dai)
688{
689 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530690 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700693 switch (dai->id) {
694 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700695 case VOICE_RECORD_TX:
696 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700697 pr_debug("%s, stop pseudo port:%d\n",
698 __func__, dai->id);
699 rc = afe_stop_pseudo_port(dai->id);
700 break;
701 default:
702 rc = afe_close(dai->id); /* can block */
703 break;
704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705 if (IS_ERR_VALUE(rc))
706 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530707 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
708 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
710 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700711}
712
713static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
714 struct snd_soc_dai *dai)
715{
716 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
717 int rc = 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700718 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
719 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
Kuirong Wang547a9982012-05-04 18:29:11 -0700720 unsigned long pcm_clk_rate;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700721
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800722 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700723
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800724 if (aux_pcm_count == 2) {
725 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
726 " return.\n", __func__, dai->id);
727 mutex_unlock(&aux_pcm_mutex);
728 return 0;
729 } else if (aux_pcm_count > 2) {
730 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
731 " aux_pcm_count = %d > 2\n",
732 __func__, dai->id, aux_pcm_count);
733 mutex_unlock(&aux_pcm_mutex);
734 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700735 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800736
737 aux_pcm_count++;
738 if (aux_pcm_count == 2) {
739 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
740 " increment\n", __func__, dai->id, aux_pcm_count);
741 mutex_unlock(&aux_pcm_mutex);
742 return 0;
743 }
744
745 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
746 __func__, dai->id, aux_pcm_count);
747
748 rc = afe_q6_interface_prepare();
749 if (IS_ERR_VALUE(rc))
750 dev_err(dai->dev, "fail to open AFE APR\n");
751
752 /*
753 * For AUX PCM Interface the below sequence of clk
754 * settings and afe_open is a strict requirement.
755 *
756 * Also using afe_open instead of afe_port_start_nowait
757 * to make sure the port is open before deasserting the
758 * clock line. This is required because pcm register is
759 * not written before clock deassert. Hence the hw does
760 * not get updated with new setting if the below clock
761 * assert/deasset and afe_open sequence is not followed.
762 */
763
764 clk_reset(pcm_clk, CLK_RESET_ASSERT);
765
766 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
767
768 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
Kuirong Wang547a9982012-05-04 18:29:11 -0700769 if (dai_data->rate == 8000) {
770 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
771 } else if (dai_data->rate == 16000) {
772 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
773 } else {
774 dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
775 dai_data->rate);
776 return -EINVAL;
777 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800778
Kuirong Wang547a9982012-05-04 18:29:11 -0700779 rc = clk_set_rate(pcm_clk, pcm_clk_rate);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800780 if (rc < 0) {
781 pr_err("%s: clk_set_rate failed\n", __func__);
782 return rc;
783 }
784
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530785 clk_prepare_enable(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800786 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
787
788 mutex_unlock(&aux_pcm_mutex);
789
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700790 return rc;
791}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792
793static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
794 struct snd_soc_dai *dai)
795{
796 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
797 int rc = 0;
798
Patrick Lai831561e2011-07-26 22:51:27 -0700799 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700800 /* PORT START should be set if prepare called in active state */
801 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700803 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806}
807
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700808static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
809 int cmd, struct snd_soc_dai *dai)
810{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700811 int rc = 0;
812
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800813 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
814 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700815
816 switch (cmd) {
817
818 case SNDRV_PCM_TRIGGER_START:
819 case SNDRV_PCM_TRIGGER_RESUME:
820 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
821 /* afe_open will be called from prepare */
822 return 0;
823
824 case SNDRV_PCM_TRIGGER_STOP:
825 case SNDRV_PCM_TRIGGER_SUSPEND:
826 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800827 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700828
829 default:
830 rc = -EINVAL;
831 }
832
833 return rc;
834
835}
836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700837static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
838 struct snd_soc_dai *dai)
839{
840 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
841 int rc = 0;
842
843 /* Start/stop port without waiting for Q6 AFE response. Need to have
844 * native q6 AFE driver propagates AFE response in order to handle
845 * port start/stop command error properly if error does arise.
846 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530847 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
848 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700849 switch (cmd) {
850 case SNDRV_PCM_TRIGGER_START:
851 case SNDRV_PCM_TRIGGER_RESUME:
852 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
853 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700854 switch (dai->id) {
855 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700856 case VOICE_RECORD_TX:
857 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700858 afe_pseudo_port_start_nowait(dai->id);
859 break;
860 default:
861 afe_port_start_nowait(dai->id,
862 &dai_data->port_config, dai_data->rate);
863 break;
864 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865 set_bit(STATUS_PORT_STARTED,
866 dai_data->status_mask);
867 }
868 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 case SNDRV_PCM_TRIGGER_STOP:
870 case SNDRV_PCM_TRIGGER_SUSPEND:
871 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
872 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700873 switch (dai->id) {
874 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700875 case VOICE_RECORD_TX:
876 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700877 afe_pseudo_port_stop_nowait(dai->id);
878 break;
879 default:
880 afe_port_stop_nowait(dai->id);
881 break;
882 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 clear_bit(STATUS_PORT_STARTED,
884 dai_data->status_mask);
885 }
886 break;
887
888 default:
889 rc = -EINVAL;
890 }
891
892 return rc;
893}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700894static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
895{
896 struct msm_dai_q6_dai_data *dai_data;
897 int rc = 0;
898
899 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
900 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
901
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800902 mutex_lock(&aux_pcm_mutex);
903
904 if (!auxpcm_plat_data)
905 auxpcm_plat_data = auxpcm_pdata;
906 else if (auxpcm_plat_data != auxpcm_pdata) {
907
908 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
909 " same platform data\n");
910 return -EINVAL;
911 }
912
913 /*
914 * The clk name for AUX PCM operation is passed as platform
915 * data to the cpu driver, since cpu drive is unaware of any
916 * boarc specific configuration.
917 */
918 if (!pcm_clk) {
919
920 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
921
922 if (IS_ERR(pcm_clk)) {
923 pr_err("%s: could not get pcm_clk\n", __func__);
924 pcm_clk = NULL;
925 return -ENODEV;
926 }
927 }
928
929 mutex_unlock(&aux_pcm_mutex);
930
931 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700932
933 if (!dai_data) {
934 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
935 dai->id);
936 rc = -ENOMEM;
937 } else
938 dev_set_drvdata(dai->dev, dai_data);
939
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800940 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700941 return rc;
942}
943
944static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
945{
946 struct msm_dai_q6_dai_data *dai_data;
947 int rc;
948
949 dai_data = dev_get_drvdata(dai->dev);
950
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800951 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700952
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800953 if (aux_pcm_count == 0) {
954 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
955 " up and return\n", __func__, dai->id);
956 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700957 }
958
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800959 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700960
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800961 if (aux_pcm_count > 0) {
962 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
963 __func__, dai->id, aux_pcm_count);
964 goto done;
965 } else if (aux_pcm_count < 0) {
966 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
967 " aux_pcm_count = %d < 0\n",
968 __func__, dai->id, aux_pcm_count);
969 goto done;
970 }
971
972 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
973 "closing afe\n",
974 __func__, dai->id, aux_pcm_count);
975
976 rc = afe_close(PCM_RX); /* can block */
977 if (IS_ERR_VALUE(rc))
978 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
979
980 rc = afe_close(PCM_TX);
981 if (IS_ERR_VALUE(rc))
982 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
983
984done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700985 kfree(dai_data);
986 snd_soc_unregister_dai(dai->dev);
987
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800988 mutex_unlock(&aux_pcm_mutex);
989
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700990 return 0;
991}
Patrick Lai04baee942012-05-01 14:38:47 -0700992
Kuirong Wang274f21a2011-12-15 21:29:08 -0800993static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
994{
Patrick Lai04baee942012-05-01 14:38:47 -0700995 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
996 dev_get_drvdata(dai->dev);
997 struct snd_kcontrol *kcontrol = NULL;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800998 int rc = 0;
999
Patrick Lai04baee942012-05-01 14:38:47 -07001000 if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
1001 kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
1002 &mi2s_dai_data->rx_dai);
1003 rc = snd_ctl_add(dai->card->snd_card, kcontrol);
Kuirong Wang274f21a2011-12-15 21:29:08 -08001004
Patrick Lai04baee942012-05-01 14:38:47 -07001005 if (IS_ERR_VALUE(rc)) {
1006 dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
1007 goto rtn;
1008 }
Kuirong Wang274f21a2011-12-15 21:29:08 -08001009 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001010
Patrick Lai04baee942012-05-01 14:38:47 -07001011 if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
1012 rc = snd_ctl_add(dai->card->snd_card,
1013 snd_ctl_new1(&mi2s_config_controls[2],
1014 &mi2s_dai_data->tx_dai));
1015
1016 if (IS_ERR_VALUE(rc)) {
1017 if (kcontrol)
1018 snd_ctl_remove(dai->card->snd_card, kcontrol);
1019 dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
1020 }
1021 }
1022
Kuirong Wang274f21a2011-12-15 21:29:08 -08001023rtn:
1024 return rc;
1025}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026
Patrick Lai04baee942012-05-01 14:38:47 -07001027static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
1028{
1029 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
1030 dev_get_drvdata(dai->dev);
1031 int rc;
1032
1033 /* If AFE port is still up, close it */
1034 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
1035 rc = afe_close(MI2S_RX); /* can block */
1036 if (IS_ERR_VALUE(rc))
1037 dev_err(dai->dev, "fail to close MI2S_RX port\n");
1038 clear_bit(STATUS_PORT_STARTED,
1039 mi2s_dai_data->rx_dai.status_mask);
1040 }
1041 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
1042 rc = afe_close(MI2S_TX); /* can block */
1043 if (IS_ERR_VALUE(rc))
1044 dev_err(dai->dev, "fail to close MI2S_TX port\n");
1045 clear_bit(STATUS_PORT_STARTED,
1046 mi2s_dai_data->tx_dai.status_mask);
1047 }
1048 kfree(mi2s_dai_data);
1049 snd_soc_unregister_dai(dai->dev);
1050
1051 return 0;
1052}
1053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001054static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
1055{
1056 struct msm_dai_q6_dai_data *dai_data;
1057 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001058 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059
1060 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
1061 GFP_KERNEL);
1062
1063 if (!dai_data) {
1064 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
1065 dai->id);
1066 rc = -ENOMEM;
1067 } else
1068 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001069 if (dai->id == SECONDARY_I2S_RX) {
1070 kcontrol = &mi2s_config_controls[1];
1071 rc = snd_ctl_add(dai->card->snd_card,
1072 snd_ctl_new1(kcontrol, dai_data));
1073 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074
1075 return rc;
1076}
1077
1078static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
1079{
1080 struct msm_dai_q6_dai_data *dai_data;
1081 int rc;
1082
1083 dai_data = dev_get_drvdata(dai->dev);
1084
1085 /* If AFE port is still up, close it */
1086 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -07001087 switch (dai->id) {
1088 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -07001089 case VOICE_RECORD_TX:
1090 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -07001091 pr_debug("%s, stop pseudo port:%d\n",
1092 __func__, dai->id);
1093 rc = afe_stop_pseudo_port(dai->id);
1094 break;
1095 default:
1096 rc = afe_close(dai->id); /* can block */
1097 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 if (IS_ERR_VALUE(rc))
1099 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301100 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001101 }
1102 kfree(dai_data);
1103 snd_soc_unregister_dai(dai->dev);
1104
1105 return 0;
1106}
1107
Lei Zhou157c1842011-08-19 13:05:04 -04001108static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1109{
1110 int rc = 0;
1111
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001112 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
1113 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -04001114 switch (dai->id) {
1115 case PRIMARY_I2S_TX:
1116 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001117 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -04001118 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
1119 break;
1120 default:
1121 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1122 rc = -EINVAL;
1123 break;
1124 }
1125
1126 return rc;
1127}
1128
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001129static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
1130 unsigned int tx_num, unsigned int *tx_slot,
1131 unsigned int rx_num, unsigned int *rx_slot)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001132{
1133 int rc = 0;
1134 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
1135 unsigned int i = 0;
1136
Kiran Kandifd30c892012-05-21 23:03:26 -07001137 dev_dbg(dai->dev, "%s: dai_id = %d\n", __func__, dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001138 switch (dai->id) {
1139 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001140 case SLIMBUS_1_RX:
Kiran Kandifd30c892012-05-21 23:03:26 -07001141 case SLIMBUS_2_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -07001142 case SLIMBUS_3_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001143 case SLIMBUS_4_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001144 /* channel number to be between 128 and 255. For RX port
1145 * use channel numbers from 138 to 144, for TX port
1146 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001147 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001148 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001149 if (!rx_slot)
1150 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001151 for (i = 0; i < rx_num; i++) {
1152 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1153 rx_slot[i];
1154 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1155 __func__, i,
1156 rx_slot[i]);
1157 }
1158 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001159 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
1160 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001161 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1162 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1163
1164 break;
1165 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001166 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001167 case SLIMBUS_2_TX:
Helen Zeng38c3c962012-05-17 14:56:20 -07001168 case SLIMBUS_3_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001169 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001170 /* channel number to be between 128 and 255. For RX port
1171 * use channel numbers from 138 to 144, for TX port
1172 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001173 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001174 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001175 if (!tx_slot)
1176 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001177 for (i = 0; i < tx_num; i++) {
1178 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1179 tx_slot[i];
1180 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1181 __func__, i, tx_slot[i]);
1182 }
1183 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001184 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
1185 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001186 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1187 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1188 break;
1189 default:
1190 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1191 rc = -EINVAL;
1192 break;
1193 }
1194 return rc;
1195}
1196
Patrick Lai04baee942012-05-01 14:38:47 -07001197static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
1198 .startup = msm_dai_q6_mi2s_startup,
1199 .prepare = msm_dai_q6_mi2s_prepare,
1200 .trigger = msm_dai_q6_mi2s_trigger,
1201 .hw_params = msm_dai_q6_mi2s_hw_params,
1202 .shutdown = msm_dai_q6_mi2s_shutdown,
1203 .set_fmt = msm_dai_q6_mi2s_set_fmt,
1204};
1205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 .prepare = msm_dai_q6_prepare,
1208 .trigger = msm_dai_q6_trigger,
1209 .hw_params = msm_dai_q6_hw_params,
1210 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -04001211 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001212 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213};
1214
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001215static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
1216 .prepare = msm_dai_q6_auxpcm_prepare,
1217 .trigger = msm_dai_q6_auxpcm_trigger,
1218 .hw_params = msm_dai_q6_auxpcm_hw_params,
1219 .shutdown = msm_dai_q6_auxpcm_shutdown,
1220};
1221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
1223 .playback = {
1224 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1225 SNDRV_PCM_RATE_16000,
1226 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1227 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -08001228 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001229 .rate_min = 8000,
1230 .rate_max = 48000,
1231 },
1232 .ops = &msm_dai_q6_ops,
1233 .probe = msm_dai_q6_dai_probe,
1234 .remove = msm_dai_q6_dai_remove,
1235};
1236
1237static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
1238 .capture = {
1239 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1240 SNDRV_PCM_RATE_16000,
1241 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1242 .channels_min = 1,
1243 .channels_max = 2,
1244 .rate_min = 8000,
1245 .rate_max = 48000,
1246 },
1247 .ops = &msm_dai_q6_ops,
1248 .probe = msm_dai_q6_dai_probe,
1249 .remove = msm_dai_q6_dai_remove,
1250};
1251
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301252static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
1253 .playback = {
1254 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1255 SNDRV_PCM_RATE_16000,
1256 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1257 .channels_min = 1,
1258 .channels_max = 2,
1259 .rate_min = 8000,
1260 .rate_max = 48000,
1261 },
1262 .ops = &msm_dai_q6_ops,
1263 .probe = msm_dai_q6_dai_probe,
1264 .remove = msm_dai_q6_dai_remove,
1265};
1266
1267static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1268 .capture = {
1269 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1270 SNDRV_PCM_RATE_16000,
1271 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1272 .channels_min = 1,
Mingming Yin647e9ea2012-03-17 19:56:10 -07001273 .channels_max = 4,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301274 .rate_min = 8000,
1275 .rate_max = 48000,
1276 },
1277 .ops = &msm_dai_q6_ops,
1278 .probe = msm_dai_q6_dai_probe,
1279 .remove = msm_dai_q6_dai_remove,
1280};
1281
Helen Zeng0705a5f2011-10-14 15:29:52 -07001282static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1283 .playback = {
1284 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1285 SNDRV_PCM_RATE_16000,
1286 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1287 .channels_min = 1,
1288 .channels_max = 2,
1289 .rate_max = 48000,
1290 .rate_min = 8000,
1291 },
1292 .ops = &msm_dai_q6_ops,
1293 .probe = msm_dai_q6_dai_probe,
1294 .remove = msm_dai_q6_dai_remove,
1295};
1296
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1298 .playback = {
1299 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1300 SNDRV_PCM_RATE_16000,
1301 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1302 .channels_min = 1,
1303 .channels_max = 2,
1304 .rate_min = 8000,
1305 .rate_max = 48000,
1306 },
1307 .ops = &msm_dai_q6_ops,
1308 .probe = msm_dai_q6_dai_probe,
1309 .remove = msm_dai_q6_dai_remove,
1310};
1311
1312static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1313 .capture = {
1314 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1315 SNDRV_PCM_RATE_16000,
1316 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1317 .channels_min = 1,
1318 .channels_max = 2,
1319 .rate_min = 8000,
1320 .rate_max = 48000,
1321 },
1322 .ops = &msm_dai_q6_ops,
1323 .probe = msm_dai_q6_dai_probe,
1324 .remove = msm_dai_q6_dai_remove,
1325};
1326
Helen Zenge3d716a2011-10-14 16:32:16 -07001327static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1328 .capture = {
1329 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1330 SNDRV_PCM_RATE_16000,
1331 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1332 .channels_min = 1,
1333 .channels_max = 2,
1334 .rate_min = 8000,
1335 .rate_max = 48000,
1336 },
1337 .ops = &msm_dai_q6_ops,
1338 .probe = msm_dai_q6_dai_probe,
1339 .remove = msm_dai_q6_dai_remove,
1340};
1341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1343 .playback = {
1344 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1345 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1346 .channels_min = 1,
1347 .channels_max = 1,
1348 .rate_max = 16000,
1349 .rate_min = 8000,
1350 },
1351 .ops = &msm_dai_q6_ops,
1352 .probe = msm_dai_q6_dai_probe,
1353 .remove = msm_dai_q6_dai_remove,
1354};
1355
1356static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1357 .playback = {
1358 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1359 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1360 .channels_min = 1,
1361 .channels_max = 1,
1362 .rate_max = 16000,
1363 .rate_min = 8000,
1364 },
1365 .ops = &msm_dai_q6_ops,
1366 .probe = msm_dai_q6_dai_probe,
1367 .remove = msm_dai_q6_dai_remove,
1368};
1369
1370static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1371 .playback = {
1372 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1373 SNDRV_PCM_RATE_16000,
1374 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1375 .channels_min = 2,
1376 .channels_max = 2,
1377 .rate_max = 48000,
1378 .rate_min = 8000,
1379 },
1380 .ops = &msm_dai_q6_ops,
1381 .probe = msm_dai_q6_dai_probe,
1382 .remove = msm_dai_q6_dai_remove,
1383};
1384
1385static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1386 .playback = {
1387 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1388 SNDRV_PCM_RATE_16000,
1389 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1390 .channels_min = 2,
1391 .channels_max = 2,
1392 .rate_max = 48000,
1393 .rate_min = 8000,
1394 },
1395 .ops = &msm_dai_q6_ops,
1396 .probe = msm_dai_q6_dai_probe,
1397 .remove = msm_dai_q6_dai_remove,
1398};
1399
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001400static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1401 .playback = {
Kuirong Wang547a9982012-05-04 18:29:11 -07001402 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001403 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1404 .channels_min = 1,
1405 .channels_max = 1,
Kuirong Wang547a9982012-05-04 18:29:11 -07001406 .rate_max = 16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001407 .rate_min = 8000,
1408 },
1409 .ops = &msm_dai_q6_auxpcm_ops,
1410 .probe = msm_dai_q6_dai_auxpcm_probe,
1411 .remove = msm_dai_q6_dai_auxpcm_remove,
1412};
1413
1414static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1415 .capture = {
Kuirong Wang547a9982012-05-04 18:29:11 -07001416 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001417 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1418 .channels_min = 1,
1419 .channels_max = 1,
Kuirong Wang547a9982012-05-04 18:29:11 -07001420 .rate_max = 16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001421 .rate_min = 8000,
1422 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001423 .ops = &msm_dai_q6_auxpcm_ops,
1424 .probe = msm_dai_q6_dai_auxpcm_probe,
1425 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001426};
1427
Patrick Lai04baee942012-05-01 14:38:47 -07001428/* Channel min and max are initialized base on platform data */
1429static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
Kuirong Wang274f21a2011-12-15 21:29:08 -08001430 .playback = {
1431 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1432 SNDRV_PCM_RATE_16000,
1433 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Kuirong Wang274f21a2011-12-15 21:29:08 -08001434 .rate_min = 8000,
1435 .rate_max = 48000,
1436 },
Kuirong Wang623b50f2012-04-16 15:51:14 -07001437 .capture = {
1438 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1439 SNDRV_PCM_RATE_16000,
1440 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Patrick Lai04baee942012-05-01 14:38:47 -07001441 .rate_min = 8000,
1442 .rate_max = 48000,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001443 },
Patrick Lai04baee942012-05-01 14:38:47 -07001444 .ops = &msm_dai_q6_mi2s_ops,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001445 .probe = msm_dai_q6_dai_mi2s_probe,
Patrick Lai04baee942012-05-01 14:38:47 -07001446 .remove = msm_dai_q6_dai_mi2s_remove,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001447};
1448
Neema Shetty3c9d2862012-03-11 01:25:32 -08001449static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1450 .playback = {
1451 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1452 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1453 .channels_min = 1,
1454 .channels_max = 1,
1455 .rate_min = 8000,
1456 .rate_max = 16000,
1457 },
1458 .ops = &msm_dai_q6_ops,
1459 .probe = msm_dai_q6_dai_probe,
1460 .remove = msm_dai_q6_dai_remove,
1461};
1462
1463static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1464 .capture = {
1465 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1466 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1467 .channels_min = 1,
1468 .channels_max = 1,
1469 .rate_min = 8000,
1470 .rate_max = 16000,
1471 },
1472 .ops = &msm_dai_q6_ops,
1473 .probe = msm_dai_q6_dai_probe,
1474 .remove = msm_dai_q6_dai_remove,
1475};
1476
Kiran Kandifd30c892012-05-21 23:03:26 -07001477static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_rx_dai = {
1478 .playback = {
1479 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1480 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1481 SNDRV_PCM_RATE_192000,
1482 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1483 .channels_min = 1,
1484 .channels_max = 2,
1485 .rate_min = 8000,
1486 .rate_max = 192000,
1487 },
1488 .ops = &msm_dai_q6_ops,
1489 .probe = msm_dai_q6_dai_probe,
1490 .remove = msm_dai_q6_dai_remove,
1491};
1492
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001493static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1494 .capture = {
1495 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1496 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1497 SNDRV_PCM_RATE_192000,
1498 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1499 .channels_min = 1,
1500 .channels_max = 4,
1501 .rate_min = 8000,
1502 .rate_max = 192000,
1503 },
1504 .ops = &msm_dai_q6_ops,
1505 .probe = msm_dai_q6_dai_probe,
1506 .remove = msm_dai_q6_dai_remove,
1507};
1508
Neema Shetty74131ac2012-05-09 13:35:26 -07001509static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
1510 .playback = {
1511 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
1512 SNDRV_PCM_RATE_48000,
1513 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1514 .channels_min = 1,
1515 .channels_max = 2,
1516 .rate_min = 8000,
1517 .rate_max = 48000,
1518 },
1519 .ops = &msm_dai_q6_ops,
1520 .probe = msm_dai_q6_dai_probe,
1521 .remove = msm_dai_q6_dai_remove,
1522};
1523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524/* To do: change to register DAIs as batch */
1525static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1526{
1527 int rc = 0;
1528
1529 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1530
1531 switch (pdev->id) {
1532 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001533 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1535 break;
1536 case PRIMARY_I2S_TX:
1537 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1538 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001539 case PCM_RX:
1540 rc = snd_soc_register_dai(&pdev->dev,
1541 &msm_dai_q6_aux_pcm_rx_dai);
1542 break;
1543 case PCM_TX:
1544 rc = snd_soc_register_dai(&pdev->dev,
1545 &msm_dai_q6_aux_pcm_tx_dai);
1546 break;
Patrick Lai04baee942012-05-01 14:38:47 -07001547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001549 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 rc = snd_soc_register_dai(&pdev->dev,
1551 &msm_dai_q6_slimbus_rx_dai);
1552 break;
1553 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001554 case SLIMBUS_4_TX:
Helen Zeng38c3c962012-05-17 14:56:20 -07001555 case SLIMBUS_3_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 rc = snd_soc_register_dai(&pdev->dev,
1557 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001558 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001559 case SLIMBUS_1_RX:
1560 rc = snd_soc_register_dai(&pdev->dev,
1561 &msm_dai_q6_slimbus_1_rx_dai);
1562 break;
1563 case SLIMBUS_1_TX:
1564 rc = snd_soc_register_dai(&pdev->dev,
1565 &msm_dai_q6_slimbus_1_tx_dai);
1566 break;
Kiran Kandifd30c892012-05-21 23:03:26 -07001567 case SLIMBUS_2_RX:
1568 rc = snd_soc_register_dai(&pdev->dev,
1569 &msm_dai_q6_slimbus_2_rx_dai);
1570 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001571 case SLIMBUS_2_TX:
1572 rc = snd_soc_register_dai(&pdev->dev,
1573 &msm_dai_q6_slimbus_2_tx_dai);
1574 break;
Neema Shetty74131ac2012-05-09 13:35:26 -07001575 case SLIMBUS_3_RX:
1576 rc = snd_soc_register_dai(&pdev->dev,
1577 &msm_dai_q6_slimbus_3_rx_dai);
1578 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 case INT_BT_SCO_RX:
1580 rc = snd_soc_register_dai(&pdev->dev,
1581 &msm_dai_q6_bt_sco_rx_dai);
1582 break;
1583 case INT_BT_SCO_TX:
1584 rc = snd_soc_register_dai(&pdev->dev,
1585 &msm_dai_q6_bt_sco_tx_dai);
1586 break;
1587 case INT_FM_RX:
1588 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1589 break;
1590 case INT_FM_TX:
1591 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1592 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301593 case RT_PROXY_DAI_001_RX:
1594 case RT_PROXY_DAI_002_RX:
1595 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1596 break;
1597 case RT_PROXY_DAI_001_TX:
1598 case RT_PROXY_DAI_002_TX:
1599 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1600 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001601 case VOICE_PLAYBACK_TX:
1602 rc = snd_soc_register_dai(&pdev->dev,
1603 &msm_dai_q6_voice_playback_tx_dai);
1604 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001605 case VOICE_RECORD_RX:
1606 case VOICE_RECORD_TX:
1607 rc = snd_soc_register_dai(&pdev->dev,
1608 &msm_dai_q6_incall_record_dai);
1609 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 default:
1611 rc = -ENODEV;
1612 break;
1613 }
1614 return rc;
1615}
1616
1617static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1618{
1619 snd_soc_unregister_dai(&pdev->dev);
1620 return 0;
1621}
1622
Patrick Lai04baee942012-05-01 14:38:47 -07001623static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
1624{
1625 struct msm_dai_q6_mi2s_dai_data *dai_data;
1626 int rc = 0;
1627
1628 dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
1629
1630 dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
1631 GFP_KERNEL);
1632
1633 if (!dai_data) {
1634 dev_err(&pdev->dev, "fail to allocate dai data\n");
1635 rc = -ENOMEM;
1636 goto rtn;
1637 } else
1638 dev_set_drvdata(&pdev->dev, dai_data);
1639
1640 rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
1641 &msm_dai_q6_mi2s_dai);
1642 if (IS_ERR_VALUE(rc))
1643 goto err_pdata;
1644
1645 dai_data->rate_constraint.count = 1;
1646 dai_data->bitwidth_constraint.count = 1;
1647 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
1648
1649 if (IS_ERR_VALUE(rc))
1650 goto err_pdata;
1651
1652 return 0;
1653
1654err_pdata:
1655 kfree(dai_data);
1656rtn:
1657 return rc;
1658}
1659
1660static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
1661{
1662 snd_soc_unregister_dai(&pdev->dev);
1663 return 0;
1664}
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666static struct platform_driver msm_dai_q6_driver = {
1667 .probe = msm_dai_q6_dev_probe,
1668 .remove = msm_dai_q6_dev_remove,
1669 .driver = {
1670 .name = "msm-dai-q6",
1671 .owner = THIS_MODULE,
1672 },
1673};
1674
Patrick Lai04baee942012-05-01 14:38:47 -07001675static struct platform_driver msm_dai_q6_mi2s_driver = {
1676 .probe = msm_dai_q6_mi2s_dev_probe,
1677 .remove = msm_dai_q6_mi2s_dev_remove,
1678 .driver = {
1679 .name = "msm-dai-q6-mi2s",
1680 .owner = THIS_MODULE,
1681 },
1682};
1683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684static int __init msm_dai_q6_init(void)
1685{
Patrick Lai04baee942012-05-01 14:38:47 -07001686 int rc1, rc2;
1687
1688 rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
1689
1690 if (IS_ERR_VALUE(rc1))
1691 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1692
1693 rc2 = platform_driver_register(&msm_dai_q6_driver);
1694
1695 if (IS_ERR_VALUE(rc2))
1696 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1697
1698 return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699}
1700module_init(msm_dai_q6_init);
1701
1702static void __exit msm_dai_q6_exit(void)
1703{
1704 platform_driver_unregister(&msm_dai_q6_driver);
1705}
1706module_exit(msm_dai_q6_exit);
1707
1708/* Module information */
1709MODULE_DESCRIPTION("MSM DSP DAI driver");
1710MODULE_LICENSE("GPL v2");