blob: 69d71851830328cf06fb54561fb22faf00b9bf47 [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),
Kuirong Wang623b50f2012-04-16 15:51:14 -070093 SOC_ENUM_EXT("MI2S TX Format", mi2s_config_enum[0],
94 msm_dai_q6_mi2s_format_get,
95 msm_dai_q6_mi2s_format_put),
Kuirong Wang875d1ec2012-04-02 19:56:25 -070096};
97
Kuirong Wang274f21a2011-12-15 21:29:08 -080098static u8 num_of_bits_set(u8 sd_line_mask)
99{
100 u8 num_bits_set = 0;
101
102 while (sd_line_mask) {
103 num_bits_set++;
104 sd_line_mask = sd_line_mask & (sd_line_mask - 1);
105 }
106 return num_bits_set;
107}
108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
110 struct snd_soc_dai *dai, int stream)
111{
112 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
113
114 dai_data->channels = params_channels(params);
115 switch (dai_data->channels) {
116 case 2:
117 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
118 break;
119 case 1:
120 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
121 break;
122 default:
123 return -EINVAL;
124 break;
125 }
126 dai_data->rate = params_rate(params);
127
128 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
129 dai_data->channels, dai_data->rate);
130
131 /* Q6 only supports 16 as now */
132 dai_data->port_config.mi2s.bitwidth = 16;
133 dai_data->port_config.mi2s.line = 1;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800134 return 0;
135}
136
137static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_hw_params *params,
138 struct snd_soc_dai *dai, int stream)
139{
140 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
141 struct msm_mi2s_data *mi2s_pdata =
142 (struct msm_mi2s_data *) dai->dev->platform_data;
143
144 dai_data->channels = params_channels(params);
145 if (num_of_bits_set(mi2s_pdata->sd_lines) == 1) {
146 switch (dai_data->channels) {
147 case 2:
148 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
149 break;
150 case 1:
151 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
152 break;
153 default:
154 pr_warn("greater than stereo has not been validated");
155 break;
156 }
157 }
Kuirong Wangc70819f2012-02-08 16:12:23 -0800158 dai_data->rate = params_rate(params);
Kuirong Wang274f21a2011-12-15 21:29:08 -0800159 /* Q6 only supports 16 as now */
160 dai_data->port_config.mi2s.bitwidth = 16;
Lei Zhou157c1842011-08-19 13:05:04 -0400161
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700162 pr_debug("%s: format = %d, channel = %d, line = %d\n",
163 __func__, dai_data->port_config.mi2s.format,
164 dai_data->port_config.mi2s.channel,
165 dai_data->port_config.mi2s.line);
Lei Zhou157c1842011-08-19 13:05:04 -0400166 return 0;
167}
168
Kuirong Wang274f21a2011-12-15 21:29:08 -0800169static int msm_dai_q6_mi2s_platform_data_validation(
170 struct snd_soc_dai *dai)
171{
172 u8 num_of_sd_lines;
173 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
174 struct msm_mi2s_data *mi2s_pdata =
175 (struct msm_mi2s_data *)dai->dev->platform_data;
176 struct snd_soc_dai_driver *dai_driver =
177 (struct snd_soc_dai_driver *)dai->driver;
178
179 num_of_sd_lines = num_of_bits_set(mi2s_pdata->sd_lines);
180
181 switch (num_of_sd_lines) {
182 case 1:
183 switch (mi2s_pdata->sd_lines) {
184 case MSM_MI2S_SD0:
185 dai_data->port_config.mi2s.line = AFE_I2S_SD0;
186 break;
187 case MSM_MI2S_SD1:
188 dai_data->port_config.mi2s.line = AFE_I2S_SD1;
189 break;
190 case MSM_MI2S_SD2:
191 dai_data->port_config.mi2s.line = AFE_I2S_SD2;
192 break;
193 case MSM_MI2S_SD3:
194 dai_data->port_config.mi2s.line = AFE_I2S_SD3;
195 break;
196 default:
197 pr_err("%s: invalid SD line\n",
198 __func__);
199 goto error_invalid_data;
200 }
201 break;
202 case 2:
203 switch (mi2s_pdata->sd_lines) {
204 case MSM_MI2S_SD0 | MSM_MI2S_SD1:
205 dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
206 break;
207 case MSM_MI2S_SD2 | MSM_MI2S_SD3:
208 dai_data->port_config.mi2s.line = AFE_I2S_QUAD23;
209 break;
210 default:
211 pr_err("%s: invalid SD line\n",
212 __func__);
213 goto error_invalid_data;
214 }
215 break;
216 case 3:
217 switch (mi2s_pdata->sd_lines) {
218 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2:
219 dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
220 break;
221 default:
222 pr_err("%s: invalid SD lines\n",
223 __func__);
224 goto error_invalid_data;
225 }
226 break;
227 case 4:
228 switch (mi2s_pdata->sd_lines) {
229 case MSM_MI2S_SD0 | MSM_MI2S_SD1 | MSM_MI2S_SD2 | MSM_MI2S_SD3:
230 dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
231 break;
232 default:
233 pr_err("%s: invalid SD lines\n",
234 __func__);
235 goto error_invalid_data;
236 }
237 break;
238 default:
239 pr_err("%s: invalid SD lines\n", __func__);
240 goto error_invalid_data;
241 }
242 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
243 dai_driver->playback.channels_max = num_of_sd_lines << 1;
Kuirong Wang623b50f2012-04-16 15:51:14 -0700244 else if (mi2s_pdata->capability == MSM_MI2S_CAP_TX)
245 dai_driver->capture.channels_max = num_of_sd_lines << 1;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800246 return 0;
247
248error_invalid_data:
249 return -EINVAL;
250}
251
Lei Zhou157c1842011-08-19 13:05:04 -0400252static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
253{
254 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
255
256 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
257 case SND_SOC_DAIFMT_CBS_CFS:
258 dai_data->port_config.mi2s.ws = 1; /* CPU is master */
259 break;
260 case SND_SOC_DAIFMT_CBM_CFM:
261 dai_data->port_config.mi2s.ws = 0; /* CPU is slave */
262 break;
263 default:
264 return -EINVAL;
265 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266
267 return 0;
268}
269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270
271static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
272 struct snd_soc_dai *dai, int stream)
273{
274 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275
276 dai_data->channels = params_channels(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700277 dai_data->rate = params_rate(params);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 /* Q6 only supports 16 as now */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800280 dai_data->port_config.slim_sch.bit_width = 16;
281 dai_data->port_config.slim_sch.data_format = 0;
282 dai_data->port_config.slim_sch.num_channels = dai_data->channels;
283 dai_data->port_config.slim_sch.reserved = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800285 dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
286 "num_channel %hu slave_ch_mapping[0] %hu\n"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700288 "slave_port_mapping[3] %hu\n sample_rate %d\n", __func__,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800289 dai_data->port_config.slim_sch.slimbus_dev_id,
290 dai_data->port_config.slim_sch.bit_width,
291 dai_data->port_config.slim_sch.data_format,
292 dai_data->port_config.slim_sch.num_channels,
293 dai_data->port_config.slim_sch.slave_ch_mapping[0],
294 dai_data->port_config.slim_sch.slave_ch_mapping[1],
295 dai_data->port_config.slim_sch.slave_ch_mapping[2],
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700296 dai_data->port_config.slim_sch.slave_ch_mapping[3],
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700297 dai_data->rate);
298
299 return 0;
300}
301
302static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
303 struct snd_soc_dai *dai, int stream)
304{
305 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
306
307 dai_data->channels = params_channels(params);
308 dai_data->rate = params_rate(params);
309
310 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
311 dai_data->channels, dai_data->rate);
312
313 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
314
315 return 0;
316}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700317static int msm_dai_q6_auxpcm_hw_params(
318 struct snd_pcm_substream *substream,
319 struct snd_pcm_hw_params *params,
320 struct snd_soc_dai *dai)
321{
322 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
323 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
324 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
325
326 if (params_channels(params) != 1) {
327 dev_err(dai->dev, "AUX PCM supports only mono stream\n");
328 return -EINVAL;
329 }
330 dai_data->channels = params_channels(params);
331
332 if (params_rate(params) != 8000) {
333 dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
334 return -EINVAL;
335 }
336 dai_data->rate = params_rate(params);
337 dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
338 dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
339 dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
340 dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
341 dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
342 dai_data->port_config.pcm.data = auxpcm_pdata->data;
343
344 return 0;
345}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530347static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
348 struct snd_soc_dai *dai)
349{
350 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
351
352 dai_data->rate = params_rate(params);
353 dai_data->port_config.rtproxy.num_ch =
354 params_channels(params);
355
356 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
357 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
358
359 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
360 dai_data->port_config.rtproxy.interleaved = 1;
Asish Bhattacharyab3568cf2012-03-15 07:05:46 +0530361 dai_data->port_config.rtproxy.frame_sz = params_period_bytes(params);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530362 dai_data->port_config.rtproxy.jitter =
363 dai_data->port_config.rtproxy.frame_sz/2;
364 dai_data->port_config.rtproxy.lw_mark = 0;
365 dai_data->port_config.rtproxy.hw_mark = 0;
366 dai_data->port_config.rtproxy.rsvd = 0;
367
368 return 0;
369}
370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371/* Current implementation assumes hw_param is called once
372 * This may not be the case but what to do when ADM and AFE
373 * port are already opened and parameter changes
374 */
375static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
376 struct snd_pcm_hw_params *params,
377 struct snd_soc_dai *dai)
378{
379 int rc = 0;
380
381 switch (dai->id) {
382 case PRIMARY_I2S_TX:
383 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800384 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
386 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800387 case MI2S_RX:
Kuirong Wang623b50f2012-04-16 15:51:14 -0700388 case MI2S_TX:
Kuirong Wang274f21a2011-12-15 21:29:08 -0800389 rc = msm_dai_q6_mi2s_hw_params(params, dai, substream->stream);
390 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800392 case SLIMBUS_1_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800394 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700395 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800396 case SLIMBUS_4_RX:
397 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700398 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
399 substream->stream);
400 break;
401 case INT_BT_SCO_RX:
402 case INT_BT_SCO_TX:
403 case INT_FM_RX:
404 case INT_FM_TX:
405 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
406 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530407 case RT_PROXY_DAI_001_TX:
408 case RT_PROXY_DAI_001_RX:
409 case RT_PROXY_DAI_002_TX:
410 case RT_PROXY_DAI_002_RX:
411 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
412 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700413 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700414 case VOICE_RECORD_RX:
415 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700416 rc = 0;
417 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418 default:
419 dev_err(dai->dev, "invalid AFE port ID\n");
420 rc = -EINVAL;
421 break;
422 }
423
424 return rc;
425}
426
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700427static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
428 struct snd_soc_dai *dai)
429{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700430 int rc = 0;
431
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800432 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700433
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800434 if (aux_pcm_count == 0) {
435 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
436 " return\n", __func__, dai->id);
437 mutex_unlock(&aux_pcm_mutex);
438 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700439 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800440
441 aux_pcm_count--;
442
443 if (aux_pcm_count > 0) {
444 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
445 __func__, dai->id, aux_pcm_count);
446 mutex_unlock(&aux_pcm_mutex);
447 return;
448 } else if (aux_pcm_count < 0) {
449 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
450 " aux_pcm_count = %d < 0\n",
451 __func__, dai->id, aux_pcm_count);
452 aux_pcm_count = 0;
453 mutex_unlock(&aux_pcm_mutex);
454 return;
455 }
456
457 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
458 dai->id, aux_pcm_count);
459
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530460 clk_disable_unprepare(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800461 rc = afe_close(PCM_RX); /* can block */
462 if (IS_ERR_VALUE(rc))
463 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
464
465 rc = afe_close(PCM_TX);
466 if (IS_ERR_VALUE(rc))
467 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
468
469 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700470}
471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
473 struct snd_soc_dai *dai)
474{
475 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530476 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700479 switch (dai->id) {
480 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700481 case VOICE_RECORD_TX:
482 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700483 pr_debug("%s, stop pseudo port:%d\n",
484 __func__, dai->id);
485 rc = afe_stop_pseudo_port(dai->id);
486 break;
487 default:
488 rc = afe_close(dai->id); /* can block */
489 break;
490 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 if (IS_ERR_VALUE(rc))
492 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530493 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
494 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
496 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700497}
498
499static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
500 struct snd_soc_dai *dai)
501{
502 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
503 int rc = 0;
504
505 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
506 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
507
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800508 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700509
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800510 if (aux_pcm_count == 2) {
511 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
512 " return.\n", __func__, dai->id);
513 mutex_unlock(&aux_pcm_mutex);
514 return 0;
515 } else if (aux_pcm_count > 2) {
516 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
517 " aux_pcm_count = %d > 2\n",
518 __func__, dai->id, aux_pcm_count);
519 mutex_unlock(&aux_pcm_mutex);
520 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700521 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800522
523 aux_pcm_count++;
524 if (aux_pcm_count == 2) {
525 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
526 " increment\n", __func__, dai->id, aux_pcm_count);
527 mutex_unlock(&aux_pcm_mutex);
528 return 0;
529 }
530
531 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
532 __func__, dai->id, aux_pcm_count);
533
534 rc = afe_q6_interface_prepare();
535 if (IS_ERR_VALUE(rc))
536 dev_err(dai->dev, "fail to open AFE APR\n");
537
538 /*
539 * For AUX PCM Interface the below sequence of clk
540 * settings and afe_open is a strict requirement.
541 *
542 * Also using afe_open instead of afe_port_start_nowait
543 * to make sure the port is open before deasserting the
544 * clock line. This is required because pcm register is
545 * not written before clock deassert. Hence the hw does
546 * not get updated with new setting if the below clock
547 * assert/deasset and afe_open sequence is not followed.
548 */
549
550 clk_reset(pcm_clk, CLK_RESET_ASSERT);
551
552 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
553
554 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
555
556 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
557 if (rc < 0) {
558 pr_err("%s: clk_set_rate failed\n", __func__);
559 return rc;
560 }
561
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530562 clk_prepare_enable(pcm_clk);
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800563 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
564
565 mutex_unlock(&aux_pcm_mutex);
566
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700567 return rc;
568}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569
570static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
571 struct snd_soc_dai *dai)
572{
573 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
574 int rc = 0;
575
Patrick Lai831561e2011-07-26 22:51:27 -0700576 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700577 /* PORT START should be set if prepare called in active state */
578 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700580 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583}
584
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700585static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
586 int cmd, struct snd_soc_dai *dai)
587{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700588 int rc = 0;
589
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800590 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
591 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700592
593 switch (cmd) {
594
595 case SNDRV_PCM_TRIGGER_START:
596 case SNDRV_PCM_TRIGGER_RESUME:
597 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
598 /* afe_open will be called from prepare */
599 return 0;
600
601 case SNDRV_PCM_TRIGGER_STOP:
602 case SNDRV_PCM_TRIGGER_SUSPEND:
603 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800604 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700605
606 default:
607 rc = -EINVAL;
608 }
609
610 return rc;
611
612}
613
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
615 struct snd_soc_dai *dai)
616{
617 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
618 int rc = 0;
619
620 /* Start/stop port without waiting for Q6 AFE response. Need to have
621 * native q6 AFE driver propagates AFE response in order to handle
622 * port start/stop command error properly if error does arise.
623 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530624 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
625 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626 switch (cmd) {
627 case SNDRV_PCM_TRIGGER_START:
628 case SNDRV_PCM_TRIGGER_RESUME:
629 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
630 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700631 switch (dai->id) {
632 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700633 case VOICE_RECORD_TX:
634 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700635 afe_pseudo_port_start_nowait(dai->id);
636 break;
637 default:
638 afe_port_start_nowait(dai->id,
639 &dai_data->port_config, dai_data->rate);
640 break;
641 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 set_bit(STATUS_PORT_STARTED,
643 dai_data->status_mask);
644 }
645 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 case SNDRV_PCM_TRIGGER_STOP:
647 case SNDRV_PCM_TRIGGER_SUSPEND:
648 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
649 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700650 switch (dai->id) {
651 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700652 case VOICE_RECORD_TX:
653 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700654 afe_pseudo_port_stop_nowait(dai->id);
655 break;
656 default:
657 afe_port_stop_nowait(dai->id);
658 break;
659 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660 clear_bit(STATUS_PORT_STARTED,
661 dai_data->status_mask);
662 }
663 break;
664
665 default:
666 rc = -EINVAL;
667 }
668
669 return rc;
670}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700671static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
672{
673 struct msm_dai_q6_dai_data *dai_data;
674 int rc = 0;
675
676 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
677 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
678
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800679 mutex_lock(&aux_pcm_mutex);
680
681 if (!auxpcm_plat_data)
682 auxpcm_plat_data = auxpcm_pdata;
683 else if (auxpcm_plat_data != auxpcm_pdata) {
684
685 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
686 " same platform data\n");
687 return -EINVAL;
688 }
689
690 /*
691 * The clk name for AUX PCM operation is passed as platform
692 * data to the cpu driver, since cpu drive is unaware of any
693 * boarc specific configuration.
694 */
695 if (!pcm_clk) {
696
697 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
698
699 if (IS_ERR(pcm_clk)) {
700 pr_err("%s: could not get pcm_clk\n", __func__);
701 pcm_clk = NULL;
702 return -ENODEV;
703 }
704 }
705
706 mutex_unlock(&aux_pcm_mutex);
707
708 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700709
710 if (!dai_data) {
711 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
712 dai->id);
713 rc = -ENOMEM;
714 } else
715 dev_set_drvdata(dai->dev, dai_data);
716
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800717 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700718 return rc;
719}
720
721static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
722{
723 struct msm_dai_q6_dai_data *dai_data;
724 int rc;
725
726 dai_data = dev_get_drvdata(dai->dev);
727
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800728 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700729
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800730 if (aux_pcm_count == 0) {
731 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
732 " up and return\n", __func__, dai->id);
733 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700734 }
735
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800736 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700737
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800738 if (aux_pcm_count > 0) {
739 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
740 __func__, dai->id, aux_pcm_count);
741 goto done;
742 } else if (aux_pcm_count < 0) {
743 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
744 " aux_pcm_count = %d < 0\n",
745 __func__, dai->id, aux_pcm_count);
746 goto done;
747 }
748
749 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
750 "closing afe\n",
751 __func__, dai->id, aux_pcm_count);
752
753 rc = afe_close(PCM_RX); /* can block */
754 if (IS_ERR_VALUE(rc))
755 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
756
757 rc = afe_close(PCM_TX);
758 if (IS_ERR_VALUE(rc))
759 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
760
761done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700762 kfree(dai_data);
763 snd_soc_unregister_dai(dai->dev);
764
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800765 mutex_unlock(&aux_pcm_mutex);
766
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700767 return 0;
768}
Kuirong Wang274f21a2011-12-15 21:29:08 -0800769static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
770{
771 struct msm_dai_q6_dai_data *dai_data;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700772 struct msm_mi2s_data *mi2s_pdata =
773 (struct msm_mi2s_data *)dai->dev->platform_data;
774 const struct snd_kcontrol_new *kcontrol;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800775 int rc = 0;
776
777 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
778 GFP_KERNEL);
779
780 if (!dai_data) {
781 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
782 dai->id);
783 rc = -ENOMEM;
784 goto rtn;
785 } else
786 dev_set_drvdata(dai->dev, dai_data);
787
788 rc = msm_dai_q6_mi2s_platform_data_validation(dai);
789 if (rc != 0) {
790 pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
791 __func__);
792 kfree(dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700793 goto rtn;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800794 }
Kuirong Wang623b50f2012-04-16 15:51:14 -0700795 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX)
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700796 kcontrol = &mi2s_config_controls[0];
Kuirong Wang623b50f2012-04-16 15:51:14 -0700797 else
798 kcontrol = &mi2s_config_controls[2];
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700799
Kuirong Wang623b50f2012-04-16 15:51:14 -0700800 rc = snd_ctl_add(dai->card->snd_card,
801 snd_ctl_new1(kcontrol, dai_data));
Kuirong Wang274f21a2011-12-15 21:29:08 -0800802rtn:
803 return rc;
804}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805
806static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
807{
808 struct msm_dai_q6_dai_data *dai_data;
809 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700810 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700811
812 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
813 GFP_KERNEL);
814
815 if (!dai_data) {
816 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
817 dai->id);
818 rc = -ENOMEM;
819 } else
820 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700821 if (dai->id == SECONDARY_I2S_RX) {
822 kcontrol = &mi2s_config_controls[1];
823 rc = snd_ctl_add(dai->card->snd_card,
824 snd_ctl_new1(kcontrol, dai_data));
825 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826
827 return rc;
828}
829
830static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
831{
832 struct msm_dai_q6_dai_data *dai_data;
833 int rc;
834
835 dai_data = dev_get_drvdata(dai->dev);
836
837 /* If AFE port is still up, close it */
838 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700839 switch (dai->id) {
840 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700841 case VOICE_RECORD_TX:
842 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700843 pr_debug("%s, stop pseudo port:%d\n",
844 __func__, dai->id);
845 rc = afe_stop_pseudo_port(dai->id);
846 break;
847 default:
848 rc = afe_close(dai->id); /* can block */
849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850 if (IS_ERR_VALUE(rc))
851 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530852 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853 }
854 kfree(dai_data);
855 snd_soc_unregister_dai(dai->dev);
856
857 return 0;
858}
859
Lei Zhou157c1842011-08-19 13:05:04 -0400860static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
861{
862 int rc = 0;
863
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800864 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
865 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -0400866 switch (dai->id) {
867 case PRIMARY_I2S_TX:
868 case PRIMARY_I2S_RX:
Kuirong Wang274f21a2011-12-15 21:29:08 -0800869 case MI2S_RX:
Kuirong Wang623b50f2012-04-16 15:51:14 -0700870 case MI2S_TX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800871 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -0400872 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
873 break;
874 default:
875 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
876 rc = -EINVAL;
877 break;
878 }
879
880 return rc;
881}
882
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800883static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
884 unsigned int tx_num, unsigned int *tx_slot,
885 unsigned int rx_num, unsigned int *rx_slot)
886
887{
888 int rc = 0;
889 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
890 unsigned int i = 0;
891
892 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
893 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800894 switch (dai->id) {
895 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800896 case SLIMBUS_1_RX:
Helen Zeng8f925502012-03-05 16:50:17 -0800897 case SLIMBUS_4_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800898 /* channel number to be between 128 and 255. For RX port
899 * use channel numbers from 138 to 144, for TX port
900 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800901 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800902 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800903 if (!rx_slot)
904 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800905 for (i = 0; i < rx_num; i++) {
906 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
907 rx_slot[i];
908 pr_debug("%s: find number of channels[%d] ch[%d]\n",
909 __func__, i,
910 rx_slot[i]);
911 }
912 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700913 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
914 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800915 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
916 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
917
918 break;
919 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800920 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700921 case SLIMBUS_2_TX:
Helen Zeng8f925502012-03-05 16:50:17 -0800922 case SLIMBUS_4_TX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800923 /* channel number to be between 128 and 255. For RX port
924 * use channel numbers from 138 to 144, for TX port
925 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800926 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800927 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800928 if (!tx_slot)
929 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800930 for (i = 0; i < tx_num; i++) {
931 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
932 tx_slot[i];
933 pr_debug("%s: find number of channels[%d] ch[%d]\n",
934 __func__, i, tx_slot[i]);
935 }
936 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700937 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
938 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800939 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
940 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
941 break;
942 default:
943 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
944 rc = -EINVAL;
945 break;
946 }
947 return rc;
948}
949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951 .prepare = msm_dai_q6_prepare,
952 .trigger = msm_dai_q6_trigger,
953 .hw_params = msm_dai_q6_hw_params,
954 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400955 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800956 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957};
958
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700959static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
960 .prepare = msm_dai_q6_auxpcm_prepare,
961 .trigger = msm_dai_q6_auxpcm_trigger,
962 .hw_params = msm_dai_q6_auxpcm_hw_params,
963 .shutdown = msm_dai_q6_auxpcm_shutdown,
964};
965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
967 .playback = {
968 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
969 SNDRV_PCM_RATE_16000,
970 .formats = SNDRV_PCM_FMTBIT_S16_LE,
971 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -0800972 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973 .rate_min = 8000,
974 .rate_max = 48000,
975 },
976 .ops = &msm_dai_q6_ops,
977 .probe = msm_dai_q6_dai_probe,
978 .remove = msm_dai_q6_dai_remove,
979};
980
981static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
982 .capture = {
983 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
984 SNDRV_PCM_RATE_16000,
985 .formats = SNDRV_PCM_FMTBIT_S16_LE,
986 .channels_min = 1,
987 .channels_max = 2,
988 .rate_min = 8000,
989 .rate_max = 48000,
990 },
991 .ops = &msm_dai_q6_ops,
992 .probe = msm_dai_q6_dai_probe,
993 .remove = msm_dai_q6_dai_remove,
994};
995
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530996static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
997 .playback = {
998 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
999 SNDRV_PCM_RATE_16000,
1000 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1001 .channels_min = 1,
1002 .channels_max = 2,
1003 .rate_min = 8000,
1004 .rate_max = 48000,
1005 },
1006 .ops = &msm_dai_q6_ops,
1007 .probe = msm_dai_q6_dai_probe,
1008 .remove = msm_dai_q6_dai_remove,
1009};
1010
1011static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1012 .capture = {
1013 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1014 SNDRV_PCM_RATE_16000,
1015 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1016 .channels_min = 1,
Mingming Yin647e9ea2012-03-17 19:56:10 -07001017 .channels_max = 4,
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301018 .rate_min = 8000,
1019 .rate_max = 48000,
1020 },
1021 .ops = &msm_dai_q6_ops,
1022 .probe = msm_dai_q6_dai_probe,
1023 .remove = msm_dai_q6_dai_remove,
1024};
1025
Helen Zeng0705a5f2011-10-14 15:29:52 -07001026static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1027 .playback = {
1028 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1029 SNDRV_PCM_RATE_16000,
1030 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1031 .channels_min = 1,
1032 .channels_max = 2,
1033 .rate_max = 48000,
1034 .rate_min = 8000,
1035 },
1036 .ops = &msm_dai_q6_ops,
1037 .probe = msm_dai_q6_dai_probe,
1038 .remove = msm_dai_q6_dai_remove,
1039};
1040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1042 .playback = {
1043 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1044 SNDRV_PCM_RATE_16000,
1045 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1046 .channels_min = 1,
1047 .channels_max = 2,
1048 .rate_min = 8000,
1049 .rate_max = 48000,
1050 },
1051 .ops = &msm_dai_q6_ops,
1052 .probe = msm_dai_q6_dai_probe,
1053 .remove = msm_dai_q6_dai_remove,
1054};
1055
1056static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1057 .capture = {
1058 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1059 SNDRV_PCM_RATE_16000,
1060 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1061 .channels_min = 1,
1062 .channels_max = 2,
1063 .rate_min = 8000,
1064 .rate_max = 48000,
1065 },
1066 .ops = &msm_dai_q6_ops,
1067 .probe = msm_dai_q6_dai_probe,
1068 .remove = msm_dai_q6_dai_remove,
1069};
1070
Helen Zenge3d716a2011-10-14 16:32:16 -07001071static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1072 .capture = {
1073 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1074 SNDRV_PCM_RATE_16000,
1075 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1076 .channels_min = 1,
1077 .channels_max = 2,
1078 .rate_min = 8000,
1079 .rate_max = 48000,
1080 },
1081 .ops = &msm_dai_q6_ops,
1082 .probe = msm_dai_q6_dai_probe,
1083 .remove = msm_dai_q6_dai_remove,
1084};
1085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1087 .playback = {
1088 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1089 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1090 .channels_min = 1,
1091 .channels_max = 1,
1092 .rate_max = 16000,
1093 .rate_min = 8000,
1094 },
1095 .ops = &msm_dai_q6_ops,
1096 .probe = msm_dai_q6_dai_probe,
1097 .remove = msm_dai_q6_dai_remove,
1098};
1099
1100static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1101 .playback = {
1102 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1103 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1104 .channels_min = 1,
1105 .channels_max = 1,
1106 .rate_max = 16000,
1107 .rate_min = 8000,
1108 },
1109 .ops = &msm_dai_q6_ops,
1110 .probe = msm_dai_q6_dai_probe,
1111 .remove = msm_dai_q6_dai_remove,
1112};
1113
1114static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1115 .playback = {
1116 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1117 SNDRV_PCM_RATE_16000,
1118 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1119 .channels_min = 2,
1120 .channels_max = 2,
1121 .rate_max = 48000,
1122 .rate_min = 8000,
1123 },
1124 .ops = &msm_dai_q6_ops,
1125 .probe = msm_dai_q6_dai_probe,
1126 .remove = msm_dai_q6_dai_remove,
1127};
1128
1129static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1130 .playback = {
1131 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1132 SNDRV_PCM_RATE_16000,
1133 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1134 .channels_min = 2,
1135 .channels_max = 2,
1136 .rate_max = 48000,
1137 .rate_min = 8000,
1138 },
1139 .ops = &msm_dai_q6_ops,
1140 .probe = msm_dai_q6_dai_probe,
1141 .remove = msm_dai_q6_dai_remove,
1142};
1143
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001144static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1145 .playback = {
1146 .rates = SNDRV_PCM_RATE_8000,
1147 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1148 .channels_min = 1,
1149 .channels_max = 1,
1150 .rate_max = 8000,
1151 .rate_min = 8000,
1152 },
1153 .ops = &msm_dai_q6_auxpcm_ops,
1154 .probe = msm_dai_q6_dai_auxpcm_probe,
1155 .remove = msm_dai_q6_dai_auxpcm_remove,
1156};
1157
1158static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1159 .capture = {
1160 .rates = SNDRV_PCM_RATE_8000,
1161 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1162 .channels_min = 1,
1163 .channels_max = 1,
1164 .rate_max = 8000,
1165 .rate_min = 8000,
1166 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001167 .ops = &msm_dai_q6_auxpcm_ops,
1168 .probe = msm_dai_q6_dai_auxpcm_probe,
1169 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001170};
1171
Kuirong Wang274f21a2011-12-15 21:29:08 -08001172static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
1173 .playback = {
1174 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1175 SNDRV_PCM_RATE_16000,
1176 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1177 .channels_min = 1,
1178 .rate_min = 8000,
1179 .rate_max = 48000,
1180 },
1181 .ops = &msm_dai_q6_ops,
1182 .probe = msm_dai_q6_dai_mi2s_probe,
1183 .remove = msm_dai_q6_dai_probe,
1184};
1185
Kuirong Wang623b50f2012-04-16 15:51:14 -07001186static struct snd_soc_dai_driver msm_dai_q6_mi2s_tx_dai = {
1187 .capture = {
1188 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1189 SNDRV_PCM_RATE_16000,
1190 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1191 .channels_min = 1,
1192 .rate_min = 8000,
1193 .rate_max = 48000,
1194 },
1195 .ops = &msm_dai_q6_ops,
1196 .probe = msm_dai_q6_dai_mi2s_probe,
1197 .remove = msm_dai_q6_dai_remove,
1198};
1199
Neema Shetty3c9d2862012-03-11 01:25:32 -08001200static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1201 .playback = {
1202 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1203 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1204 .channels_min = 1,
1205 .channels_max = 1,
1206 .rate_min = 8000,
1207 .rate_max = 16000,
1208 },
1209 .ops = &msm_dai_q6_ops,
1210 .probe = msm_dai_q6_dai_probe,
1211 .remove = msm_dai_q6_dai_remove,
1212};
1213
1214static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1215 .capture = {
1216 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1217 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1218 .channels_min = 1,
1219 .channels_max = 1,
1220 .rate_min = 8000,
1221 .rate_max = 16000,
1222 },
1223 .ops = &msm_dai_q6_ops,
1224 .probe = msm_dai_q6_dai_probe,
1225 .remove = msm_dai_q6_dai_remove,
1226};
1227
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001228static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1229 .capture = {
1230 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1231 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1232 SNDRV_PCM_RATE_192000,
1233 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1234 .channels_min = 1,
1235 .channels_max = 4,
1236 .rate_min = 8000,
1237 .rate_max = 192000,
1238 },
1239 .ops = &msm_dai_q6_ops,
1240 .probe = msm_dai_q6_dai_probe,
1241 .remove = msm_dai_q6_dai_remove,
1242};
1243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001244/* To do: change to register DAIs as batch */
1245static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1246{
1247 int rc = 0;
1248
1249 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1250
1251 switch (pdev->id) {
1252 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001253 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1255 break;
1256 case PRIMARY_I2S_TX:
1257 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1258 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001259 case PCM_RX:
1260 rc = snd_soc_register_dai(&pdev->dev,
1261 &msm_dai_q6_aux_pcm_rx_dai);
1262 break;
1263 case PCM_TX:
1264 rc = snd_soc_register_dai(&pdev->dev,
1265 &msm_dai_q6_aux_pcm_tx_dai);
1266 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -08001267 case MI2S_RX:
1268 rc = snd_soc_register_dai(&pdev->dev,
1269 &msm_dai_q6_mi2s_rx_dai);
1270 break;
Kuirong Wang623b50f2012-04-16 15:51:14 -07001271 case MI2S_TX:
1272 rc = snd_soc_register_dai(&pdev->dev,
1273 &msm_dai_q6_mi2s_tx_dai);
1274 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 case SLIMBUS_0_RX:
Helen Zeng8f925502012-03-05 16:50:17 -08001276 case SLIMBUS_4_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277 rc = snd_soc_register_dai(&pdev->dev,
1278 &msm_dai_q6_slimbus_rx_dai);
1279 break;
1280 case SLIMBUS_0_TX:
Helen Zeng8f925502012-03-05 16:50:17 -08001281 case SLIMBUS_4_TX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282 rc = snd_soc_register_dai(&pdev->dev,
1283 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001284 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001285 case SLIMBUS_1_RX:
1286 rc = snd_soc_register_dai(&pdev->dev,
1287 &msm_dai_q6_slimbus_1_rx_dai);
1288 break;
1289 case SLIMBUS_1_TX:
1290 rc = snd_soc_register_dai(&pdev->dev,
1291 &msm_dai_q6_slimbus_1_tx_dai);
1292 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001293 case SLIMBUS_2_TX:
1294 rc = snd_soc_register_dai(&pdev->dev,
1295 &msm_dai_q6_slimbus_2_tx_dai);
1296 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001297 case INT_BT_SCO_RX:
1298 rc = snd_soc_register_dai(&pdev->dev,
1299 &msm_dai_q6_bt_sco_rx_dai);
1300 break;
1301 case INT_BT_SCO_TX:
1302 rc = snd_soc_register_dai(&pdev->dev,
1303 &msm_dai_q6_bt_sco_tx_dai);
1304 break;
1305 case INT_FM_RX:
1306 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1307 break;
1308 case INT_FM_TX:
1309 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1310 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301311 case RT_PROXY_DAI_001_RX:
1312 case RT_PROXY_DAI_002_RX:
1313 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1314 break;
1315 case RT_PROXY_DAI_001_TX:
1316 case RT_PROXY_DAI_002_TX:
1317 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1318 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001319 case VOICE_PLAYBACK_TX:
1320 rc = snd_soc_register_dai(&pdev->dev,
1321 &msm_dai_q6_voice_playback_tx_dai);
1322 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001323 case VOICE_RECORD_RX:
1324 case VOICE_RECORD_TX:
1325 rc = snd_soc_register_dai(&pdev->dev,
1326 &msm_dai_q6_incall_record_dai);
1327 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328 default:
1329 rc = -ENODEV;
1330 break;
1331 }
1332 return rc;
1333}
1334
1335static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1336{
1337 snd_soc_unregister_dai(&pdev->dev);
1338 return 0;
1339}
1340
1341static struct platform_driver msm_dai_q6_driver = {
1342 .probe = msm_dai_q6_dev_probe,
1343 .remove = msm_dai_q6_dev_remove,
1344 .driver = {
1345 .name = "msm-dai-q6",
1346 .owner = THIS_MODULE,
1347 },
1348};
1349
1350static int __init msm_dai_q6_init(void)
1351{
1352 return platform_driver_register(&msm_dai_q6_driver);
1353}
1354module_init(msm_dai_q6_init);
1355
1356static void __exit msm_dai_q6_exit(void)
1357{
1358 platform_driver_unregister(&msm_dai_q6_driver);
1359}
1360module_exit(msm_dai_q6_exit);
1361
1362/* Module information */
1363MODULE_DESCRIPTION("MSM DSP DAI driver");
1364MODULE_LICENSE("GPL v2");