blob: fb7756c10ab1ddb266c0ca7a88a4434e4b8100c6 [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
535 if (params_rate(params) != 8000) {
536 dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
537 return -EINVAL;
538 }
539 dai_data->rate = params_rate(params);
540 dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
541 dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
542 dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
543 dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
544 dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
545 dai_data->port_config.pcm.data = auxpcm_pdata->data;
546
547 return 0;
548}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530550static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
551 struct snd_soc_dai *dai)
552{
553 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
554
555 dai_data->rate = params_rate(params);
556 dai_data->port_config.rtproxy.num_ch =
557 params_channels(params);
558
559 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
560 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
561
562 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
563 dai_data->port_config.rtproxy.interleaved = 1;
Asish Bhattacharyab3568cf2012-03-15 07:05:46 +0530564 dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530565 dai_data->port_config.rtproxy.jitter =
566 dai_data->port_config.rtproxy.frame_sz/2;
567 dai_data->port_config.rtproxy.lw_mark = 0;
568 dai_data->port_config.rtproxy.hw_mark = 0;
569 dai_data->port_config.rtproxy.rsvd = 0;
570
571 return 0;
572}
573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574/* Current implementation assumes hw_param is called once
575 * This may not be the case but what to do when ADM and AFE
576 * port are already opened and parameter changes
577 */
578static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
579 struct snd_pcm_hw_params *params,
580 struct snd_soc_dai *dai)
581{
582 int rc = 0;
583
584 switch (dai->id) {
585 case PRIMARY_I2S_TX:
586 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800587 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
589 break;
Patrick Lai04baee942012-05-01 14:38:47 -0700590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800592 case SLIMBUS_1_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -0700593 case SLIMBUS_3_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800595 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700596 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800597 case SLIMBUS_4_RX:
598 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
600 substream->stream);
601 break;
602 case INT_BT_SCO_RX:
603 case INT_BT_SCO_TX:
604 case INT_FM_RX:
605 case INT_FM_TX:
606 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
607 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530608 case RT_PROXY_DAI_001_TX:
609 case RT_PROXY_DAI_001_RX:
610 case RT_PROXY_DAI_002_TX:
611 case RT_PROXY_DAI_002_RX:
612 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
613 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700614 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700615 case VOICE_RECORD_RX:
616 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700617 rc = 0;
618 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 default:
620 dev_err(dai->dev, "invalid AFE port ID\n");
621 rc = -EINVAL;
622 break;
623 }
624
625 return rc;
626}
627
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700628static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
629 struct snd_soc_dai *dai)
630{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700631 int rc = 0;
632
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800633 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700634
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800635 if (aux_pcm_count == 0) {
636 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
637 " return\n", __func__, dai->id);
638 mutex_unlock(&aux_pcm_mutex);
639 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700640 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800641
642 aux_pcm_count--;
643
644 if (aux_pcm_count > 0) {
645 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
646 __func__, dai->id, aux_pcm_count);
647 mutex_unlock(&aux_pcm_mutex);
648 return;
649 } else if (aux_pcm_count < 0) {
650 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
651 " aux_pcm_count = %d < 0\n",
652 __func__, dai->id, aux_pcm_count);
653 aux_pcm_count = 0;
654 mutex_unlock(&aux_pcm_mutex);
655 return;
656 }
657
658 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
659 dai->id, aux_pcm_count);
660
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530661 clk_disable_unprepare(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800662 rc = afe_close(PCM_RX); /* can block */
663 if (IS_ERR_VALUE(rc))
664 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
665
666 rc = afe_close(PCM_TX);
667 if (IS_ERR_VALUE(rc))
668 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
669
670 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700671}
672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
674 struct snd_soc_dai *dai)
675{
676 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530677 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700679 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700680 switch (dai->id) {
681 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700682 case VOICE_RECORD_TX:
683 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700684 pr_debug("%s, stop pseudo port:%d\n",
685 __func__, dai->id);
686 rc = afe_stop_pseudo_port(dai->id);
687 break;
688 default:
689 rc = afe_close(dai->id); /* can block */
690 break;
691 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700692 if (IS_ERR_VALUE(rc))
693 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530694 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
695 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
697 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700698}
699
700static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
701 struct snd_soc_dai *dai)
702{
703 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
704 int rc = 0;
705
706 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
707 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
708
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800709 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700710
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800711 if (aux_pcm_count == 2) {
712 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
713 " return.\n", __func__, dai->id);
714 mutex_unlock(&aux_pcm_mutex);
715 return 0;
716 } else if (aux_pcm_count > 2) {
717 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
718 " aux_pcm_count = %d > 2\n",
719 __func__, dai->id, aux_pcm_count);
720 mutex_unlock(&aux_pcm_mutex);
721 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700722 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800723
724 aux_pcm_count++;
725 if (aux_pcm_count == 2) {
726 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
727 " increment\n", __func__, dai->id, aux_pcm_count);
728 mutex_unlock(&aux_pcm_mutex);
729 return 0;
730 }
731
732 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
733 __func__, dai->id, aux_pcm_count);
734
735 rc = afe_q6_interface_prepare();
736 if (IS_ERR_VALUE(rc))
737 dev_err(dai->dev, "fail to open AFE APR\n");
738
739 /*
740 * For AUX PCM Interface the below sequence of clk
741 * settings and afe_open is a strict requirement.
742 *
743 * Also using afe_open instead of afe_port_start_nowait
744 * to make sure the port is open before deasserting the
745 * clock line. This is required because pcm register is
746 * not written before clock deassert. Hence the hw does
747 * not get updated with new setting if the below clock
748 * assert/deasset and afe_open sequence is not followed.
749 */
750
751 clk_reset(pcm_clk, CLK_RESET_ASSERT);
752
753 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
754
755 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
756
757 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
758 if (rc < 0) {
759 pr_err("%s: clk_set_rate failed\n", __func__);
760 return rc;
761 }
762
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530763 clk_prepare_enable(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800764 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
765
766 mutex_unlock(&aux_pcm_mutex);
767
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700768 return rc;
769}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770
771static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
772 struct snd_soc_dai *dai)
773{
774 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
775 int rc = 0;
776
Patrick Lai831561e2011-07-26 22:51:27 -0700777 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700778 /* PORT START should be set if prepare called in active state */
779 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700781 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784}
785
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700786static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
787 int cmd, struct snd_soc_dai *dai)
788{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700789 int rc = 0;
790
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800791 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
792 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700793
794 switch (cmd) {
795
796 case SNDRV_PCM_TRIGGER_START:
797 case SNDRV_PCM_TRIGGER_RESUME:
798 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
799 /* afe_open will be called from prepare */
800 return 0;
801
802 case SNDRV_PCM_TRIGGER_STOP:
803 case SNDRV_PCM_TRIGGER_SUSPEND:
804 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800805 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700806
807 default:
808 rc = -EINVAL;
809 }
810
811 return rc;
812
813}
814
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
816 struct snd_soc_dai *dai)
817{
818 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
819 int rc = 0;
820
821 /* Start/stop port without waiting for Q6 AFE response. Need to have
822 * native q6 AFE driver propagates AFE response in order to handle
823 * port start/stop command error properly if error does arise.
824 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530825 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
826 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700827 switch (cmd) {
828 case SNDRV_PCM_TRIGGER_START:
829 case SNDRV_PCM_TRIGGER_RESUME:
830 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
831 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700832 switch (dai->id) {
833 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700834 case VOICE_RECORD_TX:
835 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700836 afe_pseudo_port_start_nowait(dai->id);
837 break;
838 default:
839 afe_port_start_nowait(dai->id,
840 &dai_data->port_config, dai_data->rate);
841 break;
842 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 set_bit(STATUS_PORT_STARTED,
844 dai_data->status_mask);
845 }
846 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 case SNDRV_PCM_TRIGGER_STOP:
848 case SNDRV_PCM_TRIGGER_SUSPEND:
849 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
850 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700851 switch (dai->id) {
852 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700853 case VOICE_RECORD_TX:
854 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700855 afe_pseudo_port_stop_nowait(dai->id);
856 break;
857 default:
858 afe_port_stop_nowait(dai->id);
859 break;
860 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861 clear_bit(STATUS_PORT_STARTED,
862 dai_data->status_mask);
863 }
864 break;
865
866 default:
867 rc = -EINVAL;
868 }
869
870 return rc;
871}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700872static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
873{
874 struct msm_dai_q6_dai_data *dai_data;
875 int rc = 0;
876
877 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
878 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
879
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800880 mutex_lock(&aux_pcm_mutex);
881
882 if (!auxpcm_plat_data)
883 auxpcm_plat_data = auxpcm_pdata;
884 else if (auxpcm_plat_data != auxpcm_pdata) {
885
886 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
887 " same platform data\n");
888 return -EINVAL;
889 }
890
891 /*
892 * The clk name for AUX PCM operation is passed as platform
893 * data to the cpu driver, since cpu drive is unaware of any
894 * boarc specific configuration.
895 */
896 if (!pcm_clk) {
897
898 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
899
900 if (IS_ERR(pcm_clk)) {
901 pr_err("%s: could not get pcm_clk\n", __func__);
902 pcm_clk = NULL;
903 return -ENODEV;
904 }
905 }
906
907 mutex_unlock(&aux_pcm_mutex);
908
909 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700910
911 if (!dai_data) {
912 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
913 dai->id);
914 rc = -ENOMEM;
915 } else
916 dev_set_drvdata(dai->dev, dai_data);
917
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800918 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700919 return rc;
920}
921
922static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
923{
924 struct msm_dai_q6_dai_data *dai_data;
925 int rc;
926
927 dai_data = dev_get_drvdata(dai->dev);
928
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800929 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700930
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800931 if (aux_pcm_count == 0) {
932 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
933 " up and return\n", __func__, dai->id);
934 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700935 }
936
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800937 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700938
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800939 if (aux_pcm_count > 0) {
940 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
941 __func__, dai->id, aux_pcm_count);
942 goto done;
943 } else if (aux_pcm_count < 0) {
944 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
945 " aux_pcm_count = %d < 0\n",
946 __func__, dai->id, aux_pcm_count);
947 goto done;
948 }
949
950 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
951 "closing afe\n",
952 __func__, dai->id, aux_pcm_count);
953
954 rc = afe_close(PCM_RX); /* can block */
955 if (IS_ERR_VALUE(rc))
956 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
957
958 rc = afe_close(PCM_TX);
959 if (IS_ERR_VALUE(rc))
960 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
961
962done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700963 kfree(dai_data);
964 snd_soc_unregister_dai(dai->dev);
965
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800966 mutex_unlock(&aux_pcm_mutex);
967
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700968 return 0;
969}
Patrick Lai04baee942012-05-01 14:38:47 -0700970
Kuirong Wang274f21a2011-12-15 21:29:08 -0800971static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
972{
Patrick Lai04baee942012-05-01 14:38:47 -0700973 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
974 dev_get_drvdata(dai->dev);
975 struct snd_kcontrol *kcontrol = NULL;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800976 int rc = 0;
977
Patrick Lai04baee942012-05-01 14:38:47 -0700978 if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
979 kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
980 &mi2s_dai_data->rx_dai);
981 rc = snd_ctl_add(dai->card->snd_card, kcontrol);
Kuirong Wang274f21a2011-12-15 21:29:08 -0800982
Patrick Lai04baee942012-05-01 14:38:47 -0700983 if (IS_ERR_VALUE(rc)) {
984 dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
985 goto rtn;
986 }
Kuirong Wang274f21a2011-12-15 21:29:08 -0800987 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700988
Patrick Lai04baee942012-05-01 14:38:47 -0700989 if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
990 rc = snd_ctl_add(dai->card->snd_card,
991 snd_ctl_new1(&mi2s_config_controls[2],
992 &mi2s_dai_data->tx_dai));
993
994 if (IS_ERR_VALUE(rc)) {
995 if (kcontrol)
996 snd_ctl_remove(dai->card->snd_card, kcontrol);
997 dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
998 }
999 }
1000
Kuirong Wang274f21a2011-12-15 21:29:08 -08001001rtn:
1002 return rc;
1003}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004
Patrick Lai04baee942012-05-01 14:38:47 -07001005static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
1006{
1007 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
1008 dev_get_drvdata(dai->dev);
1009 int rc;
1010
1011 /* If AFE port is still up, close it */
1012 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
1013 rc = afe_close(MI2S_RX); /* can block */
1014 if (IS_ERR_VALUE(rc))
1015 dev_err(dai->dev, "fail to close MI2S_RX port\n");
1016 clear_bit(STATUS_PORT_STARTED,
1017 mi2s_dai_data->rx_dai.status_mask);
1018 }
1019 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
1020 rc = afe_close(MI2S_TX); /* can block */
1021 if (IS_ERR_VALUE(rc))
1022 dev_err(dai->dev, "fail to close MI2S_TX port\n");
1023 clear_bit(STATUS_PORT_STARTED,
1024 mi2s_dai_data->tx_dai.status_mask);
1025 }
1026 kfree(mi2s_dai_data);
1027 snd_soc_unregister_dai(dai->dev);
1028
1029 return 0;
1030}
1031
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
1033{
1034 struct msm_dai_q6_dai_data *dai_data;
1035 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001036 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037
1038 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
1039 GFP_KERNEL);
1040
1041 if (!dai_data) {
1042 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
1043 dai->id);
1044 rc = -ENOMEM;
1045 } else
1046 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001047 if (dai->id == SECONDARY_I2S_RX) {
1048 kcontrol = &mi2s_config_controls[1];
1049 rc = snd_ctl_add(dai->card->snd_card,
1050 snd_ctl_new1(kcontrol, dai_data));
1051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052
1053 return rc;
1054}
1055
1056static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
1057{
1058 struct msm_dai_q6_dai_data *dai_data;
1059 int rc;
1060
1061 dai_data = dev_get_drvdata(dai->dev);
1062
1063 /* If AFE port is still up, close it */
1064 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -07001065 switch (dai->id) {
1066 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -07001067 case VOICE_RECORD_TX:
1068 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -07001069 pr_debug("%s, stop pseudo port:%d\n",
1070 __func__, dai->id);
1071 rc = afe_stop_pseudo_port(dai->id);
1072 break;
1073 default:
1074 rc = afe_close(dai->id); /* can block */
1075 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 if (IS_ERR_VALUE(rc))
1077 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301078 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 }
1080 kfree(dai_data);
1081 snd_soc_unregister_dai(dai->dev);
1082
1083 return 0;
1084}
1085
Lei Zhou157c1842011-08-19 13:05:04 -04001086static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1087{
1088 int rc = 0;
1089
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001090 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
1091 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -04001092 switch (dai->id) {
1093 case PRIMARY_I2S_TX:
1094 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001095 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -04001096 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
1097 break;
1098 default:
1099 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1100 rc = -EINVAL;
1101 break;
1102 }
1103
1104 return rc;
1105}
1106
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001107static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
1108 unsigned int tx_num, unsigned int *tx_slot,
1109 unsigned int rx_num, unsigned int *rx_slot)
1110
1111{
1112 int rc = 0;
1113 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
1114 unsigned int i = 0;
1115
1116 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
1117 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001118 switch (dai->id) {
1119 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001120 case SLIMBUS_1_RX:
Neema Shetty74131ac2012-05-09 13:35:26 -07001121 case SLIMBUS_3_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001122 case SLIMBUS_4_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001123 /* channel number to be between 128 and 255. For RX port
1124 * use channel numbers from 138 to 144, for TX port
1125 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001126 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001127 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001128 if (!rx_slot)
1129 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001130 for (i = 0; i < rx_num; i++) {
1131 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1132 rx_slot[i];
1133 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1134 __func__, i,
1135 rx_slot[i]);
1136 }
1137 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001138 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
1139 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001140 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1141 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1142
1143 break;
1144 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001145 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001146 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001147 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001148 /* channel number to be between 128 and 255. For RX port
1149 * use channel numbers from 138 to 144, for TX port
1150 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -08001151 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001152 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -08001153 if (!tx_slot)
1154 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001155 for (i = 0; i < tx_num; i++) {
1156 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
1157 tx_slot[i];
1158 pr_debug("%s: find number of channels[%d] ch[%d]\n",
1159 __func__, i, tx_slot[i]);
1160 }
1161 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001162 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
1163 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001164 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
1165 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
1166 break;
1167 default:
1168 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1169 rc = -EINVAL;
1170 break;
1171 }
1172 return rc;
1173}
1174
Patrick Lai04baee942012-05-01 14:38:47 -07001175static struct snd_soc_dai_ops msm_dai_q6_mi2s_ops = {
1176 .startup = msm_dai_q6_mi2s_startup,
1177 .prepare = msm_dai_q6_mi2s_prepare,
1178 .trigger = msm_dai_q6_mi2s_trigger,
1179 .hw_params = msm_dai_q6_mi2s_hw_params,
1180 .shutdown = msm_dai_q6_mi2s_shutdown,
1181 .set_fmt = msm_dai_q6_mi2s_set_fmt,
1182};
1183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001185 .prepare = msm_dai_q6_prepare,
1186 .trigger = msm_dai_q6_trigger,
1187 .hw_params = msm_dai_q6_hw_params,
1188 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -04001189 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001190 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001191};
1192
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001193static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
1194 .prepare = msm_dai_q6_auxpcm_prepare,
1195 .trigger = msm_dai_q6_auxpcm_trigger,
1196 .hw_params = msm_dai_q6_auxpcm_hw_params,
1197 .shutdown = msm_dai_q6_auxpcm_shutdown,
1198};
1199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001200static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
1201 .playback = {
1202 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1203 SNDRV_PCM_RATE_16000,
1204 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1205 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -08001206 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 .rate_min = 8000,
1208 .rate_max = 48000,
1209 },
1210 .ops = &msm_dai_q6_ops,
1211 .probe = msm_dai_q6_dai_probe,
1212 .remove = msm_dai_q6_dai_remove,
1213};
1214
1215static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
1216 .capture = {
1217 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1218 SNDRV_PCM_RATE_16000,
1219 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1220 .channels_min = 1,
1221 .channels_max = 2,
1222 .rate_min = 8000,
1223 .rate_max = 48000,
1224 },
1225 .ops = &msm_dai_q6_ops,
1226 .probe = msm_dai_q6_dai_probe,
1227 .remove = msm_dai_q6_dai_remove,
1228};
1229
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301230static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
1231 .playback = {
1232 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1233 SNDRV_PCM_RATE_16000,
1234 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1235 .channels_min = 1,
1236 .channels_max = 2,
1237 .rate_min = 8000,
1238 .rate_max = 48000,
1239 },
1240 .ops = &msm_dai_q6_ops,
1241 .probe = msm_dai_q6_dai_probe,
1242 .remove = msm_dai_q6_dai_remove,
1243};
1244
1245static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1246 .capture = {
1247 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1248 SNDRV_PCM_RATE_16000,
1249 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1250 .channels_min = 1,
Mingming Yin647e9ea2012-03-17 19:56:10 -07001251 .channels_max = 4,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301252 .rate_min = 8000,
1253 .rate_max = 48000,
1254 },
1255 .ops = &msm_dai_q6_ops,
1256 .probe = msm_dai_q6_dai_probe,
1257 .remove = msm_dai_q6_dai_remove,
1258};
1259
Helen Zeng0705a5f2011-10-14 15:29:52 -07001260static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1261 .playback = {
1262 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1263 SNDRV_PCM_RATE_16000,
1264 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1265 .channels_min = 1,
1266 .channels_max = 2,
1267 .rate_max = 48000,
1268 .rate_min = 8000,
1269 },
1270 .ops = &msm_dai_q6_ops,
1271 .probe = msm_dai_q6_dai_probe,
1272 .remove = msm_dai_q6_dai_remove,
1273};
1274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1276 .playback = {
1277 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1278 SNDRV_PCM_RATE_16000,
1279 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1280 .channels_min = 1,
1281 .channels_max = 2,
1282 .rate_min = 8000,
1283 .rate_max = 48000,
1284 },
1285 .ops = &msm_dai_q6_ops,
1286 .probe = msm_dai_q6_dai_probe,
1287 .remove = msm_dai_q6_dai_remove,
1288};
1289
1290static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1291 .capture = {
1292 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1293 SNDRV_PCM_RATE_16000,
1294 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1295 .channels_min = 1,
1296 .channels_max = 2,
1297 .rate_min = 8000,
1298 .rate_max = 48000,
1299 },
1300 .ops = &msm_dai_q6_ops,
1301 .probe = msm_dai_q6_dai_probe,
1302 .remove = msm_dai_q6_dai_remove,
1303};
1304
Helen Zenge3d716a2011-10-14 16:32:16 -07001305static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1306 .capture = {
1307 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1308 SNDRV_PCM_RATE_16000,
1309 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1310 .channels_min = 1,
1311 .channels_max = 2,
1312 .rate_min = 8000,
1313 .rate_max = 48000,
1314 },
1315 .ops = &msm_dai_q6_ops,
1316 .probe = msm_dai_q6_dai_probe,
1317 .remove = msm_dai_q6_dai_remove,
1318};
1319
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001320static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1321 .playback = {
1322 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1323 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1324 .channels_min = 1,
1325 .channels_max = 1,
1326 .rate_max = 16000,
1327 .rate_min = 8000,
1328 },
1329 .ops = &msm_dai_q6_ops,
1330 .probe = msm_dai_q6_dai_probe,
1331 .remove = msm_dai_q6_dai_remove,
1332};
1333
1334static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1335 .playback = {
1336 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1337 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1338 .channels_min = 1,
1339 .channels_max = 1,
1340 .rate_max = 16000,
1341 .rate_min = 8000,
1342 },
1343 .ops = &msm_dai_q6_ops,
1344 .probe = msm_dai_q6_dai_probe,
1345 .remove = msm_dai_q6_dai_remove,
1346};
1347
1348static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1349 .playback = {
1350 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1351 SNDRV_PCM_RATE_16000,
1352 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1353 .channels_min = 2,
1354 .channels_max = 2,
1355 .rate_max = 48000,
1356 .rate_min = 8000,
1357 },
1358 .ops = &msm_dai_q6_ops,
1359 .probe = msm_dai_q6_dai_probe,
1360 .remove = msm_dai_q6_dai_remove,
1361};
1362
1363static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1364 .playback = {
1365 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1366 SNDRV_PCM_RATE_16000,
1367 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1368 .channels_min = 2,
1369 .channels_max = 2,
1370 .rate_max = 48000,
1371 .rate_min = 8000,
1372 },
1373 .ops = &msm_dai_q6_ops,
1374 .probe = msm_dai_q6_dai_probe,
1375 .remove = msm_dai_q6_dai_remove,
1376};
1377
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001378static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1379 .playback = {
1380 .rates = SNDRV_PCM_RATE_8000,
1381 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1382 .channels_min = 1,
1383 .channels_max = 1,
1384 .rate_max = 8000,
1385 .rate_min = 8000,
1386 },
1387 .ops = &msm_dai_q6_auxpcm_ops,
1388 .probe = msm_dai_q6_dai_auxpcm_probe,
1389 .remove = msm_dai_q6_dai_auxpcm_remove,
1390};
1391
1392static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1393 .capture = {
1394 .rates = SNDRV_PCM_RATE_8000,
1395 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1396 .channels_min = 1,
1397 .channels_max = 1,
1398 .rate_max = 8000,
1399 .rate_min = 8000,
1400 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001401 .ops = &msm_dai_q6_auxpcm_ops,
1402 .probe = msm_dai_q6_dai_auxpcm_probe,
1403 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001404};
1405
Patrick Lai04baee942012-05-01 14:38:47 -07001406/* Channel min and max are initialized base on platform data */
1407static struct snd_soc_dai_driver msm_dai_q6_mi2s_dai = {
Kuirong Wang274f21a2011-12-15 21:29:08 -08001408 .playback = {
1409 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1410 SNDRV_PCM_RATE_16000,
1411 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Kuirong Wang274f21a2011-12-15 21:29:08 -08001412 .rate_min = 8000,
1413 .rate_max = 48000,
1414 },
Kuirong Wang623b50f2012-04-16 15:51:14 -07001415 .capture = {
1416 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1417 SNDRV_PCM_RATE_16000,
1418 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Patrick Lai04baee942012-05-01 14:38:47 -07001419 .rate_min = 8000,
1420 .rate_max = 48000,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001421 },
Patrick Lai04baee942012-05-01 14:38:47 -07001422 .ops = &msm_dai_q6_mi2s_ops,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001423 .probe = msm_dai_q6_dai_mi2s_probe,
Patrick Lai04baee942012-05-01 14:38:47 -07001424 .remove = msm_dai_q6_dai_mi2s_remove,
Kuirong Wang623b50f2012-04-16 15:51:14 -07001425};
1426
Neema Shetty3c9d2862012-03-11 01:25:32 -08001427static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1428 .playback = {
1429 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1430 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1431 .channels_min = 1,
1432 .channels_max = 1,
1433 .rate_min = 8000,
1434 .rate_max = 16000,
1435 },
1436 .ops = &msm_dai_q6_ops,
1437 .probe = msm_dai_q6_dai_probe,
1438 .remove = msm_dai_q6_dai_remove,
1439};
1440
1441static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1442 .capture = {
1443 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1444 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1445 .channels_min = 1,
1446 .channels_max = 1,
1447 .rate_min = 8000,
1448 .rate_max = 16000,
1449 },
1450 .ops = &msm_dai_q6_ops,
1451 .probe = msm_dai_q6_dai_probe,
1452 .remove = msm_dai_q6_dai_remove,
1453};
1454
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001455static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1456 .capture = {
1457 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1458 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1459 SNDRV_PCM_RATE_192000,
1460 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1461 .channels_min = 1,
1462 .channels_max = 4,
1463 .rate_min = 8000,
1464 .rate_max = 192000,
1465 },
1466 .ops = &msm_dai_q6_ops,
1467 .probe = msm_dai_q6_dai_probe,
1468 .remove = msm_dai_q6_dai_remove,
1469};
1470
Neema Shetty74131ac2012-05-09 13:35:26 -07001471static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
1472 .playback = {
1473 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
1474 SNDRV_PCM_RATE_48000,
1475 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1476 .channels_min = 1,
1477 .channels_max = 2,
1478 .rate_min = 8000,
1479 .rate_max = 48000,
1480 },
1481 .ops = &msm_dai_q6_ops,
1482 .probe = msm_dai_q6_dai_probe,
1483 .remove = msm_dai_q6_dai_remove,
1484};
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486/* To do: change to register DAIs as batch */
1487static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1488{
1489 int rc = 0;
1490
1491 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1492
1493 switch (pdev->id) {
1494 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001495 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1497 break;
1498 case PRIMARY_I2S_TX:
1499 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1500 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001501 case PCM_RX:
1502 rc = snd_soc_register_dai(&pdev->dev,
1503 &msm_dai_q6_aux_pcm_rx_dai);
1504 break;
1505 case PCM_TX:
1506 rc = snd_soc_register_dai(&pdev->dev,
1507 &msm_dai_q6_aux_pcm_tx_dai);
1508 break;
Patrick Lai04baee942012-05-01 14:38:47 -07001509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001511 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 rc = snd_soc_register_dai(&pdev->dev,
1513 &msm_dai_q6_slimbus_rx_dai);
1514 break;
1515 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001516 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 rc = snd_soc_register_dai(&pdev->dev,
1518 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001519 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001520 case SLIMBUS_1_RX:
1521 rc = snd_soc_register_dai(&pdev->dev,
1522 &msm_dai_q6_slimbus_1_rx_dai);
1523 break;
1524 case SLIMBUS_1_TX:
1525 rc = snd_soc_register_dai(&pdev->dev,
1526 &msm_dai_q6_slimbus_1_tx_dai);
1527 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001528 case SLIMBUS_2_TX:
1529 rc = snd_soc_register_dai(&pdev->dev,
1530 &msm_dai_q6_slimbus_2_tx_dai);
1531 break;
Neema Shetty74131ac2012-05-09 13:35:26 -07001532 case SLIMBUS_3_RX:
1533 rc = snd_soc_register_dai(&pdev->dev,
1534 &msm_dai_q6_slimbus_3_rx_dai);
1535 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 case INT_BT_SCO_RX:
1537 rc = snd_soc_register_dai(&pdev->dev,
1538 &msm_dai_q6_bt_sco_rx_dai);
1539 break;
1540 case INT_BT_SCO_TX:
1541 rc = snd_soc_register_dai(&pdev->dev,
1542 &msm_dai_q6_bt_sco_tx_dai);
1543 break;
1544 case INT_FM_RX:
1545 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1546 break;
1547 case INT_FM_TX:
1548 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1549 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301550 case RT_PROXY_DAI_001_RX:
1551 case RT_PROXY_DAI_002_RX:
1552 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1553 break;
1554 case RT_PROXY_DAI_001_TX:
1555 case RT_PROXY_DAI_002_TX:
1556 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1557 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001558 case VOICE_PLAYBACK_TX:
1559 rc = snd_soc_register_dai(&pdev->dev,
1560 &msm_dai_q6_voice_playback_tx_dai);
1561 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001562 case VOICE_RECORD_RX:
1563 case VOICE_RECORD_TX:
1564 rc = snd_soc_register_dai(&pdev->dev,
1565 &msm_dai_q6_incall_record_dai);
1566 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 default:
1568 rc = -ENODEV;
1569 break;
1570 }
1571 return rc;
1572}
1573
1574static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1575{
1576 snd_soc_unregister_dai(&pdev->dev);
1577 return 0;
1578}
1579
Patrick Lai04baee942012-05-01 14:38:47 -07001580static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
1581{
1582 struct msm_dai_q6_mi2s_dai_data *dai_data;
1583 int rc = 0;
1584
1585 dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
1586
1587 dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
1588 GFP_KERNEL);
1589
1590 if (!dai_data) {
1591 dev_err(&pdev->dev, "fail to allocate dai data\n");
1592 rc = -ENOMEM;
1593 goto rtn;
1594 } else
1595 dev_set_drvdata(&pdev->dev, dai_data);
1596
1597 rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
1598 &msm_dai_q6_mi2s_dai);
1599 if (IS_ERR_VALUE(rc))
1600 goto err_pdata;
1601
1602 dai_data->rate_constraint.count = 1;
1603 dai_data->bitwidth_constraint.count = 1;
1604 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
1605
1606 if (IS_ERR_VALUE(rc))
1607 goto err_pdata;
1608
1609 return 0;
1610
1611err_pdata:
1612 kfree(dai_data);
1613rtn:
1614 return rc;
1615}
1616
1617static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
1618{
1619 snd_soc_unregister_dai(&pdev->dev);
1620 return 0;
1621}
1622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623static struct platform_driver msm_dai_q6_driver = {
1624 .probe = msm_dai_q6_dev_probe,
1625 .remove = msm_dai_q6_dev_remove,
1626 .driver = {
1627 .name = "msm-dai-q6",
1628 .owner = THIS_MODULE,
1629 },
1630};
1631
Patrick Lai04baee942012-05-01 14:38:47 -07001632static struct platform_driver msm_dai_q6_mi2s_driver = {
1633 .probe = msm_dai_q6_mi2s_dev_probe,
1634 .remove = msm_dai_q6_mi2s_dev_remove,
1635 .driver = {
1636 .name = "msm-dai-q6-mi2s",
1637 .owner = THIS_MODULE,
1638 },
1639};
1640
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001641static int __init msm_dai_q6_init(void)
1642{
Patrick Lai04baee942012-05-01 14:38:47 -07001643 int rc1, rc2;
1644
1645 rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
1646
1647 if (IS_ERR_VALUE(rc1))
1648 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1649
1650 rc2 = platform_driver_register(&msm_dai_q6_driver);
1651
1652 if (IS_ERR_VALUE(rc2))
1653 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1654
1655 return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001656}
1657module_init(msm_dai_q6_init);
1658
1659static void __exit msm_dai_q6_exit(void)
1660{
1661 platform_driver_unregister(&msm_dai_q6_driver);
1662}
1663module_exit(msm_dai_q6_exit);
1664
1665/* Module information */
1666MODULE_DESCRIPTION("MSM DSP DAI driver");
1667MODULE_LICENSE("GPL v2");