blob: a53dd449858f3e36a362f477943ddd248f3e9c4d [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;
39 union afe_port_config port_config;
40};
41
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070042static struct clk *pcm_clk;
Kiran Kandi5f4ab692012-02-23 11:23:56 -080043static DEFINE_MUTEX(aux_pcm_mutex);
44static int aux_pcm_count;
45static struct msm_dai_auxpcm_pdata *auxpcm_plat_data;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070046
Kuirong Wang875d1ec2012-04-02 19:56:25 -070047static int msm_dai_q6_mi2s_format_put(struct snd_kcontrol *kcontrol,
48 struct snd_ctl_elem_value *ucontrol)
49{
50
51 struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
52 int value = ucontrol->value.integer.value[0];
53 dai_data->port_config.mi2s.format = value;
54 pr_debug("%s: value = %d, channel = %d, line = %d\n",
55 __func__, value, dai_data->port_config.mi2s.channel,
56 dai_data->port_config.mi2s.line);
57 return 0;
58}
59
60static int msm_dai_q6_mi2s_format_get(struct snd_kcontrol *kcontrol,
61 struct snd_ctl_elem_value *ucontrol)
62{
63
64 struct msm_dai_q6_dai_data *dai_data = kcontrol->private_data;
65 ucontrol->value.integer.value[0] = dai_data->port_config.mi2s.format ;
66 return 0;
67}
68
69
70/* MI2S format field for AFE_PORT_CMD_I2S_CONFIG command
71 * 0: linear PCM
72 * 1: non-linear PCM
73 * 2: PCM data in IEC 60968 container
74 * 3: compressed data in IEC 60958 container
75 */
76static const char *mi2s_format[] = {
77 "LPCM",
78 "Compr",
79 "60958-LPCM",
80 "60958-Compr"};
81
82static const struct soc_enum mi2s_config_enum[] = {
83 SOC_ENUM_SINGLE_EXT(4, mi2s_format),
84};
85
86static const struct snd_kcontrol_new mi2s_config_controls[] = {
87 SOC_ENUM_EXT("MI2S RX Format", mi2s_config_enum[0],
88 msm_dai_q6_mi2s_format_get,
89 msm_dai_q6_mi2s_format_put),
90 SOC_ENUM_EXT("SEC RX Format", mi2s_config_enum[0],
91 msm_dai_q6_mi2s_format_get,
92 msm_dai_q6_mi2s_format_put),
93};
94
Kuirong Wang274f21a2011-12-15 21:29:08 -080095static u8 num_of_bits_set(u8 sd_line_mask)
96{
97 u8 num_bits_set = 0;
98
99 while (sd_line_mask) {
100 num_bits_set++;
101 sd_line_mask = sd_line_mask & (sd_line_mask - 1);
102 }
103 return num_bits_set;
104}
105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
107 struct snd_soc_dai *dai, int stream)
108{
109 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
110
111 dai_data->channels = params_channels(params);
112 switch (dai_data->channels) {
113 case 2:
114 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
115 break;
116 case 1:
117 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
118 break;
119 default:
120 return -EINVAL;
121 break;
122 }
123 dai_data->rate = params_rate(params);
124
125 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
126 dai_data->channels, dai_data->rate);
127
128 /* Q6 only supports 16 as now */
129 dai_data->port_config.mi2s.bitwidth = 16;
130 dai_data->port_config.mi2s.line = 1;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800131 return 0;
132}
133
134static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
135 struct snd_soc_dai *dai, int stream)
136{
137 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
138 struct msm_mi2s_data *mi2s_pdata =
139 (struct msm_mi2s_data *) dai->dev->platform_data;
140
141 dai_data->channels = params_channels(params);
142 if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
143 switch (dai_data->channels) {
144 case 2:
145 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
146 break;
147 case 1:
148 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
149 break;
150 default:
151 pr_warn("greater than stereo has not been validated");
152 break;
153 }
154 }
Kuirong Wangc70819f2012-02-08 16:12:23 -0800155 dai_data->rate = params_rate(params);
Kuirong Wang274f21a2011-12-15 21:29:08 -0800156 /* Q6 only supports 16 as now */
157 dai_data->port_config.mi2s.bitwidth = 16;
Lei Zhou157c1842011-08-19 13:05:04 -0400158
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700159 pr_debug("%s: format = %d, channel = %d, line = %d\n",
160 __func__, dai_data->port_config.mi2s.format,
161 dai_data->port_config.mi2s.channel,
162 dai_data->port_config.mi2s.line);
Lei Zhou157c1842011-08-19 13:05:04 -0400163 return 0;
164}
165
Kuirong Wang274f21a2011-12-15 21:29:08 -0800166static int msm_dai_q6_mi2s_platform_data_validation(
167 struct snd_soc_dai *dai)
168{
169 u8 num_of_sd_lines;
170 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
171 struct msm_mi2s_data *mi2s_pdata =
172 (struct msm_mi2s_data *)dai->dev->platform_data;
173 struct snd_soc_dai_driver *dai_driver =
174 (struct snd_soc_dai_driver *)dai->driver;
175
176 num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);
177
178 switch (num_of_sd_lines) {
179 case 1:
180 switch (mi2s_pdata->sd_lines) {
181 case MSM_MI2S_SD0:
182 dai_data->port_config.mi2s.line = AFE_I2S_SD0;
183 break;
184 case MSM_MI2S_SD1:
185 dai_data->port_config.mi2s.line = AFE_I2S_SD1;
186 break;
187 case MSM_MI2S_SD2:
188 dai_data->port_config.mi2s.line = AFE_I2S_SD2;
189 break;
190 case MSM_MI2S_SD3:
191 dai_data->port_config.mi2s.line = AFE_I2S_SD3;
192 break;
193 default:
194 pr_err("%s: invalid SD line\n",
195 __func__);
196 goto error_invalid_data;
197 }
198 break;
199 case 2:
200 switch (mi2s_pdata->sd_lines) {
201 case MSM_MI2S_SD0 | MSM_MI2S_SD1:
202 dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
203 break;
204 case MSM_MI2S_SD2 | MSM_MI2S_SD3:
205 dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
206 break;
207 default:
208 pr_err("%s: invalid SD line\n",
209 __func__);
210 goto error_invalid_data;
211 }
212 break;
213 case 3:
214 switch (mi2s_pdata->sd_lines) {
215 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
216 dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
217 break;
218 default:
219 pr_err("%s: invalid SD lines\n",
220 __func__);
221 goto error_invalid_data;
222 }
223 break;
224 case 4:
225 switch (mi2s_pdata->sd_lines) {
226 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
227 dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
228 break;
229 default:
230 pr_err("%s: invalid SD lines\n",
231 __func__);
232 goto error_invalid_data;
233 }
234 break;
235 default:
236 pr_err("%s: invalid SD lines\n", __func__);
237 goto error_invalid_data;
238 }
239 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
240 dai_driver->playback.channels_max = num_of_sd_lines << 1;
241
242 return 0;
243
244error_invalid_data:
245 return -EINVAL;
246}
247
Lei Zhou157c1842011-08-19 13:05:04 -0400248static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
249{
250 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
251
252 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
253 case SND_SOC_DAIFMT_CBS_CFS:
254 dai_data->port_config.mi2s.ws = 1; /* CPU is master */
255 break;
256 case SND_SOC_DAIFMT_CBM_CFM:
257 dai_data->port_config.mi2s.ws = 0; /* CPU is slave */
258 break;
259 default:
260 return -EINVAL;
261 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
263 return 0;
264}
265
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266
267static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
268 struct snd_soc_dai *dai, int stream)
269{
270 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700271
272 dai_data->channels = params_channels(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 dai_data->rate = params_rate(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 /* Q6 only supports 16 as now */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800276 dai_data->port_config.slim_sch.bit_width = 16;
277 dai_data->port_config.slim_sch.data_format = 0;
278 dai_data->port_config.slim_sch.num_channels = dai_data->channels;
279 dai_data->port_config.slim_sch.reserved = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700280
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800281 dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
282 "num_channel %hu slave_ch_mapping[0] %hu\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700284 "slave_port_mapping[3] %hu\n sample_rate %d\n", __func__,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800285 dai_data->port_config.slim_sch.slimbus_dev_id,
286 dai_data->port_config.slim_sch.bit_width,
287 dai_data->port_config.slim_sch.data_format,
288 dai_data->port_config.slim_sch.num_channels,
289 dai_data->port_config.slim_sch.slave_ch_mapping[0],
290 dai_data->port_config.slim_sch.slave_ch_mapping[1],
291 dai_data->port_config.slim_sch.slave_ch_mapping[2],
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700292 dai_data->port_config.slim_sch.slave_ch_mapping[3],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 dai_data->rate);
294
295 return 0;
296}
297
298static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
299 struct snd_soc_dai *dai, int stream)
300{
301 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
302
303 dai_data->channels = params_channels(params);
304 dai_data->rate = params_rate(params);
305
306 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
307 dai_data->channels, dai_data->rate);
308
309 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
310
311 return 0;
312}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700313static int msm_dai_q6_auxpcm_hw_params(
314 struct snd_pcm_substream *substream,
315 struct snd_pcm_hw_params *params,
316 struct snd_soc_dai *dai)
317{
318 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
319 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
320 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
321
322 if (params_channels(params) != 1) {
323 dev_err(dai->dev, "AUX PCM supports only mono stream\n");
324 return -EINVAL;
325 }
326 dai_data->channels = params_channels(params);
327
328 if (params_rate(params) != 8000) {
329 dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
330 return -EINVAL;
331 }
332 dai_data->rate = params_rate(params);
333 dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
334 dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
335 dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
336 dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
337 dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
338 dai_data->port_config.pcm.data = auxpcm_pdata->data;
339
340 return 0;
341}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530343static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
344 struct snd_soc_dai *dai)
345{
346 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
347
348 dai_data->rate = params_rate(params);
349 dai_data->port_config.rtproxy.num_ch =
350 params_channels(params);
351
352 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
353 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
354
355 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
356 dai_data->port_config.rtproxy.interleaved = 1;
Asish Bhattacharyab3568cf2012-03-15 07:05:46 +0530357 dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530358 dai_data->port_config.rtproxy.jitter =
359 dai_data->port_config.rtproxy.frame_sz/2;
360 dai_data->port_config.rtproxy.lw_mark = 0;
361 dai_data->port_config.rtproxy.hw_mark = 0;
362 dai_data->port_config.rtproxy.rsvd = 0;
363
364 return 0;
365}
366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367/* Current implementation assumes hw_param is called once
368 * This may not be the case but what to do when ADM and AFE
369 * port are already opened and parameter changes
370 */
371static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
372 struct snd_pcm_hw_params *params,
373 struct snd_soc_dai *dai)
374{
375 int rc = 0;
376
377 switch (dai->id) {
378 case PRIMARY_I2S_TX:
379 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800380 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
382 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800383 case MI2S_RX:
384 rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
385 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700386 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800387 case SLIMBUS_1_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800389 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700390 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800391 case SLIMBUS_4_RX:
392 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
394 substream->stream);
395 break;
396 case INT_BT_SCO_RX:
397 case INT_BT_SCO_TX:
398 case INT_FM_RX:
399 case INT_FM_TX:
400 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
401 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530402 case RT_PROXY_DAI_001_TX:
403 case RT_PROXY_DAI_001_RX:
404 case RT_PROXY_DAI_002_TX:
405 case RT_PROXY_DAI_002_RX:
406 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
407 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700408 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700409 case VOICE_RECORD_RX:
410 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700411 rc = 0;
412 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700413 default:
414 dev_err(dai->dev, "invalid AFE port ID\n");
415 rc = -EINVAL;
416 break;
417 }
418
419 return rc;
420}
421
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700422static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
423 struct snd_soc_dai *dai)
424{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700425 int rc = 0;
426
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800427 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700428
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800429 if (aux_pcm_count == 0) {
430 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
431 " return\n", __func__, dai->id);
432 mutex_unlock(&aux_pcm_mutex);
433 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700434 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800435
436 aux_pcm_count--;
437
438 if (aux_pcm_count > 0) {
439 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
440 __func__, dai->id, aux_pcm_count);
441 mutex_unlock(&aux_pcm_mutex);
442 return;
443 } else if (aux_pcm_count < 0) {
444 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
445 " aux_pcm_count = %d < 0\n",
446 __func__, dai->id, aux_pcm_count);
447 aux_pcm_count = 0;
448 mutex_unlock(&aux_pcm_mutex);
449 return;
450 }
451
452 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
453 dai->id, aux_pcm_count);
454
455 clk_disable(pcm_clk);
456 rc = afe_close(PCM_RX); /* can block */
457 if (IS_ERR_VALUE(rc))
458 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
459
460 rc = afe_close(PCM_TX);
461 if (IS_ERR_VALUE(rc))
462 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
463
464 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700465}
466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
468 struct snd_soc_dai *dai)
469{
470 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530471 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700474 switch (dai->id) {
475 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700476 case VOICE_RECORD_TX:
477 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700478 pr_debug("%s, stop pseudo port:%d\n",
479 __func__, dai->id);
480 rc = afe_stop_pseudo_port(dai->id);
481 break;
482 default:
483 rc = afe_close(dai->id); /* can block */
484 break;
485 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700486 if (IS_ERR_VALUE(rc))
487 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530488 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
489 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700490 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
491 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700492}
493
494static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
495 struct snd_soc_dai *dai)
496{
497 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
498 int rc = 0;
499
500 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
501 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
502
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800503 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700504
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800505 if (aux_pcm_count == 2) {
506 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
507 " return.\n", __func__, dai->id);
508 mutex_unlock(&aux_pcm_mutex);
509 return 0;
510 } else if (aux_pcm_count > 2) {
511 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
512 " aux_pcm_count = %d > 2\n",
513 __func__, dai->id, aux_pcm_count);
514 mutex_unlock(&aux_pcm_mutex);
515 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700516 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800517
518 aux_pcm_count++;
519 if (aux_pcm_count == 2) {
520 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
521 " increment\n", __func__, dai->id, aux_pcm_count);
522 mutex_unlock(&aux_pcm_mutex);
523 return 0;
524 }
525
526 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
527 __func__, dai->id, aux_pcm_count);
528
529 rc = afe_q6_interface_prepare();
530 if (IS_ERR_VALUE(rc))
531 dev_err(dai->dev, "fail to open AFE APR\n");
532
533 /*
534 * For AUX PCM Interface the below sequence of clk
535 * settings and afe_open is a strict requirement.
536 *
537 * Also using afe_open instead of afe_port_start_nowait
538 * to make sure the port is open before deasserting the
539 * clock line. This is required because pcm register is
540 * not written before clock deassert. Hence the hw does
541 * not get updated with new setting if the below clock
542 * assert/deasset and afe_open sequence is not followed.
543 */
544
545 clk_reset(pcm_clk, CLK_RESET_ASSERT);
546
547 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
548
549 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
550
551 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
552 if (rc < 0) {
553 pr_err("%s: clk_set_rate failed\n", __func__);
554 return rc;
555 }
556
557 clk_enable(pcm_clk);
558 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
559
560 mutex_unlock(&aux_pcm_mutex);
561
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700562 return rc;
563}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564
565static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
566 struct snd_soc_dai *dai)
567{
568 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
569 int rc = 0;
570
Patrick Lai831561e2011-07-26 22:51:27 -0700571 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700572 /* PORT START should be set if prepare called in active state */
573 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700575 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578}
579
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700580static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
581 int cmd, struct snd_soc_dai *dai)
582{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700583 int rc = 0;
584
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800585 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
586 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700587
588 switch (cmd) {
589
590 case SNDRV_PCM_TRIGGER_START:
591 case SNDRV_PCM_TRIGGER_RESUME:
592 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
593 /* afe_open will be called from prepare */
594 return 0;
595
596 case SNDRV_PCM_TRIGGER_STOP:
597 case SNDRV_PCM_TRIGGER_SUSPEND:
598 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800599 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700600
601 default:
602 rc = -EINVAL;
603 }
604
605 return rc;
606
607}
608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
610 struct snd_soc_dai *dai)
611{
612 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
613 int rc = 0;
614
615 /* Start/stop port without waiting for Q6 AFE response. Need to have
616 * native q6 AFE driver propagates AFE response in order to handle
617 * port start/stop command error properly if error does arise.
618 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530619 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
620 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 switch (cmd) {
622 case SNDRV_PCM_TRIGGER_START:
623 case SNDRV_PCM_TRIGGER_RESUME:
624 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
625 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700626 switch (dai->id) {
627 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700628 case VOICE_RECORD_TX:
629 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700630 afe_pseudo_port_start_nowait(dai->id);
631 break;
632 default:
633 afe_port_start_nowait(dai->id,
634 &dai_data->port_config, dai_data->rate);
635 break;
636 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 set_bit(STATUS_PORT_STARTED,
638 dai_data->status_mask);
639 }
640 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700641 case SNDRV_PCM_TRIGGER_STOP:
642 case SNDRV_PCM_TRIGGER_SUSPEND:
643 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
644 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700645 switch (dai->id) {
646 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700647 case VOICE_RECORD_TX:
648 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700649 afe_pseudo_port_stop_nowait(dai->id);
650 break;
651 default:
652 afe_port_stop_nowait(dai->id);
653 break;
654 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 clear_bit(STATUS_PORT_STARTED,
656 dai_data->status_mask);
657 }
658 break;
659
660 default:
661 rc = -EINVAL;
662 }
663
664 return rc;
665}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700666static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
667{
668 struct msm_dai_q6_dai_data *dai_data;
669 int rc = 0;
670
671 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
672 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
673
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800674 mutex_lock(&aux_pcm_mutex);
675
676 if (!auxpcm_plat_data)
677 auxpcm_plat_data = auxpcm_pdata;
678 else if (auxpcm_plat_data != auxpcm_pdata) {
679
680 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
681 " same platform data\n");
682 return -EINVAL;
683 }
684
685 /*
686 * The clk name for AUX PCM operation is passed as platform
687 * data to the cpu driver, since cpu drive is unaware of any
688 * boarc specific configuration.
689 */
690 if (!pcm_clk) {
691
692 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
693
694 if (IS_ERR(pcm_clk)) {
695 pr_err("%s: could not get pcm_clk\n", __func__);
696 pcm_clk = NULL;
697 return -ENODEV;
698 }
699 }
700
701 mutex_unlock(&aux_pcm_mutex);
702
703 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700704
705 if (!dai_data) {
706 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
707 dai->id);
708 rc = -ENOMEM;
709 } else
710 dev_set_drvdata(dai->dev, dai_data);
711
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800712 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700713 return rc;
714}
715
716static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
717{
718 struct msm_dai_q6_dai_data *dai_data;
719 int rc;
720
721 dai_data = dev_get_drvdata(dai->dev);
722
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800723 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700724
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800725 if (aux_pcm_count == 0) {
726 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
727 " up and return\n", __func__, dai->id);
728 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700729 }
730
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800731 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700732
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800733 if (aux_pcm_count > 0) {
734 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
735 __func__, dai->id, aux_pcm_count);
736 goto done;
737 } else if (aux_pcm_count < 0) {
738 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
739 " aux_pcm_count = %d < 0\n",
740 __func__, dai->id, aux_pcm_count);
741 goto done;
742 }
743
744 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
745 "closing afe\n",
746 __func__, dai->id, aux_pcm_count);
747
748 rc = afe_close(PCM_RX); /* can block */
749 if (IS_ERR_VALUE(rc))
750 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
751
752 rc = afe_close(PCM_TX);
753 if (IS_ERR_VALUE(rc))
754 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
755
756done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700757 kfree(dai_data);
758 snd_soc_unregister_dai(dai->dev);
759
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800760 mutex_unlock(&aux_pcm_mutex);
761
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700762 return 0;
763}
Kuirong Wang274f21a2011-12-15 21:29:08 -0800764static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
765{
766 struct msm_dai_q6_dai_data *dai_data;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700767 struct msm_mi2s_data *mi2s_pdata =
768 (struct msm_mi2s_data *)dai->dev->platform_data;
769 const struct snd_kcontrol_new *kcontrol;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800770 int rc = 0;
771
772 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
773 GFP_KERNEL);
774
775 if (!dai_data) {
776 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
777 dai->id);
778 rc = -ENOMEM;
779 goto rtn;
780 } else
781 dev_set_drvdata(dai->dev, dai_data);
782
783 rc = msm_dai_q6_mi2s_platform_data_validation(dai);
784 if (rc != 0) {
785 pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
786 __func__);
787 kfree(dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700788 goto rtn;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800789 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700790 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX) {
791 kcontrol = &mi2s_config_controls[0];
792 rc = snd_ctl_add(dai->card->snd_card,
793 snd_ctl_new1(kcontrol, dai_data));
794 }
795
Kuirong Wang274f21a2011-12-15 21:29:08 -0800796rtn:
797 return rc;
798}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700799
800static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
801{
802 struct msm_dai_q6_dai_data *dai_data;
803 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700804 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805
806 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
807 GFP_KERNEL);
808
809 if (!dai_data) {
810 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
811 dai->id);
812 rc = -ENOMEM;
813 } else
814 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700815 if (dai->id == SECONDARY_I2S_RX) {
816 kcontrol = &mi2s_config_controls[1];
817 rc = snd_ctl_add(dai->card->snd_card,
818 snd_ctl_new1(kcontrol, dai_data));
819 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820
821 return rc;
822}
823
824static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
825{
826 struct msm_dai_q6_dai_data *dai_data;
827 int rc;
828
829 dai_data = dev_get_drvdata(dai->dev);
830
831 /* If AFE port is still up, close it */
832 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700833 switch (dai->id) {
834 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700835 case VOICE_RECORD_TX:
836 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700837 pr_debug("%s, stop pseudo port:%d\n",
838 __func__, dai->id);
839 rc = afe_stop_pseudo_port(dai->id);
840 break;
841 default:
842 rc = afe_close(dai->id); /* can block */
843 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 if (IS_ERR_VALUE(rc))
845 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530846 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847 }
848 kfree(dai_data);
849 snd_soc_unregister_dai(dai->dev);
850
851 return 0;
852}
853
Lei Zhou157c1842011-08-19 13:05:04 -0400854static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
855{
856 int rc = 0;
857
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800858 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
859 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -0400860 switch (dai->id) {
861 case PRIMARY_I2S_TX:
862 case PRIMARY_I2S_RX:
Kuirong Wang274f21a2011-12-15 21:29:08 -0800863 case MI2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800864 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -0400865 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
866 break;
867 default:
868 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
869 rc = -EINVAL;
870 break;
871 }
872
873 return rc;
874}
875
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800876static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
877 unsigned int tx_num, unsigned int *tx_slot,
878 unsigned int rx_num, unsigned int *rx_slot)
879
880{
881 int rc = 0;
882 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
883 unsigned int i = 0;
884
885 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
886 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800887 switch (dai->id) {
888 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800889 case SLIMBUS_1_RX:
Helen Zeng8f925502012-03-05 16:50:17 -0800890 case SLIMBUS_4_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800891 /* channel number to be between 128 and 255. For RX port
892 * use channel numbers from 138 to 144, for TX port
893 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800894 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800895 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800896 if (!rx_slot)
897 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800898 for (i = 0; i < rx_num; i++) {
899 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
900 rx_slot[i];
901 pr_debug("%s: find number of channels[%d] ch[%d]\n",
902 __func__, i,
903 rx_slot[i]);
904 }
905 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700906 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
907 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800908 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
909 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
910
911 break;
912 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800913 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700914 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800915 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800916 /* channel number to be between 128 and 255. For RX port
917 * use channel numbers from 138 to 144, for TX port
918 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800919 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800920 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800921 if (!tx_slot)
922 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800923 for (i = 0; i < tx_num; i++) {
924 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
925 tx_slot[i];
926 pr_debug("%s: find number of channels[%d] ch[%d]\n",
927 __func__, i, tx_slot[i]);
928 }
929 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700930 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
931 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800932 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
933 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
934 break;
935 default:
936 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
937 rc = -EINVAL;
938 break;
939 }
940 return rc;
941}
942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 .prepare = msm_dai_q6_prepare,
945 .trigger = msm_dai_q6_trigger,
946 .hw_params = msm_dai_q6_hw_params,
947 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400948 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800949 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950};
951
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700952static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
953 .prepare = msm_dai_q6_auxpcm_prepare,
954 .trigger = msm_dai_q6_auxpcm_trigger,
955 .hw_params = msm_dai_q6_auxpcm_hw_params,
956 .shutdown = msm_dai_q6_auxpcm_shutdown,
957};
958
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
960 .playback = {
961 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
962 SNDRV_PCM_RATE_16000,
963 .formats = SNDRV_PCM_FMTBIT_S16_LE,
964 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -0800965 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 .rate_min = 8000,
967 .rate_max = 48000,
968 },
969 .ops = &msm_dai_q6_ops,
970 .probe = msm_dai_q6_dai_probe,
971 .remove = msm_dai_q6_dai_remove,
972};
973
974static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
975 .capture = {
976 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
977 SNDRV_PCM_RATE_16000,
978 .formats = SNDRV_PCM_FMTBIT_S16_LE,
979 .channels_min = 1,
980 .channels_max = 2,
981 .rate_min = 8000,
982 .rate_max = 48000,
983 },
984 .ops = &msm_dai_q6_ops,
985 .probe = msm_dai_q6_dai_probe,
986 .remove = msm_dai_q6_dai_remove,
987};
988
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530989static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
990 .playback = {
991 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
992 SNDRV_PCM_RATE_16000,
993 .formats = SNDRV_PCM_FMTBIT_S16_LE,
994 .channels_min = 1,
995 .channels_max = 2,
996 .rate_min = 8000,
997 .rate_max = 48000,
998 },
999 .ops = &msm_dai_q6_ops,
1000 .probe = msm_dai_q6_dai_probe,
1001 .remove = msm_dai_q6_dai_remove,
1002};
1003
1004static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1005 .capture = {
1006 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1007 SNDRV_PCM_RATE_16000,
1008 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1009 .channels_min = 1,
Mingming Yin647e9ea2012-03-17 19:56:10 -07001010 .channels_max = 4,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301011 .rate_min = 8000,
1012 .rate_max = 48000,
1013 },
1014 .ops = &msm_dai_q6_ops,
1015 .probe = msm_dai_q6_dai_probe,
1016 .remove = msm_dai_q6_dai_remove,
1017};
1018
Helen Zeng0705a5f2011-10-14 15:29:52 -07001019static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1020 .playback = {
1021 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1022 SNDRV_PCM_RATE_16000,
1023 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1024 .channels_min = 1,
1025 .channels_max = 2,
1026 .rate_max = 48000,
1027 .rate_min = 8000,
1028 },
1029 .ops = &msm_dai_q6_ops,
1030 .probe = msm_dai_q6_dai_probe,
1031 .remove = msm_dai_q6_dai_remove,
1032};
1033
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1035 .playback = {
1036 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1037 SNDRV_PCM_RATE_16000,
1038 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1039 .channels_min = 1,
1040 .channels_max = 2,
1041 .rate_min = 8000,
1042 .rate_max = 48000,
1043 },
1044 .ops = &msm_dai_q6_ops,
1045 .probe = msm_dai_q6_dai_probe,
1046 .remove = msm_dai_q6_dai_remove,
1047};
1048
1049static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1050 .capture = {
1051 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1052 SNDRV_PCM_RATE_16000,
1053 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1054 .channels_min = 1,
1055 .channels_max = 2,
1056 .rate_min = 8000,
1057 .rate_max = 48000,
1058 },
1059 .ops = &msm_dai_q6_ops,
1060 .probe = msm_dai_q6_dai_probe,
1061 .remove = msm_dai_q6_dai_remove,
1062};
1063
Helen Zenge3d716a2011-10-14 16:32:16 -07001064static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1065 .capture = {
1066 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1067 SNDRV_PCM_RATE_16000,
1068 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1069 .channels_min = 1,
1070 .channels_max = 2,
1071 .rate_min = 8000,
1072 .rate_max = 48000,
1073 },
1074 .ops = &msm_dai_q6_ops,
1075 .probe = msm_dai_q6_dai_probe,
1076 .remove = msm_dai_q6_dai_remove,
1077};
1078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1080 .playback = {
1081 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1082 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1083 .channels_min = 1,
1084 .channels_max = 1,
1085 .rate_max = 16000,
1086 .rate_min = 8000,
1087 },
1088 .ops = &msm_dai_q6_ops,
1089 .probe = msm_dai_q6_dai_probe,
1090 .remove = msm_dai_q6_dai_remove,
1091};
1092
1093static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1094 .playback = {
1095 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1096 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1097 .channels_min = 1,
1098 .channels_max = 1,
1099 .rate_max = 16000,
1100 .rate_min = 8000,
1101 },
1102 .ops = &msm_dai_q6_ops,
1103 .probe = msm_dai_q6_dai_probe,
1104 .remove = msm_dai_q6_dai_remove,
1105};
1106
1107static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1108 .playback = {
1109 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1110 SNDRV_PCM_RATE_16000,
1111 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1112 .channels_min = 2,
1113 .channels_max = 2,
1114 .rate_max = 48000,
1115 .rate_min = 8000,
1116 },
1117 .ops = &msm_dai_q6_ops,
1118 .probe = msm_dai_q6_dai_probe,
1119 .remove = msm_dai_q6_dai_remove,
1120};
1121
1122static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1123 .playback = {
1124 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1125 SNDRV_PCM_RATE_16000,
1126 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1127 .channels_min = 2,
1128 .channels_max = 2,
1129 .rate_max = 48000,
1130 .rate_min = 8000,
1131 },
1132 .ops = &msm_dai_q6_ops,
1133 .probe = msm_dai_q6_dai_probe,
1134 .remove = msm_dai_q6_dai_remove,
1135};
1136
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001137static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1138 .playback = {
1139 .rates = SNDRV_PCM_RATE_8000,
1140 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1141 .channels_min = 1,
1142 .channels_max = 1,
1143 .rate_max = 8000,
1144 .rate_min = 8000,
1145 },
1146 .ops = &msm_dai_q6_auxpcm_ops,
1147 .probe = msm_dai_q6_dai_auxpcm_probe,
1148 .remove = msm_dai_q6_dai_auxpcm_remove,
1149};
1150
1151static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1152 .capture = {
1153 .rates = SNDRV_PCM_RATE_8000,
1154 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1155 .channels_min = 1,
1156 .channels_max = 1,
1157 .rate_max = 8000,
1158 .rate_min = 8000,
1159 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001160 .ops = &msm_dai_q6_auxpcm_ops,
1161 .probe = msm_dai_q6_dai_auxpcm_probe,
1162 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001163};
1164
Kuirong Wang274f21a2011-12-15 21:29:08 -08001165static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
1166 .playback = {
1167 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1168 SNDRV_PCM_RATE_16000,
1169 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1170 .channels_min = 1,
1171 .rate_min = 8000,
1172 .rate_max = 48000,
1173 },
1174 .ops = &msm_dai_q6_ops,
1175 .probe = msm_dai_q6_dai_mi2s_probe,
1176 .remove = msm_dai_q6_dai_probe,
1177};
1178
Neema Shetty3c9d2862012-03-11 01:25:32 -08001179static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1180 .playback = {
1181 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1182 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1183 .channels_min = 1,
1184 .channels_max = 1,
1185 .rate_min = 8000,
1186 .rate_max = 16000,
1187 },
1188 .ops = &msm_dai_q6_ops,
1189 .probe = msm_dai_q6_dai_probe,
1190 .remove = msm_dai_q6_dai_remove,
1191};
1192
1193static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1194 .capture = {
1195 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1196 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1197 .channels_min = 1,
1198 .channels_max = 1,
1199 .rate_min = 8000,
1200 .rate_max = 16000,
1201 },
1202 .ops = &msm_dai_q6_ops,
1203 .probe = msm_dai_q6_dai_probe,
1204 .remove = msm_dai_q6_dai_remove,
1205};
1206
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001207static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1208 .capture = {
1209 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1210 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1211 SNDRV_PCM_RATE_192000,
1212 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1213 .channels_min = 1,
1214 .channels_max = 4,
1215 .rate_min = 8000,
1216 .rate_max = 192000,
1217 },
1218 .ops = &msm_dai_q6_ops,
1219 .probe = msm_dai_q6_dai_probe,
1220 .remove = msm_dai_q6_dai_remove,
1221};
1222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223/* To do: change to register DAIs as batch */
1224static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1225{
1226 int rc = 0;
1227
1228 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1229
1230 switch (pdev->id) {
1231 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001232 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001233 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1234 break;
1235 case PRIMARY_I2S_TX:
1236 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1237 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001238 case PCM_RX:
1239 rc = snd_soc_register_dai(&pdev->dev,
1240 &msm_dai_q6_aux_pcm_rx_dai);
1241 break;
1242 case PCM_TX:
1243 rc = snd_soc_register_dai(&pdev->dev,
1244 &msm_dai_q6_aux_pcm_tx_dai);
1245 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -08001246 case MI2S_RX:
1247 rc = snd_soc_register_dai(&pdev->dev,
1248 &msm_dai_q6_mi2s_rx_dai);
1249 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001251 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252 rc = snd_soc_register_dai(&pdev->dev,
1253 &msm_dai_q6_slimbus_rx_dai);
1254 break;
1255 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001256 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 rc = snd_soc_register_dai(&pdev->dev,
1258 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001259 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001260 case SLIMBUS_1_RX:
1261 rc = snd_soc_register_dai(&pdev->dev,
1262 &msm_dai_q6_slimbus_1_rx_dai);
1263 break;
1264 case SLIMBUS_1_TX:
1265 rc = snd_soc_register_dai(&pdev->dev,
1266 &msm_dai_q6_slimbus_1_tx_dai);
1267 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001268 case SLIMBUS_2_TX:
1269 rc = snd_soc_register_dai(&pdev->dev,
1270 &msm_dai_q6_slimbus_2_tx_dai);
1271 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272 case INT_BT_SCO_RX:
1273 rc = snd_soc_register_dai(&pdev->dev,
1274 &msm_dai_q6_bt_sco_rx_dai);
1275 break;
1276 case INT_BT_SCO_TX:
1277 rc = snd_soc_register_dai(&pdev->dev,
1278 &msm_dai_q6_bt_sco_tx_dai);
1279 break;
1280 case INT_FM_RX:
1281 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1282 break;
1283 case INT_FM_TX:
1284 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1285 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301286 case RT_PROXY_DAI_001_RX:
1287 case RT_PROXY_DAI_002_RX:
1288 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1289 break;
1290 case RT_PROXY_DAI_001_TX:
1291 case RT_PROXY_DAI_002_TX:
1292 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1293 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001294 case VOICE_PLAYBACK_TX:
1295 rc = snd_soc_register_dai(&pdev->dev,
1296 &msm_dai_q6_voice_playback_tx_dai);
1297 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001298 case VOICE_RECORD_RX:
1299 case VOICE_RECORD_TX:
1300 rc = snd_soc_register_dai(&pdev->dev,
1301 &msm_dai_q6_incall_record_dai);
1302 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 default:
1304 rc = -ENODEV;
1305 break;
1306 }
1307 return rc;
1308}
1309
1310static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1311{
1312 snd_soc_unregister_dai(&pdev->dev);
1313 return 0;
1314}
1315
1316static struct platform_driver msm_dai_q6_driver = {
1317 .probe = msm_dai_q6_dev_probe,
1318 .remove = msm_dai_q6_dev_remove,
1319 .driver = {
1320 .name = "msm-dai-q6",
1321 .owner = THIS_MODULE,
1322 },
1323};
1324
1325static int __init msm_dai_q6_init(void)
1326{
1327 return platform_driver_register(&msm_dai_q6_driver);
1328}
1329module_init(msm_dai_q6_init);
1330
1331static void __exit msm_dai_q6_exit(void)
1332{
1333 platform_driver_unregister(&msm_dai_q6_driver);
1334}
1335module_exit(msm_dai_q6_exit);
1336
1337/* Module information */
1338MODULE_DESCRIPTION("MSM DSP DAI driver");
1339MODULE_LICENSE("GPL v2");