blob: a62541a554b9521d447b0c580966dee6100096c0 [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 Kandi1e6371d2012-03-29 11:48:57 -0700607 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800608 case SLIMBUS_4_RX:
609 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
611 substream->stream);
612 break;
613 case INT_BT_SCO_RX:
614 case INT_BT_SCO_TX:
615 case INT_FM_RX:
616 case INT_FM_TX:
617 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
618 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530619 case RT_PROXY_DAI_001_TX:
620 case RT_PROXY_DAI_001_RX:
621 case RT_PROXY_DAI_002_TX:
622 case RT_PROXY_DAI_002_RX:
623 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
624 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700625 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700626 case VOICE_RECORD_RX:
627 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700628 rc = 0;
629 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630 default:
631 dev_err(dai->dev, "invalid AFE port ID\n");
632 rc = -EINVAL;
633 break;
634 }
635
636 return rc;
637}
638
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700639static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
640 struct snd_soc_dai *dai)
641{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700642 int rc = 0;
643
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800644 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700645
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800646 if (aux_pcm_count == 0) {
647 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
648 " return\n", __func__, dai->id);
649 mutex_unlock(&aux_pcm_mutex);
650 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700651 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800652
653 aux_pcm_count--;
654
655 if (aux_pcm_count > 0) {
656 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
657 __func__, dai->id, aux_pcm_count);
658 mutex_unlock(&aux_pcm_mutex);
659 return;
660 } else if (aux_pcm_count < 0) {
661 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
662 " aux_pcm_count = %d < 0\n",
663 __func__, dai->id, aux_pcm_count);
664 aux_pcm_count = 0;
665 mutex_unlock(&aux_pcm_mutex);
666 return;
667 }
668
669 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
670 dai->id, aux_pcm_count);
671
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530672 clk_disable_unprepare(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800673 rc = afe_close(PCM_RX); /* can block */
674 if (IS_ERR_VALUE(rc))
675 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
676
677 rc = afe_close(PCM_TX);
678 if (IS_ERR_VALUE(rc))
679 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
680
681 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700682}
683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700684static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
685 struct snd_soc_dai *dai)
686{
687 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530688 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700691 switch (dai->id) {
692 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700693 case VOICE_RECORD_TX:
694 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700695 pr_debug("%s, stop pseudo port:%d\n",
696 __func__, dai->id);
697 rc = afe_stop_pseudo_port(dai->id);
698 break;
699 default:
700 rc = afe_close(dai->id); /* can block */
701 break;
702 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700703 if (IS_ERR_VALUE(rc))
704 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530705 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
706 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
708 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700709}
710
711static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
712 struct snd_soc_dai *dai)
713{
714 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
715 int rc = 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700716 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
717 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
Kuirong Wang547a9982012-05-04 18:29:11 -0700718 unsigned long pcm_clk_rate;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700719
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800720 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700721
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800722 if (aux_pcm_count == 2) {
723 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
724 " return.\n", __func__, dai->id);
725 mutex_unlock(&aux_pcm_mutex);
726 return 0;
727 } else if (aux_pcm_count > 2) {
728 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
729 " aux_pcm_count = %d > 2\n",
730 __func__, dai->id, aux_pcm_count);
731 mutex_unlock(&aux_pcm_mutex);
732 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700733 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800734
735 aux_pcm_count++;
736 if (aux_pcm_count == 2) {
737 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
738 " increment\n", __func__, dai->id, aux_pcm_count);
739 mutex_unlock(&aux_pcm_mutex);
740 return 0;
741 }
742
743 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
744 __func__, dai->id, aux_pcm_count);
745
746 rc = afe_q6_interface_prepare();
747 if (IS_ERR_VALUE(rc))
748 dev_err(dai->dev, "fail to open AFE APR\n");
749
750 /*
751 * For AUX PCM Interface the below sequence of clk
752 * settings and afe_open is a strict requirement.
753 *
754 * Also using afe_open instead of afe_port_start_nowait
755 * to make sure the port is open before deasserting the
756 * clock line. This is required because pcm register is
757 * not written before clock deassert. Hence the hw does
758 * not get updated with new setting if the below clock
759 * assert/deasset and afe_open sequence is not followed.
760 */
761
762 clk_reset(pcm_clk, CLK_RESET_ASSERT);
763
764 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
765
766 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
Kuirong Wang547a9982012-05-04 18:29:11 -0700767 if (dai_data->rate == 8000) {
768 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
769 } else if (dai_data->rate == 16000) {
770 pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
771 } else {
772 dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
773 dai_data->rate);
774 return -EINVAL;
775 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800776
Kuirong Wang547a9982012-05-04 18:29:11 -0700777 rc = clk_set_rate(pcm_clk, pcm_clk_rate);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800778 if (rc < 0) {
779 pr_err("%s: clk_set_rate failed\n", __func__);
780 return rc;
781 }
782
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530783 clk_prepare_enable(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800784 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
785
786 mutex_unlock(&aux_pcm_mutex);
787
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700788 return rc;
789}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790
791static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
792 struct snd_soc_dai *dai)
793{
794 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
795 int rc = 0;
796
Patrick Lai831561e2011-07-26 22:51:27 -0700797 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700798 /* PORT START should be set if prepare called in active state */
799 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700801 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804}
805
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700806static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
807 int cmd, struct snd_soc_dai *dai)
808{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700809 int rc = 0;
810
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800811 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
812 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700813
814 switch (cmd) {
815
816 case SNDRV_PCM_TRIGGER_START:
817 case SNDRV_PCM_TRIGGER_RESUME:
818 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
819 /* afe_open will be called from prepare */
820 return 0;
821
822 case SNDRV_PCM_TRIGGER_STOP:
823 case SNDRV_PCM_TRIGGER_SUSPEND:
824 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800825 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700826
827 default:
828 rc = -EINVAL;
829 }
830
831 return rc;
832
833}
834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
836 struct snd_soc_dai *dai)
837{
838 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
839 int rc = 0;
840
841 /* Start/stop port without waiting for Q6 AFE response. Need to have
842 * native q6 AFE driver propagates AFE response in order to handle
843 * port start/stop command error properly if error does arise.
844 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530845 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
846 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 switch (cmd) {
848 case SNDRV_PCM_TRIGGER_START:
849 case SNDRV_PCM_TRIGGER_RESUME:
850 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
851 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700852 switch (dai->id) {
853 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700854 case VOICE_RECORD_TX:
855 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700856 afe_pseudo_port_start_nowait(dai->id);
857 break;
858 default:
859 afe_port_start_nowait(dai->id,
860 &dai_data->port_config, dai_data->rate);
861 break;
862 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863 set_bit(STATUS_PORT_STARTED,
864 dai_data->status_mask);
865 }
866 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 case SNDRV_PCM_TRIGGER_STOP:
868 case SNDRV_PCM_TRIGGER_SUSPEND:
869 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
870 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700871 switch (dai->id) {
872 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700873 case VOICE_RECORD_TX:
874 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700875 afe_pseudo_port_stop_nowait(dai->id);
876 break;
877 default:
878 afe_port_stop_nowait(dai->id);
879 break;
880 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881 clear_bit(STATUS_PORT_STARTED,
882 dai_data->status_mask);
883 }
884 break;
885
886 default:
887 rc = -EINVAL;
888 }
889
890 return rc;
891}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700892static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
893{
894 struct msm_dai_q6_dai_data *dai_data;
895 int rc = 0;
896
897 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
898 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
899
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800900 mutex_lock(&aux_pcm_mutex);
901
902 if (!auxpcm_plat_data)
903 auxpcm_plat_data = auxpcm_pdata;
904 else if (auxpcm_plat_data != auxpcm_pdata) {
905
906 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
907 " same platform data\n");
908 return -EINVAL;
909 }
910
911 /*
912 * The clk name for AUX PCM operation is passed as platform
913 * data to the cpu driver, since cpu drive is unaware of any
914 * boarc specific configuration.
915 */
916 if (!pcm_clk) {
917
918 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
919
920 if (IS_ERR(pcm_clk)) {
921 pr_err("%s: could not get pcm_clk\n", __func__);
922 pcm_clk = NULL;
923 return -ENODEV;
924 }
925 }
926
927 mutex_unlock(&aux_pcm_mutex);
928
929 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700930
931 if (!dai_data) {
932 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
933 dai->id);
934 rc = -ENOMEM;
935 } else
936 dev_set_drvdata(dai->dev, dai_data);
937
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800938 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700939 return rc;
940}
941
942static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
943{
944 struct msm_dai_q6_dai_data *dai_data;
945 int rc;
946
947 dai_data = dev_get_drvdata(dai->dev);
948
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800949 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700950
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800951 if (aux_pcm_count == 0) {
952 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
953 " up and return\n", __func__, dai->id);
954 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700955 }
956
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800957 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700958
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800959 if (aux_pcm_count > 0) {
960 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
961 __func__, dai->id, aux_pcm_count);
962 goto done;
963 } else if (aux_pcm_count < 0) {
964 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
965 " aux_pcm_count = %d < 0\n",
966 __func__, dai->id, aux_pcm_count);
967 goto done;
968 }
969
970 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
971 "closing afe\n",
972 __func__, dai->id, aux_pcm_count);
973
974 rc = afe_close(PCM_RX); /* can block */
975 if (IS_ERR_VALUE(rc))
976 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
977
978 rc = afe_close(PCM_TX);
979 if (IS_ERR_VALUE(rc))
980 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
981
982done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700983 kfree(dai_data);
984 snd_soc_unregister_dai(dai->dev);
985
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800986 mutex_unlock(&aux_pcm_mutex);
987
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700988 return 0;
989}
Patrick Lai04baee942012-05-01 14:38:47 -0700990
Kuirong Wang274f21a2011-12-15 21:29:08 -0800991static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
992{
Patrick Lai04baee942012-05-01 14:38:47 -0700993 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
994 dev_get_drvdata(dai->dev);
995 struct snd_kcontrol *kcontrol = NULL;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800996 int rc = 0;
997
Patrick Lai04baee942012-05-01 14:38:47 -0700998 if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
999 kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
1000 &mi2s_dai_data->rx_dai);
1001 rc = snd_ctl_add(dai->card->snd_card, kcontrol);
Kuirong Wang274f21a2011-12-15 21:29:08 -08001002
Patrick Lai04baee942012-05-01 14:38:47 -07001003 if (IS_ERR_VALUE(rc)) {
1004 dev_err(dai->dev, "%s: err add RX fmt ctl\n", __func__);
1005 goto rtn;
1006 }
Kuirong Wang274f21a2011-12-15 21:29:08 -08001007 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001008
Patrick Lai04baee942012-05-01 14:38:47 -07001009 if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
1010 rc = snd_ctl_add(dai->card->snd_card,
1011 snd_ctl_new1(&mi2s_config_controls[2],
1012 &mi2s_dai_data->tx_dai));
1013
1014 if (IS_ERR_VALUE(rc)) {
1015 if (kcontrol)
1016 snd_ctl_remove(dai->card->snd_card, kcontrol);
1017 dev_err(dai->dev, "%s: err add TX fmt ctl\n", __func__);
1018 }
1019 }
1020
Kuirong Wang274f21a2011-12-15 21:29:08 -08001021rtn:
1022 return rc;
1023}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024
Patrick Lai04baee942012-05-01 14:38:47 -07001025static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
1026{
1027 struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
1028 dev_get_drvdata(dai->dev);
1029 int rc;
1030
1031 /* If AFE port is still up, close it */
1032 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
1033 rc = afe_close(MI2S_RX); /* can block */
1034 if (IS_ERR_VALUE(rc))
1035 dev_err(dai->dev, "fail to close MI2S_RX port\n");
1036 clear_bit(STATUS_PORT_STARTED,
1037 mi2s_dai_data->rx_dai.status_mask);
1038 }
1039 if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
1040 rc = afe_close(MI2S_TX); /* can block */
1041 if (IS_ERR_VALUE(rc))
1042 dev_err(dai->dev, "fail to close MI2S_TX port\n");
1043 clear_bit(STATUS_PORT_STARTED,
1044 mi2s_dai_data->tx_dai.status_mask);
1045 }
1046 kfree(mi2s_dai_data);
1047 snd_soc_unregister_dai(dai->dev);
1048
1049 return 0;
1050}
1051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
1053{
1054 struct msm_dai_q6_dai_data *dai_data;
1055 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001056 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001057
1058 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
1059 GFP_KERNEL);
1060
1061 if (!dai_data) {
1062 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
1063 dai->id);
1064 rc = -ENOMEM;
1065 } else
1066 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -07001067 if (dai->id == SECONDARY_I2S_RX) {
1068 kcontrol = &mi2s_config_controls[1];
1069 rc = snd_ctl_add(dai->card->snd_card,
1070 snd_ctl_new1(kcontrol, dai_data));
1071 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072
1073 return rc;
1074}
1075
1076static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
1077{
1078 struct msm_dai_q6_dai_data *dai_data;
1079 int rc;
1080
1081 dai_data = dev_get_drvdata(dai->dev);
1082
1083 /* If AFE port is still up, close it */
1084 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -07001085 switch (dai->id) {
1086 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -07001087 case VOICE_RECORD_TX:
1088 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -07001089 pr_debug("%s, stop pseudo port:%d\n",
1090 __func__, dai->id);
1091 rc = afe_stop_pseudo_port(dai->id);
1092 break;
1093 default:
1094 rc = afe_close(dai->id); /* can block */
1095 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001096 if (IS_ERR_VALUE(rc))
1097 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301098 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 }
1100 kfree(dai_data);
1101 snd_soc_unregister_dai(dai->dev);
1102
1103 return 0;
1104}
1105
Lei Zhou157c1842011-08-19 13:05:04 -04001106static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1107{
1108 int rc = 0;
1109
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001110 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
1111 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -04001112 switch (dai->id) {
1113 case PRIMARY_I2S_TX:
1114 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001115 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -04001116 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
1117 break;
1118 default:
1119 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
1120 rc = -EINVAL;
1121 break;
1122 }
1123
1124 return rc;
1125}
1126
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001127static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
1128 unsigned int tx_num, unsigned int *tx_slot,
1129 unsigned int rx_num, unsigned int *rx_slot)
1130
1131{
1132 int rc = 0;
1133 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
1134 unsigned int i = 0;
1135
1136 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
1137 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001138 switch (dai->id) {
1139 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -08001140 case SLIMBUS_1_RX:
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 Kandi1e6371d2012-03-29 11:48:57 -07001475static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1476 .capture = {
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 = 4,
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
Neema Shetty74131ac2012-05-09 13:35:26 -07001491static struct snd_soc_dai_driver msm_dai_q6_slimbus_3_rx_dai = {
1492 .playback = {
1493 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
1494 SNDRV_PCM_RATE_48000,
1495 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1496 .channels_min = 1,
1497 .channels_max = 2,
1498 .rate_min = 8000,
1499 .rate_max = 48000,
1500 },
1501 .ops = &msm_dai_q6_ops,
1502 .probe = msm_dai_q6_dai_probe,
1503 .remove = msm_dai_q6_dai_remove,
1504};
1505
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506/* To do: change to register DAIs as batch */
1507static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1508{
1509 int rc = 0;
1510
1511 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1512
1513 switch (pdev->id) {
1514 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001515 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1517 break;
1518 case PRIMARY_I2S_TX:
1519 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1520 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001521 case PCM_RX:
1522 rc = snd_soc_register_dai(&pdev->dev,
1523 &msm_dai_q6_aux_pcm_rx_dai);
1524 break;
1525 case PCM_TX:
1526 rc = snd_soc_register_dai(&pdev->dev,
1527 &msm_dai_q6_aux_pcm_tx_dai);
1528 break;
Patrick Lai04baee942012-05-01 14:38:47 -07001529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001531 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532 rc = snd_soc_register_dai(&pdev->dev,
1533 &msm_dai_q6_slimbus_rx_dai);
1534 break;
1535 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001536 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 rc = snd_soc_register_dai(&pdev->dev,
1538 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001539 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001540 case SLIMBUS_1_RX:
1541 rc = snd_soc_register_dai(&pdev->dev,
1542 &msm_dai_q6_slimbus_1_rx_dai);
1543 break;
1544 case SLIMBUS_1_TX:
1545 rc = snd_soc_register_dai(&pdev->dev,
1546 &msm_dai_q6_slimbus_1_tx_dai);
1547 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001548 case SLIMBUS_2_TX:
1549 rc = snd_soc_register_dai(&pdev->dev,
1550 &msm_dai_q6_slimbus_2_tx_dai);
1551 break;
Neema Shetty74131ac2012-05-09 13:35:26 -07001552 case SLIMBUS_3_RX:
1553 rc = snd_soc_register_dai(&pdev->dev,
1554 &msm_dai_q6_slimbus_3_rx_dai);
1555 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 case INT_BT_SCO_RX:
1557 rc = snd_soc_register_dai(&pdev->dev,
1558 &msm_dai_q6_bt_sco_rx_dai);
1559 break;
1560 case INT_BT_SCO_TX:
1561 rc = snd_soc_register_dai(&pdev->dev,
1562 &msm_dai_q6_bt_sco_tx_dai);
1563 break;
1564 case INT_FM_RX:
1565 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1566 break;
1567 case INT_FM_TX:
1568 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1569 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301570 case RT_PROXY_DAI_001_RX:
1571 case RT_PROXY_DAI_002_RX:
1572 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1573 break;
1574 case RT_PROXY_DAI_001_TX:
1575 case RT_PROXY_DAI_002_TX:
1576 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1577 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001578 case VOICE_PLAYBACK_TX:
1579 rc = snd_soc_register_dai(&pdev->dev,
1580 &msm_dai_q6_voice_playback_tx_dai);
1581 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001582 case VOICE_RECORD_RX:
1583 case VOICE_RECORD_TX:
1584 rc = snd_soc_register_dai(&pdev->dev,
1585 &msm_dai_q6_incall_record_dai);
1586 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587 default:
1588 rc = -ENODEV;
1589 break;
1590 }
1591 return rc;
1592}
1593
1594static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1595{
1596 snd_soc_unregister_dai(&pdev->dev);
1597 return 0;
1598}
1599
Patrick Lai04baee942012-05-01 14:38:47 -07001600static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
1601{
1602 struct msm_dai_q6_mi2s_dai_data *dai_data;
1603 int rc = 0;
1604
1605 dev_dbg(&pdev->dev, "%s: pdev %p dev %p\n", __func__, pdev, &pdev->dev);
1606
1607 dai_data = kzalloc(sizeof(struct msm_dai_q6_mi2s_dai_data),
1608 GFP_KERNEL);
1609
1610 if (!dai_data) {
1611 dev_err(&pdev->dev, "fail to allocate dai data\n");
1612 rc = -ENOMEM;
1613 goto rtn;
1614 } else
1615 dev_set_drvdata(&pdev->dev, dai_data);
1616
1617 rc = msm_dai_q6_mi2s_platform_data_validation(pdev,
1618 &msm_dai_q6_mi2s_dai);
1619 if (IS_ERR_VALUE(rc))
1620 goto err_pdata;
1621
1622 dai_data->rate_constraint.count = 1;
1623 dai_data->bitwidth_constraint.count = 1;
1624 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_mi2s_dai);
1625
1626 if (IS_ERR_VALUE(rc))
1627 goto err_pdata;
1628
1629 return 0;
1630
1631err_pdata:
1632 kfree(dai_data);
1633rtn:
1634 return rc;
1635}
1636
1637static __devexit int msm_dai_q6_mi2s_dev_remove(struct platform_device *pdev)
1638{
1639 snd_soc_unregister_dai(&pdev->dev);
1640 return 0;
1641}
1642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643static struct platform_driver msm_dai_q6_driver = {
1644 .probe = msm_dai_q6_dev_probe,
1645 .remove = msm_dai_q6_dev_remove,
1646 .driver = {
1647 .name = "msm-dai-q6",
1648 .owner = THIS_MODULE,
1649 },
1650};
1651
Patrick Lai04baee942012-05-01 14:38:47 -07001652static struct platform_driver msm_dai_q6_mi2s_driver = {
1653 .probe = msm_dai_q6_mi2s_dev_probe,
1654 .remove = msm_dai_q6_mi2s_dev_remove,
1655 .driver = {
1656 .name = "msm-dai-q6-mi2s",
1657 .owner = THIS_MODULE,
1658 },
1659};
1660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661static int __init msm_dai_q6_init(void)
1662{
Patrick Lai04baee942012-05-01 14:38:47 -07001663 int rc1, rc2;
1664
1665 rc1 = platform_driver_register(&msm_dai_q6_mi2s_driver);
1666
1667 if (IS_ERR_VALUE(rc1))
1668 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1669
1670 rc2 = platform_driver_register(&msm_dai_q6_driver);
1671
1672 if (IS_ERR_VALUE(rc2))
1673 pr_err("%s: fail to register mi2s dai driver\n", __func__);
1674
1675 return (IS_ERR_VALUE(rc1) && IS_ERR_VALUE(rc2)) ? -1 : 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676}
1677module_init(msm_dai_q6_init);
1678
1679static void __exit msm_dai_q6_exit(void)
1680{
1681 platform_driver_unregister(&msm_dai_q6_driver);
1682}
1683module_exit(msm_dai_q6_exit);
1684
1685/* Module information */
1686MODULE_DESCRIPTION("MSM DSP DAI driver");
1687MODULE_LICENSE("GPL v2");