blob: 284320db6f894581c6de4478735b866d8bc5b105 [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 Zeng8f925502012-03-05 16:50:17 -0800609 case SLIMBUS_4_RX:
610 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
612 substream->stream);
613 break;
614 case INT_BT_SCO_RX:
615 case INT_BT_SCO_TX:
616 case INT_FM_RX:
617 case INT_FM_TX:
618 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
619 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530620 case RT_PROXY_DAI_001_TX:
621 case RT_PROXY_DAI_001_RX:
622 case RT_PROXY_DAI_002_TX:
623 case RT_PROXY_DAI_002_RX:
624 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
625 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700626 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700627 case VOICE_RECORD_RX:
628 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700629 rc = 0;
630 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700631 default:
632 dev_err(dai->dev, "invalid AFE port ID\n");
633 rc = -EINVAL;
634 break;
635 }
636
637 return rc;
638}
639
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700640static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
641 struct snd_soc_dai *dai)
642{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700643 int rc = 0;
644
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800645 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700646
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800647 if (aux_pcm_count == 0) {
648 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
649 " return\n", __func__, dai->id);
650 mutex_unlock(&aux_pcm_mutex);
651 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700652 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800653
654 aux_pcm_count--;
655
656 if (aux_pcm_count > 0) {
657 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
658 __func__, dai->id, aux_pcm_count);
659 mutex_unlock(&aux_pcm_mutex);
660 return;
661 } else if (aux_pcm_count < 0) {
662 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
663 " aux_pcm_count = %d < 0\n",
664 __func__, dai->id, aux_pcm_count);
665 aux_pcm_count = 0;
666 mutex_unlock(&aux_pcm_mutex);
667 return;
668 }
669
670 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
671 dai->id, aux_pcm_count);
672
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530673 clk_disable_unprepare(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800674 rc = afe_close(PCM_RX); /* can block */
675 if (IS_ERR_VALUE(rc))
676 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
677
678 rc = afe_close(PCM_TX);
679 if (IS_ERR_VALUE(rc))
680 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
681
682 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700683}
684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
686 struct snd_soc_dai *dai)
687{
688 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530689 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700692 switch (dai->id) {
693 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700694 case VOICE_RECORD_TX:
695 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700696 pr_debug("%s, stop pseudo port:%d\n",
697 __func__, dai->id);
698 rc = afe_stop_pseudo_port(dai->id);
699 break;
700 default:
701 rc = afe_close(dai->id); /* can block */
702 break;
703 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 if (IS_ERR_VALUE(rc))
705 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530706 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
707 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700708 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
709 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700710}
711
712static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
713 struct snd_soc_dai *dai)
714{
715 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
716 int rc = 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700717 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
718 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
Kuirong Wang547a9982012-05-04 18:29:11 -0700719 unsigned long pcm_clk_rate;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700720
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800721 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700722
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800723 if (aux_pcm_count == 2) {
724 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
725 " return.\n", __func__, dai->id);
726 mutex_unlock(&aux_pcm_mutex);
727 return 0;
728 } else if (aux_pcm_count > 2) {
729 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
730 " aux_pcm_count = %d > 2\n",
731 __func__, dai->id, aux_pcm_count);
732 mutex_unlock(&aux_pcm_mutex);
733 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700734 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800735
736 aux_pcm_count++;
737 if (aux_pcm_count == 2) {
738 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
739 " increment\n", __func__, dai->id, aux_pcm_count);
740 mutex_unlock(&aux_pcm_mutex);
741 return 0;
742 }
743
744 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
745 __func__, dai->id, aux_pcm_count);
746
747 rc = afe_q6_interface_prepare();
748 if (IS_ERR_VALUE(rc))
749 dev_err(dai->dev, "fail to open AFE APR\n");
750
751 /*
752 * For AUX PCM Interface the below sequence of clk
753 * settings and afe_open is a strict requirement.
754 *
755 * Also using afe_open instead of afe_port_start_nowait
756 * to make sure the port is open before deasserting the
757 * clock line. This is required because pcm register is
758 * not written before clock deassert. Hence the hw does
759 * not get updated with new setting if the below clock
760 * assert/deasset and afe_open sequence is not followed.
761 */
762
763 clk_reset(pcm_clk, CLK_RESET_ASSERT);
764
765 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
766
767 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
Kuirong Wang547a9982012-05-04 18:29:11 -0700768 if (dai_data->rate == 8000) {
769 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
770 } else if (dai_data->rate == 16000) {
771 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
772 } else {
773 dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
774 dai_data->rate);
775 return -EINVAL;
776 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800777
Kuirong Wang547a9982012-05-04 18:29:11 -0700778 rc = clk_set_rate(pcm_clk, pcm_clk_rate);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800779 if (rc < 0) {
780 pr_err("%s: clk_set_rate failed\n", __func__);
781 return rc;
782 }
783
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530784 clk_prepare_enable(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800785 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
786
787 mutex_unlock(&aux_pcm_mutex);
788
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700789 return rc;
790}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700791
792static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
793 struct snd_soc_dai *dai)
794{
795 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
796 int rc = 0;
797
Patrick Lai831561e2011-07-26 22:51:27 -0700798 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700799 /* PORT START should be set if prepare called in active state */
800 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700802 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805}
806
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700807static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
808 int cmd, struct snd_soc_dai *dai)
809{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700810 int rc = 0;
811
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800812 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
813 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700814
815 switch (cmd) {
816
817 case SNDRV_PCM_TRIGGER_START:
818 case SNDRV_PCM_TRIGGER_RESUME:
819 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
820 /* afe_open will be called from prepare */
821 return 0;
822
823 case SNDRV_PCM_TRIGGER_STOP:
824 case SNDRV_PCM_TRIGGER_SUSPEND:
825 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800826 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700827
828 default:
829 rc = -EINVAL;
830 }
831
832 return rc;
833
834}
835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
837 struct snd_soc_dai *dai)
838{
839 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
840 int rc = 0;
841
842 /* Start/stop port without waiting for Q6 AFE response. Need to have
843 * native q6 AFE driver propagates AFE response in order to handle
844 * port start/stop command error properly if error does arise.
845 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530846 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
847 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700848 switch (cmd) {
849 case SNDRV_PCM_TRIGGER_START:
850 case SNDRV_PCM_TRIGGER_RESUME:
851 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
852 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700853 switch (dai->id) {
854 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700855 case VOICE_RECORD_TX:
856 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700857 afe_pseudo_port_start_nowait(dai->id);
858 break;
859 default:
860 afe_port_start_nowait(dai->id,
861 &dai_data->port_config, dai_data->rate);
862 break;
863 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 set_bit(STATUS_PORT_STARTED,
865 dai_data->status_mask);
866 }
867 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 case SNDRV_PCM_TRIGGER_STOP:
869 case SNDRV_PCM_TRIGGER_SUSPEND:
870 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
871 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700872 switch (dai->id) {
873 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700874 case VOICE_RECORD_TX:
875 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700876 afe_pseudo_port_stop_nowait(dai->id);
877 break;
878 default:
879 afe_port_stop_nowait(dai->id);
880 break;
881 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882 clear_bit(STATUS_PORT_STARTED,
883 dai_data->status_mask);
884 }
885 break;
886
887 default:
888 rc = -EINVAL;
889 }
890
891 return rc;
892}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700893static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
894{
895 struct msm_dai_q6_dai_data *dai_data;
896 int rc = 0;
897
898 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
899 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
900
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800901 mutex_lock(&aux_pcm_mutex);
902
903 if (!auxpcm_plat_data)
904 auxpcm_plat_data = auxpcm_pdata;
905 else if (auxpcm_plat_data != auxpcm_pdata) {
906
907 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
908 " same platform data\n");
909 return -EINVAL;
910 }
911
912 /*
913 * The clk name for AUX PCM operation is passed as platform
914 * data to the cpu driver, since cpu drive is unaware of any
915 * boarc specific configuration.
916 */
917 if (!pcm_clk) {
918
919 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
920
921 if (IS_ERR(pcm_clk)) {
922 pr_err("%s: could not get pcm_clk\n", __func__);
923 pcm_clk = NULL;
924 return -ENODEV;
925 }
926 }
927
928 mutex_unlock(&aux_pcm_mutex);
929
930 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700931
932 if (!dai_data) {
933 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
934 dai->id);
935 rc = -ENOMEM;
936 } else
937 dev_set_drvdata(dai->dev, dai_data);
938
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800939 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700940 return rc;
941}
942
943static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
944{
945 struct msm_dai_q6_dai_data *dai_data;
946 int rc;
947
948 dai_data = dev_get_drvdata(dai->dev);
949
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800950 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700951
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800952 if (aux_pcm_count == 0) {
953 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
954 " up and return\n", __func__, dai->id);
955 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700956 }
957
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800958 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700959
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800960 if (aux_pcm_count > 0) {
961 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
962 __func__, dai->id, aux_pcm_count);
963 goto done;
964 } else if (aux_pcm_count < 0) {
965 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
966 " aux_pcm_count = %d < 0\n",
967 __func__, dai->id, aux_pcm_count);
968 goto done;
969 }
970
971 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
972 "closing afe\n",
973 __func__, dai->id, aux_pcm_count);
974
975 rc = afe_close(PCM_RX); /* can block */
976 if (IS_ERR_VALUE(rc))
977 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
978
979 rc = afe_close(PCM_TX);
980 if (IS_ERR_VALUE(rc))
981 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
982
983done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700984 kfree(dai_data);
985 snd_soc_unregister_dai(dai->dev);
986
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800987 mutex_unlock(&aux_pcm_mutex);
988
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700989 return 0;
990}
Patrick Lai04baee942012-05-01 14:38:47 -0700991
Kuirong Wang274f21a2011-12-15 21:29:08 -0800992static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
993{
Patrick Lai04baee942012-05-01 14:38:47 -0700994 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
995 dev_get_drvdata(dai->dev);
996 struct snd_kcontrol *kcontrol = NULL;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800997 int rc = 0;
998
Patrick Lai04baee942012-05-01 14:38:47 -0700999 if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
1000 kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
1001 &mi2s_dai_data->rx_dai);
1002 rc = snd_ctl_add(dai->card->snd_card, kcontrol);
Kuirong Wang274f21a2011-12-15 21:29:08 -08001003
Patrick Lai04baee942012-05-01 14:38:47 -07001004 if (IS_ERR_VALUE(rc)) {
1005 dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
1006 goto rtn;
1007 }
Kuirong Wang274f21a2011-12-15 21:29:08 -08001008 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001009
Patrick Lai04baee942012-05-01 14:38:47 -07001010 if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
1011 rc = snd_ctl_add(dai->card->snd_card,
1012 snd_ctl_new1(&mi2s_config_controls[2],
1013 &mi2s_dai_data->tx_dai));
1014
1015 if (IS_ERR_VALUE(rc)) {
1016 if (kcontrol)
1017 snd_ctl_remove(dai->card->snd_card, kcontrol);
1018 dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
1019 }
1020 }
1021
Kuirong Wang274f21a2011-12-15 21:29:08 -08001022rtn:
1023 return rc;
1024}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025
Patrick Lai04baee942012-05-01 14:38:47 -07001026static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
1027{
1028 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
1029 dev_get_drvdata(dai->dev);
1030 int rc;
1031
1032 /* If AFE port is still up, close it */
1033 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
1034 rc = afe_close(MI2S_RX); /* can block */
1035 if (IS_ERR_VALUE(rc))
1036 dev_err(dai->dev, "fail to close MI2S_RX port\n");
1037 clear_bit(STATUS_PORT_STARTED,
1038 mi2s_dai_data->rx_dai.status_mask);
1039 }
1040 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
1041 rc = afe_close(MI2S_TX); /* can block */
1042 if (IS_ERR_VALUE(rc))
1043 dev_err(dai->dev, "fail to close MI2S_TX port\n");
1044 clear_bit(STATUS_PORT_STARTED,
1045 mi2s_dai_data->tx_dai.status_mask);
1046 }
1047 kfree(mi2s_dai_data);
1048 snd_soc_unregister_dai(dai->dev);
1049
1050 return 0;
1051}
1052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
1054{
1055 struct msm_dai_q6_dai_data *dai_data;
1056 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001057 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001058
1059 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
1060 GFP_KERNEL);
1061
1062 if (!dai_data) {
1063 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
1064 dai->id);
1065 rc = -ENOMEM;
1066 } else
1067 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001068 if (dai->id == SECONDARY_I2S_RX) {
1069 kcontrol = &mi2s_config_controls[1];
1070 rc = snd_ctl_add(dai->card->snd_card,
1071 snd_ctl_new1(kcontrol, dai_data));
1072 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073
1074 return rc;
1075}
1076
1077static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
1078{
1079 struct msm_dai_q6_dai_data *dai_data;
1080 int rc;
1081
1082 dai_data = dev_get_drvdata(dai->dev);
1083
1084 /* If AFE port is still up, close it */
1085 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -07001086 switch (dai->id) {
1087 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -07001088 case VOICE_RECORD_TX:
1089 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -07001090 pr_debug("%s, stop pseudo port:%d\n",
1091 __func__, dai->id);
1092 rc = afe_stop_pseudo_port(dai->id);
1093 break;
1094 default:
1095 rc = afe_close(dai->id); /* can block */
1096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001097 if (IS_ERR_VALUE(rc))
1098 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301099 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 }
1101 kfree(dai_data);
1102 snd_soc_unregister_dai(dai->dev);
1103
1104 return 0;
1105}
1106
Lei Zhou157c1842011-08-19 13:05:04 -04001107static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1108{
1109 int rc = 0;
1110
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001111 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
1112 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -04001113 switch (dai->id) {
1114 case PRIMARY_I2S_TX:
1115 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001116 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -04001117 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
1118 break;
1119 default:
1120 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1121 rc = -EINVAL;
1122 break;
1123 }
1124
1125 return rc;
1126}
1127
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001128static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
1129 unsigned int tx_num, unsigned int *tx_slot,
1130 unsigned int rx_num, unsigned int *rx_slot)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001131{
1132 int rc = 0;
1133 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
1134 unsigned int i = 0;
1135
Kiran Kandifd30c892012-05-21 23:03:26 -07001136 dev_dbg(dai->dev, "%s: dai_id = %d\n", __func__, dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001137 switch (dai->id) {
1138 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001139 case SLIMBUS_1_RX:
Kiran Kandifd30c892012-05-21 23:03:26 -07001140 case SLIMBUS_2_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -07001141 case SLIMBUS_3_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001142 case SLIMBUS_4_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001143 /* channel number to be between 128 and 255. For RX port
1144 * use channel numbers from 138 to 144, for TX port
1145 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001146 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001147 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001148 if (!rx_slot)
1149 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001150 for (i = 0; i < rx_num; i++) {
1151 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1152 rx_slot[i];
1153 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1154 __func__, i,
1155 rx_slot[i]);
1156 }
1157 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001158 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
1159 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001160 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1161 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1162
1163 break;
1164 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001165 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001166 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001167 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001168 /* channel number to be between 128 and 255. For RX port
1169 * use channel numbers from 138 to 144, for TX port
1170 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001171 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001172 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001173 if (!tx_slot)
1174 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001175 for (i = 0; i < tx_num; i++) {
1176 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1177 tx_slot[i];
1178 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1179 __func__, i, tx_slot[i]);
1180 }
1181 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001182 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
1183 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001184 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1185 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1186 break;
1187 default:
1188 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1189 rc = -EINVAL;
1190 break;
1191 }
1192 return rc;
1193}
1194
Patrick Lai04baee942012-05-01 14:38:47 -07001195static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
1196 .startup = msm_dai_q6_mi2s_startup,
1197 .prepare = msm_dai_q6_mi2s_prepare,
1198 .trigger = msm_dai_q6_mi2s_trigger,
1199 .hw_params = msm_dai_q6_mi2s_hw_params,
1200 .shutdown = msm_dai_q6_mi2s_shutdown,
1201 .set_fmt = msm_dai_q6_mi2s_set_fmt,
1202};
1203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 .prepare = msm_dai_q6_prepare,
1206 .trigger = msm_dai_q6_trigger,
1207 .hw_params = msm_dai_q6_hw_params,
1208 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -04001209 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001210 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211};
1212
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001213static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
1214 .prepare = msm_dai_q6_auxpcm_prepare,
1215 .trigger = msm_dai_q6_auxpcm_trigger,
1216 .hw_params = msm_dai_q6_auxpcm_hw_params,
1217 .shutdown = msm_dai_q6_auxpcm_shutdown,
1218};
1219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
1221 .playback = {
1222 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1223 SNDRV_PCM_RATE_16000,
1224 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1225 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -08001226 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227 .rate_min = 8000,
1228 .rate_max = 48000,
1229 },
1230 .ops = &msm_dai_q6_ops,
1231 .probe = msm_dai_q6_dai_probe,
1232 .remove = msm_dai_q6_dai_remove,
1233};
1234
1235static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
1236 .capture = {
1237 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1238 SNDRV_PCM_RATE_16000,
1239 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1240 .channels_min = 1,
1241 .channels_max = 2,
1242 .rate_min = 8000,
1243 .rate_max = 48000,
1244 },
1245 .ops = &msm_dai_q6_ops,
1246 .probe = msm_dai_q6_dai_probe,
1247 .remove = msm_dai_q6_dai_remove,
1248};
1249
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301250static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
1251 .playback = {
1252 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1253 SNDRV_PCM_RATE_16000,
1254 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1255 .channels_min = 1,
1256 .channels_max = 2,
1257 .rate_min = 8000,
1258 .rate_max = 48000,
1259 },
1260 .ops = &msm_dai_q6_ops,
1261 .probe = msm_dai_q6_dai_probe,
1262 .remove = msm_dai_q6_dai_remove,
1263};
1264
1265static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1266 .capture = {
1267 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1268 SNDRV_PCM_RATE_16000,
1269 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1270 .channels_min = 1,
Mingming Yin647e9ea2012-03-17 19:56:10 -07001271 .channels_max = 4,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301272 .rate_min = 8000,
1273 .rate_max = 48000,
1274 },
1275 .ops = &msm_dai_q6_ops,
1276 .probe = msm_dai_q6_dai_probe,
1277 .remove = msm_dai_q6_dai_remove,
1278};
1279
Helen Zeng0705a5f2011-10-14 15:29:52 -07001280static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1281 .playback = {
1282 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1283 SNDRV_PCM_RATE_16000,
1284 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1285 .channels_min = 1,
1286 .channels_max = 2,
1287 .rate_max = 48000,
1288 .rate_min = 8000,
1289 },
1290 .ops = &msm_dai_q6_ops,
1291 .probe = msm_dai_q6_dai_probe,
1292 .remove = msm_dai_q6_dai_remove,
1293};
1294
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1296 .playback = {
1297 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1298 SNDRV_PCM_RATE_16000,
1299 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1300 .channels_min = 1,
1301 .channels_max = 2,
1302 .rate_min = 8000,
1303 .rate_max = 48000,
1304 },
1305 .ops = &msm_dai_q6_ops,
1306 .probe = msm_dai_q6_dai_probe,
1307 .remove = msm_dai_q6_dai_remove,
1308};
1309
1310static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1311 .capture = {
1312 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1313 SNDRV_PCM_RATE_16000,
1314 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1315 .channels_min = 1,
1316 .channels_max = 2,
1317 .rate_min = 8000,
1318 .rate_max = 48000,
1319 },
1320 .ops = &msm_dai_q6_ops,
1321 .probe = msm_dai_q6_dai_probe,
1322 .remove = msm_dai_q6_dai_remove,
1323};
1324
Helen Zenge3d716a2011-10-14 16:32:16 -07001325static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1326 .capture = {
1327 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1328 SNDRV_PCM_RATE_16000,
1329 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1330 .channels_min = 1,
1331 .channels_max = 2,
1332 .rate_min = 8000,
1333 .rate_max = 48000,
1334 },
1335 .ops = &msm_dai_q6_ops,
1336 .probe = msm_dai_q6_dai_probe,
1337 .remove = msm_dai_q6_dai_remove,
1338};
1339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1341 .playback = {
1342 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1343 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1344 .channels_min = 1,
1345 .channels_max = 1,
1346 .rate_max = 16000,
1347 .rate_min = 8000,
1348 },
1349 .ops = &msm_dai_q6_ops,
1350 .probe = msm_dai_q6_dai_probe,
1351 .remove = msm_dai_q6_dai_remove,
1352};
1353
1354static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1355 .playback = {
1356 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1357 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1358 .channels_min = 1,
1359 .channels_max = 1,
1360 .rate_max = 16000,
1361 .rate_min = 8000,
1362 },
1363 .ops = &msm_dai_q6_ops,
1364 .probe = msm_dai_q6_dai_probe,
1365 .remove = msm_dai_q6_dai_remove,
1366};
1367
1368static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1369 .playback = {
1370 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1371 SNDRV_PCM_RATE_16000,
1372 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1373 .channels_min = 2,
1374 .channels_max = 2,
1375 .rate_max = 48000,
1376 .rate_min = 8000,
1377 },
1378 .ops = &msm_dai_q6_ops,
1379 .probe = msm_dai_q6_dai_probe,
1380 .remove = msm_dai_q6_dai_remove,
1381};
1382
1383static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1384 .playback = {
1385 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1386 SNDRV_PCM_RATE_16000,
1387 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1388 .channels_min = 2,
1389 .channels_max = 2,
1390 .rate_max = 48000,
1391 .rate_min = 8000,
1392 },
1393 .ops = &msm_dai_q6_ops,
1394 .probe = msm_dai_q6_dai_probe,
1395 .remove = msm_dai_q6_dai_remove,
1396};
1397
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001398static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1399 .playback = {
Kuirong Wang547a9982012-05-04 18:29:11 -07001400 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001401 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1402 .channels_min = 1,
1403 .channels_max = 1,
Kuirong Wang547a9982012-05-04 18:29:11 -07001404 .rate_max = 16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001405 .rate_min = 8000,
1406 },
1407 .ops = &msm_dai_q6_auxpcm_ops,
1408 .probe = msm_dai_q6_dai_auxpcm_probe,
1409 .remove = msm_dai_q6_dai_auxpcm_remove,
1410};
1411
1412static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1413 .capture = {
Kuirong Wang547a9982012-05-04 18:29:11 -07001414 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001415 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1416 .channels_min = 1,
1417 .channels_max = 1,
Kuirong Wang547a9982012-05-04 18:29:11 -07001418 .rate_max = 16000,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001419 .rate_min = 8000,
1420 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001421 .ops = &msm_dai_q6_auxpcm_ops,
1422 .probe = msm_dai_q6_dai_auxpcm_probe,
1423 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001424};
1425
Patrick Lai04baee942012-05-01 14:38:47 -07001426/* Channel min and max are initialized base on platform data */
1427static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
Kuirong Wang274f21a2011-12-15 21:29:08 -08001428 .playback = {
1429 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1430 SNDRV_PCM_RATE_16000,
1431 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Kuirong Wang274f21a2011-12-15 21:29:08 -08001432 .rate_min = 8000,
1433 .rate_max = 48000,
1434 },
Kuirong Wang623b50f2012-04-16 15:51:14 -07001435 .capture = {
1436 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1437 SNDRV_PCM_RATE_16000,
1438 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Patrick Lai04baee942012-05-01 14:38:47 -07001439 .rate_min = 8000,
1440 .rate_max = 48000,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001441 },
Patrick Lai04baee942012-05-01 14:38:47 -07001442 .ops = &msm_dai_q6_mi2s_ops,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001443 .probe = msm_dai_q6_dai_mi2s_probe,
Patrick Lai04baee942012-05-01 14:38:47 -07001444 .remove = msm_dai_q6_dai_mi2s_remove,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001445};
1446
Neema Shetty3c9d2862012-03-11 01:25:32 -08001447static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1448 .playback = {
1449 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1450 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1451 .channels_min = 1,
1452 .channels_max = 1,
1453 .rate_min = 8000,
1454 .rate_max = 16000,
1455 },
1456 .ops = &msm_dai_q6_ops,
1457 .probe = msm_dai_q6_dai_probe,
1458 .remove = msm_dai_q6_dai_remove,
1459};
1460
1461static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1462 .capture = {
1463 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1464 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1465 .channels_min = 1,
1466 .channels_max = 1,
1467 .rate_min = 8000,
1468 .rate_max = 16000,
1469 },
1470 .ops = &msm_dai_q6_ops,
1471 .probe = msm_dai_q6_dai_probe,
1472 .remove = msm_dai_q6_dai_remove,
1473};
1474
Kiran Kandifd30c892012-05-21 23:03:26 -07001475static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_rx_dai = {
1476 .playback = {
1477 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1478 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1479 SNDRV_PCM_RATE_192000,
1480 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1481 .channels_min = 1,
1482 .channels_max = 2,
1483 .rate_min = 8000,
1484 .rate_max = 192000,
1485 },
1486 .ops = &msm_dai_q6_ops,
1487 .probe = msm_dai_q6_dai_probe,
1488 .remove = msm_dai_q6_dai_remove,
1489};
1490
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001491static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1492 .capture = {
1493 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1494 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1495 SNDRV_PCM_RATE_192000,
1496 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1497 .channels_min = 1,
1498 .channels_max = 4,
1499 .rate_min = 8000,
1500 .rate_max = 192000,
1501 },
1502 .ops = &msm_dai_q6_ops,
1503 .probe = msm_dai_q6_dai_probe,
1504 .remove = msm_dai_q6_dai_remove,
1505};
1506
Neema Shetty74131ac2012-05-09 13:35:26 -07001507static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
1508 .playback = {
1509 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
1510 SNDRV_PCM_RATE_48000,
1511 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1512 .channels_min = 1,
1513 .channels_max = 2,
1514 .rate_min = 8000,
1515 .rate_max = 48000,
1516 },
1517 .ops = &msm_dai_q6_ops,
1518 .probe = msm_dai_q6_dai_probe,
1519 .remove = msm_dai_q6_dai_remove,
1520};
1521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522/* To do: change to register DAIs as batch */
1523static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1524{
1525 int rc = 0;
1526
1527 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1528
1529 switch (pdev->id) {
1530 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001531 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1533 break;
1534 case PRIMARY_I2S_TX:
1535 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1536 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001537 case PCM_RX:
1538 rc = snd_soc_register_dai(&pdev->dev,
1539 &msm_dai_q6_aux_pcm_rx_dai);
1540 break;
1541 case PCM_TX:
1542 rc = snd_soc_register_dai(&pdev->dev,
1543 &msm_dai_q6_aux_pcm_tx_dai);
1544 break;
Patrick Lai04baee942012-05-01 14:38:47 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001547 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 rc = snd_soc_register_dai(&pdev->dev,
1549 &msm_dai_q6_slimbus_rx_dai);
1550 break;
1551 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001552 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 rc = snd_soc_register_dai(&pdev->dev,
1554 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001555 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001556 case SLIMBUS_1_RX:
1557 rc = snd_soc_register_dai(&pdev->dev,
1558 &msm_dai_q6_slimbus_1_rx_dai);
1559 break;
1560 case SLIMBUS_1_TX:
1561 rc = snd_soc_register_dai(&pdev->dev,
1562 &msm_dai_q6_slimbus_1_tx_dai);
1563 break;
Kiran Kandifd30c892012-05-21 23:03:26 -07001564 case SLIMBUS_2_RX:
1565 rc = snd_soc_register_dai(&pdev->dev,
1566 &msm_dai_q6_slimbus_2_rx_dai);
1567 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001568 case SLIMBUS_2_TX:
1569 rc = snd_soc_register_dai(&pdev->dev,
1570 &msm_dai_q6_slimbus_2_tx_dai);
1571 break;
Neema Shetty74131ac2012-05-09 13:35:26 -07001572 case SLIMBUS_3_RX:
1573 rc = snd_soc_register_dai(&pdev->dev,
1574 &msm_dai_q6_slimbus_3_rx_dai);
1575 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 case INT_BT_SCO_RX:
1577 rc = snd_soc_register_dai(&pdev->dev,
1578 &msm_dai_q6_bt_sco_rx_dai);
1579 break;
1580 case INT_BT_SCO_TX:
1581 rc = snd_soc_register_dai(&pdev->dev,
1582 &msm_dai_q6_bt_sco_tx_dai);
1583 break;
1584 case INT_FM_RX:
1585 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1586 break;
1587 case INT_FM_TX:
1588 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1589 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301590 case RT_PROXY_DAI_001_RX:
1591 case RT_PROXY_DAI_002_RX:
1592 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1593 break;
1594 case RT_PROXY_DAI_001_TX:
1595 case RT_PROXY_DAI_002_TX:
1596 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1597 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001598 case VOICE_PLAYBACK_TX:
1599 rc = snd_soc_register_dai(&pdev->dev,
1600 &msm_dai_q6_voice_playback_tx_dai);
1601 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001602 case VOICE_RECORD_RX:
1603 case VOICE_RECORD_TX:
1604 rc = snd_soc_register_dai(&pdev->dev,
1605 &msm_dai_q6_incall_record_dai);
1606 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 default:
1608 rc = -ENODEV;
1609 break;
1610 }
1611 return rc;
1612}
1613
1614static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1615{
1616 snd_soc_unregister_dai(&pdev->dev);
1617 return 0;
1618}
1619
Patrick Lai04baee942012-05-01 14:38:47 -07001620static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
1621{
1622 struct msm_dai_q6_mi2s_dai_data *dai_data;
1623 int rc = 0;
1624
1625 dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
1626
1627 dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
1628 GFP_KERNEL);
1629
1630 if (!dai_data) {
1631 dev_err(&pdev->dev, "fail to allocate dai data\n");
1632 rc = -ENOMEM;
1633 goto rtn;
1634 } else
1635 dev_set_drvdata(&pdev->dev, dai_data);
1636
1637 rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
1638 &msm_dai_q6_mi2s_dai);
1639 if (IS_ERR_VALUE(rc))
1640 goto err_pdata;
1641
1642 dai_data->rate_constraint.count = 1;
1643 dai_data->bitwidth_constraint.count = 1;
1644 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
1645
1646 if (IS_ERR_VALUE(rc))
1647 goto err_pdata;
1648
1649 return 0;
1650
1651err_pdata:
1652 kfree(dai_data);
1653rtn:
1654 return rc;
1655}
1656
1657static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
1658{
1659 snd_soc_unregister_dai(&pdev->dev);
1660 return 0;
1661}
1662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663static struct platform_driver msm_dai_q6_driver = {
1664 .probe = msm_dai_q6_dev_probe,
1665 .remove = msm_dai_q6_dev_remove,
1666 .driver = {
1667 .name = "msm-dai-q6",
1668 .owner = THIS_MODULE,
1669 },
1670};
1671
Patrick Lai04baee942012-05-01 14:38:47 -07001672static struct platform_driver msm_dai_q6_mi2s_driver = {
1673 .probe = msm_dai_q6_mi2s_dev_probe,
1674 .remove = msm_dai_q6_mi2s_dev_remove,
1675 .driver = {
1676 .name = "msm-dai-q6-mi2s",
1677 .owner = THIS_MODULE,
1678 },
1679};
1680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001681static int __init msm_dai_q6_init(void)
1682{
Patrick Lai04baee942012-05-01 14:38:47 -07001683 int rc1, rc2;
1684
1685 rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
1686
1687 if (IS_ERR_VALUE(rc1))
1688 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1689
1690 rc2 = platform_driver_register(&msm_dai_q6_driver);
1691
1692 if (IS_ERR_VALUE(rc2))
1693 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1694
1695 return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001696}
1697module_init(msm_dai_q6_init);
1698
1699static void __exit msm_dai_q6_exit(void)
1700{
1701 platform_driver_unregister(&msm_dai_q6_driver);
1702}
1703module_exit(msm_dai_q6_exit);
1704
1705/* Module information */
1706MODULE_DESCRIPTION("MSM DSP DAI driver");
1707MODULE_LICENSE("GPL v2");