blob: c45351e8a32a95058b2160e18febb4ba49b0516e [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>
27#include <mach/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028
29enum {
30 STATUS_PORT_STARTED, /* track if AFE port has started */
31 STATUS_MAX
32};
33
34struct msm_dai_q6_dai_data {
35 DECLARE_BITMAP(status_mask, STATUS_MAX);
36 u32 rate;
37 u32 channels;
38 union afe_port_config port_config;
39};
40
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070041static struct clk *pcm_clk;
Kiran Kandi5f4ab692012-02-23 11:23:56 -080042static DEFINE_MUTEX(aux_pcm_mutex);
43static int aux_pcm_count;
44static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070045
Kuirong Wang274f21a2011-12-15 21:29:08 -080046static u8 num_of_bits_set(u8 sd_line_mask)
47{
48 u8 num_bits_set = 0;
49
50 while (sd_line_mask) {
51 num_bits_set++;
52 sd_line_mask = sd_line_mask & (sd_line_mask - 1);
53 }
54 return num_bits_set;
55}
56
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070057static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
58 struct snd_soc_dai *dai, int stream)
59{
60 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
61
62 dai_data->channels = params_channels(params);
63 switch (dai_data->channels) {
64 case 2:
65 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
66 break;
67 case 1:
68 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
69 break;
70 default:
71 return -EINVAL;
72 break;
73 }
74 dai_data->rate = params_rate(params);
75
76 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
77 dai_data->channels, dai_data->rate);
78
79 /* Q6 only supports 16 as now */
80 dai_data->port_config.mi2s.bitwidth = 16;
81 dai_data->port_config.mi2s.line = 1;
Kuirong Wang274f21a2011-12-15 21:29:08 -080082 return 0;
83}
84
85static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
86 struct snd_soc_dai *dai, int stream)
87{
88 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
89 struct msm_mi2s_data *mi2s_pdata =
90 (struct msm_mi2s_data *) dai->dev->platform_data;
91
92 dai_data->channels = params_channels(params);
93 if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
94 switch (dai_data->channels) {
95 case 2:
96 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
97 break;
98 case 1:
99 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
100 break;
101 default:
102 pr_warn("greater than stereo has not been validated");
103 break;
104 }
105 }
Kuirong Wangc70819f2012-02-08 16:12:23 -0800106 dai_data->rate = params_rate(params);
Kuirong Wang274f21a2011-12-15 21:29:08 -0800107 /* Q6 only supports 16 as now */
108 dai_data->port_config.mi2s.bitwidth = 16;
Lei Zhou157c1842011-08-19 13:05:04 -0400109
110 return 0;
111}
112
Kuirong Wang274f21a2011-12-15 21:29:08 -0800113static int msm_dai_q6_mi2s_platform_data_validation(
114 struct snd_soc_dai *dai)
115{
116 u8 num_of_sd_lines;
117 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
118 struct msm_mi2s_data *mi2s_pdata =
119 (struct msm_mi2s_data *)dai->dev->platform_data;
120 struct snd_soc_dai_driver *dai_driver =
121 (struct snd_soc_dai_driver *)dai->driver;
122
123 num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);
124
125 switch (num_of_sd_lines) {
126 case 1:
127 switch (mi2s_pdata->sd_lines) {
128 case MSM_MI2S_SD0:
129 dai_data->port_config.mi2s.line = AFE_I2S_SD0;
130 break;
131 case MSM_MI2S_SD1:
132 dai_data->port_config.mi2s.line = AFE_I2S_SD1;
133 break;
134 case MSM_MI2S_SD2:
135 dai_data->port_config.mi2s.line = AFE_I2S_SD2;
136 break;
137 case MSM_MI2S_SD3:
138 dai_data->port_config.mi2s.line = AFE_I2S_SD3;
139 break;
140 default:
141 pr_err("%s: invalid SD line\n",
142 __func__);
143 goto error_invalid_data;
144 }
145 break;
146 case 2:
147 switch (mi2s_pdata->sd_lines) {
148 case MSM_MI2S_SD0 | MSM_MI2S_SD1:
149 dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
150 break;
151 case MSM_MI2S_SD2 | MSM_MI2S_SD3:
152 dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
153 break;
154 default:
155 pr_err("%s: invalid SD line\n",
156 __func__);
157 goto error_invalid_data;
158 }
159 break;
160 case 3:
161 switch (mi2s_pdata->sd_lines) {
162 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
163 dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
164 break;
165 default:
166 pr_err("%s: invalid SD lines\n",
167 __func__);
168 goto error_invalid_data;
169 }
170 break;
171 case 4:
172 switch (mi2s_pdata->sd_lines) {
173 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
174 dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
175 break;
176 default:
177 pr_err("%s: invalid SD lines\n",
178 __func__);
179 goto error_invalid_data;
180 }
181 break;
182 default:
183 pr_err("%s: invalid SD lines\n", __func__);
184 goto error_invalid_data;
185 }
186 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
187 dai_driver->playback.channels_max = num_of_sd_lines << 1;
188
189 return 0;
190
191error_invalid_data:
192 return -EINVAL;
193}
194
Lei Zhou157c1842011-08-19 13:05:04 -0400195static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
196{
197 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
198
199 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
200 case SND_SOC_DAIFMT_CBS_CFS:
201 dai_data->port_config.mi2s.ws = 1; /* CPU is master */
202 break;
203 case SND_SOC_DAIFMT_CBM_CFM:
204 dai_data->port_config.mi2s.ws = 0; /* CPU is slave */
205 break;
206 default:
207 return -EINVAL;
208 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209
210 return 0;
211}
212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
214static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
215 struct snd_soc_dai *dai, int stream)
216{
217 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700218
219 dai_data->channels = params_channels(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 dai_data->rate = params_rate(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 /* Q6 only supports 16 as now */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800223 dai_data->port_config.slim_sch.bit_width = 16;
224 dai_data->port_config.slim_sch.data_format = 0;
225 dai_data->port_config.slim_sch.num_channels = dai_data->channels;
226 dai_data->port_config.slim_sch.reserved = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800228 dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
229 "num_channel %hu slave_ch_mapping[0] %hu\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800231 "sample_rate %d\n", __func__,
232 dai_data->port_config.slim_sch.slimbus_dev_id,
233 dai_data->port_config.slim_sch.bit_width,
234 dai_data->port_config.slim_sch.data_format,
235 dai_data->port_config.slim_sch.num_channels,
236 dai_data->port_config.slim_sch.slave_ch_mapping[0],
237 dai_data->port_config.slim_sch.slave_ch_mapping[1],
238 dai_data->port_config.slim_sch.slave_ch_mapping[2],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239 dai_data->rate);
240
241 return 0;
242}
243
244static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
245 struct snd_soc_dai *dai, int stream)
246{
247 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
248
249 dai_data->channels = params_channels(params);
250 dai_data->rate = params_rate(params);
251
252 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
253 dai_data->channels, dai_data->rate);
254
255 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
256
257 return 0;
258}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700259static int msm_dai_q6_auxpcm_hw_params(
260 struct snd_pcm_substream *substream,
261 struct snd_pcm_hw_params *params,
262 struct snd_soc_dai *dai)
263{
264 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
265 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
266 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
267
268 if (params_channels(params) != 1) {
269 dev_err(dai->dev, "AUX PCM supports only mono stream\n");
270 return -EINVAL;
271 }
272 dai_data->channels = params_channels(params);
273
274 if (params_rate(params) != 8000) {
275 dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
276 return -EINVAL;
277 }
278 dai_data->rate = params_rate(params);
279 dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
280 dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
281 dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
282 dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
283 dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
284 dai_data->port_config.pcm.data = auxpcm_pdata->data;
285
286 return 0;
287}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530289static int get_frame_size(u16 rate, u16 ch)
290{
291 if (rate == 8000) {
292 if (ch == 1)
293 return 128 * 2;
294 else
295 return 128 * 2 * 2;
296 } else if (rate == 16000) {
297 if (ch == 1)
298 return 128 * 2 * 2;
299 else
300 return 128 * 2 * 4;
301 } else if (rate == 48000) {
302 if (ch == 1)
303 return 128 * 2 * 6;
304 else
305 return 128 * 2 * 12;
306 } else
307 return 128 * 2 * 12;
308}
309
310static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
311 struct snd_soc_dai *dai)
312{
313 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
314
315 dai_data->rate = params_rate(params);
316 dai_data->port_config.rtproxy.num_ch =
317 params_channels(params);
318
319 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
320 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
321
322 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
323 dai_data->port_config.rtproxy.interleaved = 1;
324 dai_data->port_config.rtproxy.frame_sz = get_frame_size(dai_data->rate,
325 dai_data->port_config.rtproxy.num_ch);
326 dai_data->port_config.rtproxy.jitter =
327 dai_data->port_config.rtproxy.frame_sz/2;
328 dai_data->port_config.rtproxy.lw_mark = 0;
329 dai_data->port_config.rtproxy.hw_mark = 0;
330 dai_data->port_config.rtproxy.rsvd = 0;
331
332 return 0;
333}
334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335/* Current implementation assumes hw_param is called once
336 * This may not be the case but what to do when ADM and AFE
337 * port are already opened and parameter changes
338 */
339static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
340 struct snd_pcm_hw_params *params,
341 struct snd_soc_dai *dai)
342{
343 int rc = 0;
344
345 switch (dai->id) {
346 case PRIMARY_I2S_TX:
347 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800348 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
350 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800351 case MI2S_RX:
352 rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
353 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800355 case SLIMBUS_1_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800357 case SLIMBUS_1_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
359 substream->stream);
360 break;
361 case INT_BT_SCO_RX:
362 case INT_BT_SCO_TX:
363 case INT_FM_RX:
364 case INT_FM_TX:
365 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
366 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530367 case RT_PROXY_DAI_001_TX:
368 case RT_PROXY_DAI_001_RX:
369 case RT_PROXY_DAI_002_TX:
370 case RT_PROXY_DAI_002_RX:
371 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
372 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700373 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700374 case VOICE_RECORD_RX:
375 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700376 rc = 0;
377 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700378 default:
379 dev_err(dai->dev, "invalid AFE port ID\n");
380 rc = -EINVAL;
381 break;
382 }
383
384 return rc;
385}
386
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700387static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
388 struct snd_soc_dai *dai)
389{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700390 int rc = 0;
391
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800392 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700393
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800394 if (aux_pcm_count == 0) {
395 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
396 " return\n", __func__, dai->id);
397 mutex_unlock(&aux_pcm_mutex);
398 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700399 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800400
401 aux_pcm_count--;
402
403 if (aux_pcm_count > 0) {
404 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
405 __func__, dai->id, aux_pcm_count);
406 mutex_unlock(&aux_pcm_mutex);
407 return;
408 } else if (aux_pcm_count < 0) {
409 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
410 " aux_pcm_count = %d < 0\n",
411 __func__, dai->id, aux_pcm_count);
412 aux_pcm_count = 0;
413 mutex_unlock(&aux_pcm_mutex);
414 return;
415 }
416
417 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
418 dai->id, aux_pcm_count);
419
420 clk_disable(pcm_clk);
421 rc = afe_close(PCM_RX); /* can block */
422 if (IS_ERR_VALUE(rc))
423 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
424
425 rc = afe_close(PCM_TX);
426 if (IS_ERR_VALUE(rc))
427 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
428
429 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700430}
431
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700432static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
433 struct snd_soc_dai *dai)
434{
435 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530436 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700439 switch (dai->id) {
440 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700441 case VOICE_RECORD_TX:
442 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700443 pr_debug("%s, stop pseudo port:%d\n",
444 __func__, dai->id);
445 rc = afe_stop_pseudo_port(dai->id);
446 break;
447 default:
448 rc = afe_close(dai->id); /* can block */
449 break;
450 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700451 if (IS_ERR_VALUE(rc))
452 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530453 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
454 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700455 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
456 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700457}
458
459static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
460 struct snd_soc_dai *dai)
461{
462 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
463 int rc = 0;
464
465 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
466 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
467
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800468 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700469
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800470 if (aux_pcm_count == 2) {
471 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
472 " return.\n", __func__, dai->id);
473 mutex_unlock(&aux_pcm_mutex);
474 return 0;
475 } else if (aux_pcm_count > 2) {
476 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
477 " aux_pcm_count = %d > 2\n",
478 __func__, dai->id, aux_pcm_count);
479 mutex_unlock(&aux_pcm_mutex);
480 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700481 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800482
483 aux_pcm_count++;
484 if (aux_pcm_count == 2) {
485 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
486 " increment\n", __func__, dai->id, aux_pcm_count);
487 mutex_unlock(&aux_pcm_mutex);
488 return 0;
489 }
490
491 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
492 __func__, dai->id, aux_pcm_count);
493
494 rc = afe_q6_interface_prepare();
495 if (IS_ERR_VALUE(rc))
496 dev_err(dai->dev, "fail to open AFE APR\n");
497
498 /*
499 * For AUX PCM Interface the below sequence of clk
500 * settings and afe_open is a strict requirement.
501 *
502 * Also using afe_open instead of afe_port_start_nowait
503 * to make sure the port is open before deasserting the
504 * clock line. This is required because pcm register is
505 * not written before clock deassert. Hence the hw does
506 * not get updated with new setting if the below clock
507 * assert/deasset and afe_open sequence is not followed.
508 */
509
510 clk_reset(pcm_clk, CLK_RESET_ASSERT);
511
512 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
513
514 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
515
516 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
517 if (rc < 0) {
518 pr_err("%s: clk_set_rate failed\n", __func__);
519 return rc;
520 }
521
522 clk_enable(pcm_clk);
523 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
524
525 mutex_unlock(&aux_pcm_mutex);
526
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700527 return rc;
528}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
530static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
531 struct snd_soc_dai *dai)
532{
533 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
534 int rc = 0;
535
Patrick Lai831561e2011-07-26 22:51:27 -0700536 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700537 /* PORT START should be set if prepare called in active state */
538 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700539 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700540 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543}
544
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700545static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
546 int cmd, struct snd_soc_dai *dai)
547{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700548 int rc = 0;
549
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800550 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
551 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700552
553 switch (cmd) {
554
555 case SNDRV_PCM_TRIGGER_START:
556 case SNDRV_PCM_TRIGGER_RESUME:
557 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
558 /* afe_open will be called from prepare */
559 return 0;
560
561 case SNDRV_PCM_TRIGGER_STOP:
562 case SNDRV_PCM_TRIGGER_SUSPEND:
563 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800564 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700565
566 default:
567 rc = -EINVAL;
568 }
569
570 return rc;
571
572}
573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
575 struct snd_soc_dai *dai)
576{
577 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
578 int rc = 0;
579
580 /* Start/stop port without waiting for Q6 AFE response. Need to have
581 * native q6 AFE driver propagates AFE response in order to handle
582 * port start/stop command error properly if error does arise.
583 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530584 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
585 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 switch (cmd) {
587 case SNDRV_PCM_TRIGGER_START:
588 case SNDRV_PCM_TRIGGER_RESUME:
589 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
590 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700591 switch (dai->id) {
592 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700593 case VOICE_RECORD_TX:
594 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700595 afe_pseudo_port_start_nowait(dai->id);
596 break;
597 default:
598 afe_port_start_nowait(dai->id,
599 &dai_data->port_config, dai_data->rate);
600 break;
601 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 set_bit(STATUS_PORT_STARTED,
603 dai_data->status_mask);
604 }
605 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606 case SNDRV_PCM_TRIGGER_STOP:
607 case SNDRV_PCM_TRIGGER_SUSPEND:
608 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
609 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700610 switch (dai->id) {
611 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700612 case VOICE_RECORD_TX:
613 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700614 afe_pseudo_port_stop_nowait(dai->id);
615 break;
616 default:
617 afe_port_stop_nowait(dai->id);
618 break;
619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 clear_bit(STATUS_PORT_STARTED,
621 dai_data->status_mask);
622 }
623 break;
624
625 default:
626 rc = -EINVAL;
627 }
628
629 return rc;
630}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700631static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
632{
633 struct msm_dai_q6_dai_data *dai_data;
634 int rc = 0;
635
636 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
637 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
638
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800639 mutex_lock(&aux_pcm_mutex);
640
641 if (!auxpcm_plat_data)
642 auxpcm_plat_data = auxpcm_pdata;
643 else if (auxpcm_plat_data != auxpcm_pdata) {
644
645 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
646 " same platform data\n");
647 return -EINVAL;
648 }
649
650 /*
651 * The clk name for AUX PCM operation is passed as platform
652 * data to the cpu driver, since cpu drive is unaware of any
653 * boarc specific configuration.
654 */
655 if (!pcm_clk) {
656
657 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
658
659 if (IS_ERR(pcm_clk)) {
660 pr_err("%s: could not get pcm_clk\n", __func__);
661 pcm_clk = NULL;
662 return -ENODEV;
663 }
664 }
665
666 mutex_unlock(&aux_pcm_mutex);
667
668 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700669
670 if (!dai_data) {
671 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
672 dai->id);
673 rc = -ENOMEM;
674 } else
675 dev_set_drvdata(dai->dev, dai_data);
676
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800677 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700678 return rc;
679}
680
681static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
682{
683 struct msm_dai_q6_dai_data *dai_data;
684 int rc;
685
686 dai_data = dev_get_drvdata(dai->dev);
687
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800688 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700689
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800690 if (aux_pcm_count == 0) {
691 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
692 " up and return\n", __func__, dai->id);
693 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700694 }
695
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800696 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700697
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800698 if (aux_pcm_count > 0) {
699 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
700 __func__, dai->id, aux_pcm_count);
701 goto done;
702 } else if (aux_pcm_count < 0) {
703 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
704 " aux_pcm_count = %d < 0\n",
705 __func__, dai->id, aux_pcm_count);
706 goto done;
707 }
708
709 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
710 "closing afe\n",
711 __func__, dai->id, aux_pcm_count);
712
713 rc = afe_close(PCM_RX); /* can block */
714 if (IS_ERR_VALUE(rc))
715 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
716
717 rc = afe_close(PCM_TX);
718 if (IS_ERR_VALUE(rc))
719 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
720
721done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700722 kfree(dai_data);
723 snd_soc_unregister_dai(dai->dev);
724
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800725 mutex_unlock(&aux_pcm_mutex);
726
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700727 return 0;
728}
Kuirong Wang274f21a2011-12-15 21:29:08 -0800729static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
730{
731 struct msm_dai_q6_dai_data *dai_data;
732 int rc = 0;
733
734 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
735 GFP_KERNEL);
736
737 if (!dai_data) {
738 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
739 dai->id);
740 rc = -ENOMEM;
741 goto rtn;
742 } else
743 dev_set_drvdata(dai->dev, dai_data);
744
745 rc = msm_dai_q6_mi2s_platform_data_validation(dai);
746 if (rc != 0) {
747 pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
748 __func__);
749 kfree(dai_data);
750 }
751rtn:
752 return rc;
753}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754
755static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
756{
757 struct msm_dai_q6_dai_data *dai_data;
758 int rc = 0;
759
760 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
761 GFP_KERNEL);
762
763 if (!dai_data) {
764 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
765 dai->id);
766 rc = -ENOMEM;
767 } else
768 dev_set_drvdata(dai->dev, dai_data);
769
770 return rc;
771}
772
773static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
774{
775 struct msm_dai_q6_dai_data *dai_data;
776 int rc;
777
778 dai_data = dev_get_drvdata(dai->dev);
779
780 /* If AFE port is still up, close it */
781 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700782 switch (dai->id) {
783 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700784 case VOICE_RECORD_TX:
785 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700786 pr_debug("%s, stop pseudo port:%d\n",
787 __func__, dai->id);
788 rc = afe_stop_pseudo_port(dai->id);
789 break;
790 default:
791 rc = afe_close(dai->id); /* can block */
792 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700793 if (IS_ERR_VALUE(rc))
794 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530795 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796 }
797 kfree(dai_data);
798 snd_soc_unregister_dai(dai->dev);
799
800 return 0;
801}
802
Lei Zhou157c1842011-08-19 13:05:04 -0400803static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
804{
805 int rc = 0;
806
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800807 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
808 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -0400809 switch (dai->id) {
810 case PRIMARY_I2S_TX:
811 case PRIMARY_I2S_RX:
Kuirong Wang274f21a2011-12-15 21:29:08 -0800812 case MI2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800813 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -0400814 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
815 break;
816 default:
817 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
818 rc = -EINVAL;
819 break;
820 }
821
822 return rc;
823}
824
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800825static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
826 unsigned int tx_num, unsigned int *tx_slot,
827 unsigned int rx_num, unsigned int *rx_slot)
828
829{
830 int rc = 0;
831 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
832 unsigned int i = 0;
833
834 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
835 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800836 switch (dai->id) {
837 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800838 case SLIMBUS_1_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800839 /* channel number to be between 128 and 255. For RX port
840 * use channel numbers from 138 to 144, for TX port
841 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800842 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800843 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800844 if (!rx_slot)
845 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800846 for (i = 0; i < rx_num; i++) {
847 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
848 rx_slot[i];
849 pr_debug("%s: find number of channels[%d] ch[%d]\n",
850 __func__, i,
851 rx_slot[i]);
852 }
853 dai_data->port_config.slim_sch.num_channels = rx_num;
854 pr_debug("%s:SLIMBUS_0_RX cnt[%d] ch[%d %d]\n", __func__,
855 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
856 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
857
858 break;
859 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800860 case SLIMBUS_1_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800861 /* channel number to be between 128 and 255. For RX port
862 * use channel numbers from 138 to 144, for TX port
863 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800864 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800865 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800866 if (!tx_slot)
867 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800868 for (i = 0; i < tx_num; i++) {
869 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
870 tx_slot[i];
871 pr_debug("%s: find number of channels[%d] ch[%d]\n",
872 __func__, i, tx_slot[i]);
873 }
874 dai_data->port_config.slim_sch.num_channels = tx_num;
875 pr_debug("%s:SLIMBUS_0_TX cnt[%d] ch[%d %d]\n", __func__,
876 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
877 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
878 break;
879 default:
880 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
881 rc = -EINVAL;
882 break;
883 }
884 return rc;
885}
886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888 .prepare = msm_dai_q6_prepare,
889 .trigger = msm_dai_q6_trigger,
890 .hw_params = msm_dai_q6_hw_params,
891 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400892 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800893 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894};
895
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700896static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
897 .prepare = msm_dai_q6_auxpcm_prepare,
898 .trigger = msm_dai_q6_auxpcm_trigger,
899 .hw_params = msm_dai_q6_auxpcm_hw_params,
900 .shutdown = msm_dai_q6_auxpcm_shutdown,
901};
902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
904 .playback = {
905 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
906 SNDRV_PCM_RATE_16000,
907 .formats = SNDRV_PCM_FMTBIT_S16_LE,
908 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -0800909 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700910 .rate_min = 8000,
911 .rate_max = 48000,
912 },
913 .ops = &msm_dai_q6_ops,
914 .probe = msm_dai_q6_dai_probe,
915 .remove = msm_dai_q6_dai_remove,
916};
917
918static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
919 .capture = {
920 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
921 SNDRV_PCM_RATE_16000,
922 .formats = SNDRV_PCM_FMTBIT_S16_LE,
923 .channels_min = 1,
924 .channels_max = 2,
925 .rate_min = 8000,
926 .rate_max = 48000,
927 },
928 .ops = &msm_dai_q6_ops,
929 .probe = msm_dai_q6_dai_probe,
930 .remove = msm_dai_q6_dai_remove,
931};
932
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530933static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
934 .playback = {
935 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
936 SNDRV_PCM_RATE_16000,
937 .formats = SNDRV_PCM_FMTBIT_S16_LE,
938 .channels_min = 1,
939 .channels_max = 2,
940 .rate_min = 8000,
941 .rate_max = 48000,
942 },
943 .ops = &msm_dai_q6_ops,
944 .probe = msm_dai_q6_dai_probe,
945 .remove = msm_dai_q6_dai_remove,
946};
947
948static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
949 .capture = {
950 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
951 SNDRV_PCM_RATE_16000,
952 .formats = SNDRV_PCM_FMTBIT_S16_LE,
953 .channels_min = 1,
954 .channels_max = 2,
955 .rate_min = 8000,
956 .rate_max = 48000,
957 },
958 .ops = &msm_dai_q6_ops,
959 .probe = msm_dai_q6_dai_probe,
960 .remove = msm_dai_q6_dai_remove,
961};
962
Helen Zeng0705a5f2011-10-14 15:29:52 -0700963static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
964 .playback = {
965 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
966 SNDRV_PCM_RATE_16000,
967 .formats = SNDRV_PCM_FMTBIT_S16_LE,
968 .channels_min = 1,
969 .channels_max = 2,
970 .rate_max = 48000,
971 .rate_min = 8000,
972 },
973 .ops = &msm_dai_q6_ops,
974 .probe = msm_dai_q6_dai_probe,
975 .remove = msm_dai_q6_dai_remove,
976};
977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
979 .playback = {
980 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
981 SNDRV_PCM_RATE_16000,
982 .formats = SNDRV_PCM_FMTBIT_S16_LE,
983 .channels_min = 1,
984 .channels_max = 2,
985 .rate_min = 8000,
986 .rate_max = 48000,
987 },
988 .ops = &msm_dai_q6_ops,
989 .probe = msm_dai_q6_dai_probe,
990 .remove = msm_dai_q6_dai_remove,
991};
992
993static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
994 .capture = {
995 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
996 SNDRV_PCM_RATE_16000,
997 .formats = SNDRV_PCM_FMTBIT_S16_LE,
998 .channels_min = 1,
999 .channels_max = 2,
1000 .rate_min = 8000,
1001 .rate_max = 48000,
1002 },
1003 .ops = &msm_dai_q6_ops,
1004 .probe = msm_dai_q6_dai_probe,
1005 .remove = msm_dai_q6_dai_remove,
1006};
1007
Helen Zenge3d716a2011-10-14 16:32:16 -07001008static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1009 .capture = {
1010 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1011 SNDRV_PCM_RATE_16000,
1012 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1013 .channels_min = 1,
1014 .channels_max = 2,
1015 .rate_min = 8000,
1016 .rate_max = 48000,
1017 },
1018 .ops = &msm_dai_q6_ops,
1019 .probe = msm_dai_q6_dai_probe,
1020 .remove = msm_dai_q6_dai_remove,
1021};
1022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1024 .playback = {
1025 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1026 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1027 .channels_min = 1,
1028 .channels_max = 1,
1029 .rate_max = 16000,
1030 .rate_min = 8000,
1031 },
1032 .ops = &msm_dai_q6_ops,
1033 .probe = msm_dai_q6_dai_probe,
1034 .remove = msm_dai_q6_dai_remove,
1035};
1036
1037static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1038 .playback = {
1039 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1040 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1041 .channels_min = 1,
1042 .channels_max = 1,
1043 .rate_max = 16000,
1044 .rate_min = 8000,
1045 },
1046 .ops = &msm_dai_q6_ops,
1047 .probe = msm_dai_q6_dai_probe,
1048 .remove = msm_dai_q6_dai_remove,
1049};
1050
1051static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1052 .playback = {
1053 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1054 SNDRV_PCM_RATE_16000,
1055 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1056 .channels_min = 2,
1057 .channels_max = 2,
1058 .rate_max = 48000,
1059 .rate_min = 8000,
1060 },
1061 .ops = &msm_dai_q6_ops,
1062 .probe = msm_dai_q6_dai_probe,
1063 .remove = msm_dai_q6_dai_remove,
1064};
1065
1066static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1067 .playback = {
1068 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1069 SNDRV_PCM_RATE_16000,
1070 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1071 .channels_min = 2,
1072 .channels_max = 2,
1073 .rate_max = 48000,
1074 .rate_min = 8000,
1075 },
1076 .ops = &msm_dai_q6_ops,
1077 .probe = msm_dai_q6_dai_probe,
1078 .remove = msm_dai_q6_dai_remove,
1079};
1080
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001081static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1082 .playback = {
1083 .rates = SNDRV_PCM_RATE_8000,
1084 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1085 .channels_min = 1,
1086 .channels_max = 1,
1087 .rate_max = 8000,
1088 .rate_min = 8000,
1089 },
1090 .ops = &msm_dai_q6_auxpcm_ops,
1091 .probe = msm_dai_q6_dai_auxpcm_probe,
1092 .remove = msm_dai_q6_dai_auxpcm_remove,
1093};
1094
1095static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1096 .capture = {
1097 .rates = SNDRV_PCM_RATE_8000,
1098 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1099 .channels_min = 1,
1100 .channels_max = 1,
1101 .rate_max = 8000,
1102 .rate_min = 8000,
1103 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001104 .ops = &msm_dai_q6_auxpcm_ops,
1105 .probe = msm_dai_q6_dai_auxpcm_probe,
1106 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001107};
1108
Kuirong Wang274f21a2011-12-15 21:29:08 -08001109static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
1110 .playback = {
1111 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1112 SNDRV_PCM_RATE_16000,
1113 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1114 .channels_min = 1,
1115 .rate_min = 8000,
1116 .rate_max = 48000,
1117 },
1118 .ops = &msm_dai_q6_ops,
1119 .probe = msm_dai_q6_dai_mi2s_probe,
1120 .remove = msm_dai_q6_dai_probe,
1121};
1122
Neema Shetty3c9d2862012-03-11 01:25:32 -08001123static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1124 .playback = {
1125 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1126 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1127 .channels_min = 1,
1128 .channels_max = 1,
1129 .rate_min = 8000,
1130 .rate_max = 16000,
1131 },
1132 .ops = &msm_dai_q6_ops,
1133 .probe = msm_dai_q6_dai_probe,
1134 .remove = msm_dai_q6_dai_remove,
1135};
1136
1137static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1138 .capture = {
1139 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1140 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1141 .channels_min = 1,
1142 .channels_max = 1,
1143 .rate_min = 8000,
1144 .rate_max = 16000,
1145 },
1146 .ops = &msm_dai_q6_ops,
1147 .probe = msm_dai_q6_dai_probe,
1148 .remove = msm_dai_q6_dai_remove,
1149};
1150
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001151/* To do: change to register DAIs as batch */
1152static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1153{
1154 int rc = 0;
1155
1156 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1157
1158 switch (pdev->id) {
1159 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001160 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1162 break;
1163 case PRIMARY_I2S_TX:
1164 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1165 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001166 case PCM_RX:
1167 rc = snd_soc_register_dai(&pdev->dev,
1168 &msm_dai_q6_aux_pcm_rx_dai);
1169 break;
1170 case PCM_TX:
1171 rc = snd_soc_register_dai(&pdev->dev,
1172 &msm_dai_q6_aux_pcm_tx_dai);
1173 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -08001174 case MI2S_RX:
1175 rc = snd_soc_register_dai(&pdev->dev,
1176 &msm_dai_q6_mi2s_rx_dai);
1177 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 case SLIMBUS_0_RX:
1179 rc = snd_soc_register_dai(&pdev->dev,
1180 &msm_dai_q6_slimbus_rx_dai);
1181 break;
1182 case SLIMBUS_0_TX:
1183 rc = snd_soc_register_dai(&pdev->dev,
1184 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001185 break;
1186
1187 case SLIMBUS_1_RX:
1188 rc = snd_soc_register_dai(&pdev->dev,
1189 &msm_dai_q6_slimbus_1_rx_dai);
1190 break;
1191 case SLIMBUS_1_TX:
1192 rc = snd_soc_register_dai(&pdev->dev,
1193 &msm_dai_q6_slimbus_1_tx_dai);
1194 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 case INT_BT_SCO_RX:
1196 rc = snd_soc_register_dai(&pdev->dev,
1197 &msm_dai_q6_bt_sco_rx_dai);
1198 break;
1199 case INT_BT_SCO_TX:
1200 rc = snd_soc_register_dai(&pdev->dev,
1201 &msm_dai_q6_bt_sco_tx_dai);
1202 break;
1203 case INT_FM_RX:
1204 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1205 break;
1206 case INT_FM_TX:
1207 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1208 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301209 case RT_PROXY_DAI_001_RX:
1210 case RT_PROXY_DAI_002_RX:
1211 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1212 break;
1213 case RT_PROXY_DAI_001_TX:
1214 case RT_PROXY_DAI_002_TX:
1215 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1216 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001217 case VOICE_PLAYBACK_TX:
1218 rc = snd_soc_register_dai(&pdev->dev,
1219 &msm_dai_q6_voice_playback_tx_dai);
1220 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001221 case VOICE_RECORD_RX:
1222 case VOICE_RECORD_TX:
1223 rc = snd_soc_register_dai(&pdev->dev,
1224 &msm_dai_q6_incall_record_dai);
1225 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 default:
1227 rc = -ENODEV;
1228 break;
1229 }
1230 return rc;
1231}
1232
1233static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1234{
1235 snd_soc_unregister_dai(&pdev->dev);
1236 return 0;
1237}
1238
1239static struct platform_driver msm_dai_q6_driver = {
1240 .probe = msm_dai_q6_dev_probe,
1241 .remove = msm_dai_q6_dev_remove,
1242 .driver = {
1243 .name = "msm-dai-q6",
1244 .owner = THIS_MODULE,
1245 },
1246};
1247
1248static int __init msm_dai_q6_init(void)
1249{
1250 return platform_driver_register(&msm_dai_q6_driver);
1251}
1252module_init(msm_dai_q6_init);
1253
1254static void __exit msm_dai_q6_exit(void)
1255{
1256 platform_driver_unregister(&msm_dai_q6_driver);
1257}
1258module_exit(msm_dai_q6_exit);
1259
1260/* Module information */
1261MODULE_DESCRIPTION("MSM DSP DAI driver");
1262MODULE_LICENSE("GPL v2");