blob: e6d50126ec724ff5cfee17966842965a890116e9 [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:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
392 substream->stream);
393 break;
394 case INT_BT_SCO_RX:
395 case INT_BT_SCO_TX:
396 case INT_FM_RX:
397 case INT_FM_TX:
398 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
399 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530400 case RT_PROXY_DAI_001_TX:
401 case RT_PROXY_DAI_001_RX:
402 case RT_PROXY_DAI_002_TX:
403 case RT_PROXY_DAI_002_RX:
404 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
405 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700406 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700407 case VOICE_RECORD_RX:
408 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700409 rc = 0;
410 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 default:
412 dev_err(dai->dev, "invalid AFE port ID\n");
413 rc = -EINVAL;
414 break;
415 }
416
417 return rc;
418}
419
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700420static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
421 struct snd_soc_dai *dai)
422{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700423 int rc = 0;
424
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800425 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700426
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800427 if (aux_pcm_count == 0) {
428 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. Just"
429 " return\n", __func__, dai->id);
430 mutex_unlock(&aux_pcm_mutex);
431 return;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700432 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800433
434 aux_pcm_count--;
435
436 if (aux_pcm_count > 0) {
437 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
438 __func__, dai->id, aux_pcm_count);
439 mutex_unlock(&aux_pcm_mutex);
440 return;
441 } else if (aux_pcm_count < 0) {
442 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
443 " aux_pcm_count = %d < 0\n",
444 __func__, dai->id, aux_pcm_count);
445 aux_pcm_count = 0;
446 mutex_unlock(&aux_pcm_mutex);
447 return;
448 }
449
450 pr_debug("%s: dai->id = %d aux_pcm_count = %d\n", __func__,
451 dai->id, aux_pcm_count);
452
453 clk_disable(pcm_clk);
454 rc = afe_close(PCM_RX); /* can block */
455 if (IS_ERR_VALUE(rc))
456 dev_err(dai->dev, "fail to close PCM_RX AFE port\n");
457
458 rc = afe_close(PCM_TX);
459 if (IS_ERR_VALUE(rc))
460 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
461
462 mutex_unlock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700463}
464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
466 struct snd_soc_dai *dai)
467{
468 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530469 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700472 switch (dai->id) {
473 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700474 case VOICE_RECORD_TX:
475 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700476 pr_debug("%s, stop pseudo port:%d\n",
477 __func__, dai->id);
478 rc = afe_stop_pseudo_port(dai->id);
479 break;
480 default:
481 rc = afe_close(dai->id); /* can block */
482 break;
483 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484 if (IS_ERR_VALUE(rc))
485 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530486 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
487 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
489 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700490}
491
492static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
493 struct snd_soc_dai *dai)
494{
495 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
496 int rc = 0;
497
498 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
499 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
500
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800501 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700502
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800503 if (aux_pcm_count == 2) {
504 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 2. Just"
505 " return.\n", __func__, dai->id);
506 mutex_unlock(&aux_pcm_mutex);
507 return 0;
508 } else if (aux_pcm_count > 2) {
509 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
510 " aux_pcm_count = %d > 2\n",
511 __func__, dai->id, aux_pcm_count);
512 mutex_unlock(&aux_pcm_mutex);
513 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700514 }
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800515
516 aux_pcm_count++;
517 if (aux_pcm_count == 2) {
518 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d after "
519 " increment\n", __func__, dai->id, aux_pcm_count);
520 mutex_unlock(&aux_pcm_mutex);
521 return 0;
522 }
523
524 pr_debug("%s:dai->id:%d aux_pcm_count = %d. opening afe\n",
525 __func__, dai->id, aux_pcm_count);
526
527 rc = afe_q6_interface_prepare();
528 if (IS_ERR_VALUE(rc))
529 dev_err(dai->dev, "fail to open AFE APR\n");
530
531 /*
532 * For AUX PCM Interface the below sequence of clk
533 * settings and afe_open is a strict requirement.
534 *
535 * Also using afe_open instead of afe_port_start_nowait
536 * to make sure the port is open before deasserting the
537 * clock line. This is required because pcm register is
538 * not written before clock deassert. Hence the hw does
539 * not get updated with new setting if the below clock
540 * assert/deasset and afe_open sequence is not followed.
541 */
542
543 clk_reset(pcm_clk, CLK_RESET_ASSERT);
544
545 afe_open(PCM_RX, &dai_data->port_config, dai_data->rate);
546
547 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
548
549 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
550 if (rc < 0) {
551 pr_err("%s: clk_set_rate failed\n", __func__);
552 return rc;
553 }
554
555 clk_enable(pcm_clk);
556 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
557
558 mutex_unlock(&aux_pcm_mutex);
559
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700560 return rc;
561}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562
563static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
564 struct snd_soc_dai *dai)
565{
566 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
567 int rc = 0;
568
Patrick Lai831561e2011-07-26 22:51:27 -0700569 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700570 /* PORT START should be set if prepare called in active state */
571 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700573 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700576}
577
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700578static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
579 int cmd, struct snd_soc_dai *dai)
580{
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700581 int rc = 0;
582
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800583 pr_debug("%s:port:%d cmd:%d aux_pcm_count= %d",
584 __func__, dai->id, cmd, aux_pcm_count);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700585
586 switch (cmd) {
587
588 case SNDRV_PCM_TRIGGER_START:
589 case SNDRV_PCM_TRIGGER_RESUME:
590 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
591 /* afe_open will be called from prepare */
592 return 0;
593
594 case SNDRV_PCM_TRIGGER_STOP:
595 case SNDRV_PCM_TRIGGER_SUSPEND:
596 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800597 return 0;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700598
599 default:
600 rc = -EINVAL;
601 }
602
603 return rc;
604
605}
606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
608 struct snd_soc_dai *dai)
609{
610 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
611 int rc = 0;
612
613 /* Start/stop port without waiting for Q6 AFE response. Need to have
614 * native q6 AFE driver propagates AFE response in order to handle
615 * port start/stop command error properly if error does arise.
616 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530617 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
618 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 switch (cmd) {
620 case SNDRV_PCM_TRIGGER_START:
621 case SNDRV_PCM_TRIGGER_RESUME:
622 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
623 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700624 switch (dai->id) {
625 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700626 case VOICE_RECORD_TX:
627 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700628 afe_pseudo_port_start_nowait(dai->id);
629 break;
630 default:
631 afe_port_start_nowait(dai->id,
632 &dai_data->port_config, dai_data->rate);
633 break;
634 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635 set_bit(STATUS_PORT_STARTED,
636 dai_data->status_mask);
637 }
638 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 case SNDRV_PCM_TRIGGER_STOP:
640 case SNDRV_PCM_TRIGGER_SUSPEND:
641 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
642 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700643 switch (dai->id) {
644 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700645 case VOICE_RECORD_TX:
646 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700647 afe_pseudo_port_stop_nowait(dai->id);
648 break;
649 default:
650 afe_port_stop_nowait(dai->id);
651 break;
652 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653 clear_bit(STATUS_PORT_STARTED,
654 dai_data->status_mask);
655 }
656 break;
657
658 default:
659 rc = -EINVAL;
660 }
661
662 return rc;
663}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700664static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
665{
666 struct msm_dai_q6_dai_data *dai_data;
667 int rc = 0;
668
669 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
670 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
671
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800672 mutex_lock(&aux_pcm_mutex);
673
674 if (!auxpcm_plat_data)
675 auxpcm_plat_data = auxpcm_pdata;
676 else if (auxpcm_plat_data != auxpcm_pdata) {
677
678 dev_err(dai->dev, "AUX PCM RX and TX devices does not have"
679 " same platform data\n");
680 return -EINVAL;
681 }
682
683 /*
684 * The clk name for AUX PCM operation is passed as platform
685 * data to the cpu driver, since cpu drive is unaware of any
686 * boarc specific configuration.
687 */
688 if (!pcm_clk) {
689
690 pcm_clk = clk_get(dai->dev, auxpcm_pdata->clk);
691
692 if (IS_ERR(pcm_clk)) {
693 pr_err("%s: could not get pcm_clk\n", __func__);
694 pcm_clk = NULL;
695 return -ENODEV;
696 }
697 }
698
699 mutex_unlock(&aux_pcm_mutex);
700
701 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data), GFP_KERNEL);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700702
703 if (!dai_data) {
704 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
705 dai->id);
706 rc = -ENOMEM;
707 } else
708 dev_set_drvdata(dai->dev, dai_data);
709
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800710 pr_debug("%s : probe done for dai->id %d\n", __func__, dai->id);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700711 return rc;
712}
713
714static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
715{
716 struct msm_dai_q6_dai_data *dai_data;
717 int rc;
718
719 dai_data = dev_get_drvdata(dai->dev);
720
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800721 mutex_lock(&aux_pcm_mutex);
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700722
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800723 if (aux_pcm_count == 0) {
724 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count is 0. clean"
725 " up and return\n", __func__, dai->id);
726 goto done;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700727 }
728
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800729 aux_pcm_count--;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700730
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800731 if (aux_pcm_count > 0) {
732 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d\n",
733 __func__, dai->id, aux_pcm_count);
734 goto done;
735 } else if (aux_pcm_count < 0) {
736 dev_err(dai->dev, "%s(): ERROR: dai->id %d"
737 " aux_pcm_count = %d < 0\n",
738 __func__, dai->id, aux_pcm_count);
739 goto done;
740 }
741
742 dev_dbg(dai->dev, "%s(): dai->id %d aux_pcm_count = %d."
743 "closing afe\n",
744 __func__, dai->id, aux_pcm_count);
745
746 rc = afe_close(PCM_RX); /* can block */
747 if (IS_ERR_VALUE(rc))
748 dev_err(dai->dev, "fail to close AUX PCM RX AFE port\n");
749
750 rc = afe_close(PCM_TX);
751 if (IS_ERR_VALUE(rc))
752 dev_err(dai->dev, "fail to close AUX PCM TX AFE port\n");
753
754done:
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700755 kfree(dai_data);
756 snd_soc_unregister_dai(dai->dev);
757
Kiran Kandi5f4ab692012-02-23 11:23:56 -0800758 mutex_unlock(&aux_pcm_mutex);
759
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700760 return 0;
761}
Kuirong Wang274f21a2011-12-15 21:29:08 -0800762static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
763{
764 struct msm_dai_q6_dai_data *dai_data;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700765 struct msm_mi2s_data *mi2s_pdata =
766 (struct msm_mi2s_data *)dai->dev->platform_data;
767 const struct snd_kcontrol_new *kcontrol;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800768 int rc = 0;
769
770 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
771 GFP_KERNEL);
772
773 if (!dai_data) {
774 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
775 dai->id);
776 rc = -ENOMEM;
777 goto rtn;
778 } else
779 dev_set_drvdata(dai->dev, dai_data);
780
781 rc = msm_dai_q6_mi2s_platform_data_validation(dai);
782 if (rc != 0) {
783 pr_err("%s: The msm_dai_q6_mi2s_platform_data_validation failed\n",
784 __func__);
785 kfree(dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700786 goto rtn;
Kuirong Wang274f21a2011-12-15 21:29:08 -0800787 }
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700788 if (mi2s_pdata->capability == MSM_MI2S_CAP_RX) {
789 kcontrol = &mi2s_config_controls[0];
790 rc = snd_ctl_add(dai->card->snd_card,
791 snd_ctl_new1(kcontrol, dai_data));
792 }
793
Kuirong Wang274f21a2011-12-15 21:29:08 -0800794rtn:
795 return rc;
796}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700797
798static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
799{
800 struct msm_dai_q6_dai_data *dai_data;
801 int rc = 0;
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700802 const struct snd_kcontrol_new *kcontrol;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700803
804 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
805 GFP_KERNEL);
806
807 if (!dai_data) {
808 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
809 dai->id);
810 rc = -ENOMEM;
811 } else
812 dev_set_drvdata(dai->dev, dai_data);
Kuirong Wang875d1ec2012-04-02 19:56:25 -0700813 if (dai->id == SECONDARY_I2S_RX) {
814 kcontrol = &mi2s_config_controls[1];
815 rc = snd_ctl_add(dai->card->snd_card,
816 snd_ctl_new1(kcontrol, dai_data));
817 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818
819 return rc;
820}
821
822static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
823{
824 struct msm_dai_q6_dai_data *dai_data;
825 int rc;
826
827 dai_data = dev_get_drvdata(dai->dev);
828
829 /* If AFE port is still up, close it */
830 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700831 switch (dai->id) {
832 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700833 case VOICE_RECORD_TX:
834 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700835 pr_debug("%s, stop pseudo port:%d\n",
836 __func__, dai->id);
837 rc = afe_stop_pseudo_port(dai->id);
838 break;
839 default:
840 rc = afe_close(dai->id); /* can block */
841 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700842 if (IS_ERR_VALUE(rc))
843 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530844 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700845 }
846 kfree(dai_data);
847 snd_soc_unregister_dai(dai->dev);
848
849 return 0;
850}
851
Lei Zhou157c1842011-08-19 13:05:04 -0400852static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
853{
854 int rc = 0;
855
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800856 dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
857 dai->id, fmt);
Lei Zhou157c1842011-08-19 13:05:04 -0400858 switch (dai->id) {
859 case PRIMARY_I2S_TX:
860 case PRIMARY_I2S_RX:
Kuirong Wang274f21a2011-12-15 21:29:08 -0800861 case MI2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -0800862 case SECONDARY_I2S_RX:
Lei Zhou157c1842011-08-19 13:05:04 -0400863 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
864 break;
865 default:
866 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
867 rc = -EINVAL;
868 break;
869 }
870
871 return rc;
872}
873
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800874static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
875 unsigned int tx_num, unsigned int *tx_slot,
876 unsigned int rx_num, unsigned int *rx_slot)
877
878{
879 int rc = 0;
880 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
881 unsigned int i = 0;
882
883 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
884 dai->id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800885 switch (dai->id) {
886 case SLIMBUS_0_RX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800887 case SLIMBUS_1_RX:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800888 /* channel number to be between 128 and 255. For RX port
889 * use channel numbers from 138 to 144, for TX port
890 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800891 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800892 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800893 if (!rx_slot)
894 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800895 for (i = 0; i < rx_num; i++) {
896 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
897 rx_slot[i];
898 pr_debug("%s: find number of channels[%d] ch[%d]\n",
899 __func__, i,
900 rx_slot[i]);
901 }
902 dai_data->port_config.slim_sch.num_channels = rx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700903 pr_debug("%s:SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__,
904 (dai->id - SLIMBUS_0_RX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800905 rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
906 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
907
908 break;
909 case SLIMBUS_0_TX:
Neema Shetty3c9d2862012-03-11 01:25:32 -0800910 case SLIMBUS_1_TX:
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700911 case SLIMBUS_2_TX:
912
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800913 /* channel number to be between 128 and 255. For RX port
914 * use channel numbers from 138 to 144, for TX port
915 * use channel numbers from 128 to 137
Neema Shetty3c9d2862012-03-11 01:25:32 -0800916 * For ports between MDM-APQ use channel numbers from 145
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800917 */
Bharath Ramachandramurthy94ad7e22012-02-28 18:44:07 -0800918 if (!tx_slot)
919 return -EINVAL;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800920 for (i = 0; i < tx_num; i++) {
921 dai_data->port_config.slim_sch.slave_ch_mapping[i] =
922 tx_slot[i];
923 pr_debug("%s: find number of channels[%d] ch[%d]\n",
924 __func__, i, tx_slot[i]);
925 }
926 dai_data->port_config.slim_sch.num_channels = tx_num;
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700927 pr_debug("%s:SLIMBUS_%d_TX cnt[%d] ch[%d %d]\n", __func__,
928 (dai->id - SLIMBUS_0_TX) / 2,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800929 tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
930 dai_data->port_config.slim_sch.slave_ch_mapping[1]);
931 break;
932 default:
933 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
934 rc = -EINVAL;
935 break;
936 }
937 return rc;
938}
939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 .prepare = msm_dai_q6_prepare,
942 .trigger = msm_dai_q6_trigger,
943 .hw_params = msm_dai_q6_hw_params,
944 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400945 .set_fmt = msm_dai_q6_set_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800946 .set_channel_map = msm_dai_q6_set_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947};
948
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700949static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
950 .prepare = msm_dai_q6_auxpcm_prepare,
951 .trigger = msm_dai_q6_auxpcm_trigger,
952 .hw_params = msm_dai_q6_auxpcm_hw_params,
953 .shutdown = msm_dai_q6_auxpcm_shutdown,
954};
955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
957 .playback = {
958 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
959 SNDRV_PCM_RATE_16000,
960 .formats = SNDRV_PCM_FMTBIT_S16_LE,
961 .channels_min = 1,
Kiran Kandi9db678b2012-01-15 14:25:59 -0800962 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700963 .rate_min = 8000,
964 .rate_max = 48000,
965 },
966 .ops = &msm_dai_q6_ops,
967 .probe = msm_dai_q6_dai_probe,
968 .remove = msm_dai_q6_dai_remove,
969};
970
971static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
972 .capture = {
973 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
974 SNDRV_PCM_RATE_16000,
975 .formats = SNDRV_PCM_FMTBIT_S16_LE,
976 .channels_min = 1,
977 .channels_max = 2,
978 .rate_min = 8000,
979 .rate_max = 48000,
980 },
981 .ops = &msm_dai_q6_ops,
982 .probe = msm_dai_q6_dai_probe,
983 .remove = msm_dai_q6_dai_remove,
984};
985
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530986static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
987 .playback = {
988 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
989 SNDRV_PCM_RATE_16000,
990 .formats = SNDRV_PCM_FMTBIT_S16_LE,
991 .channels_min = 1,
992 .channels_max = 2,
993 .rate_min = 8000,
994 .rate_max = 48000,
995 },
996 .ops = &msm_dai_q6_ops,
997 .probe = msm_dai_q6_dai_probe,
998 .remove = msm_dai_q6_dai_remove,
999};
1000
1001static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
1002 .capture = {
1003 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1004 SNDRV_PCM_RATE_16000,
1005 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1006 .channels_min = 1,
1007 .channels_max = 2,
1008 .rate_min = 8000,
1009 .rate_max = 48000,
1010 },
1011 .ops = &msm_dai_q6_ops,
1012 .probe = msm_dai_q6_dai_probe,
1013 .remove = msm_dai_q6_dai_remove,
1014};
1015
Helen Zeng0705a5f2011-10-14 15:29:52 -07001016static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
1017 .playback = {
1018 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1019 SNDRV_PCM_RATE_16000,
1020 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1021 .channels_min = 1,
1022 .channels_max = 2,
1023 .rate_max = 48000,
1024 .rate_min = 8000,
1025 },
1026 .ops = &msm_dai_q6_ops,
1027 .probe = msm_dai_q6_dai_probe,
1028 .remove = msm_dai_q6_dai_remove,
1029};
1030
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
1032 .playback = {
1033 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1034 SNDRV_PCM_RATE_16000,
1035 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1036 .channels_min = 1,
1037 .channels_max = 2,
1038 .rate_min = 8000,
1039 .rate_max = 48000,
1040 },
1041 .ops = &msm_dai_q6_ops,
1042 .probe = msm_dai_q6_dai_probe,
1043 .remove = msm_dai_q6_dai_remove,
1044};
1045
1046static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
1047 .capture = {
1048 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1049 SNDRV_PCM_RATE_16000,
1050 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1051 .channels_min = 1,
1052 .channels_max = 2,
1053 .rate_min = 8000,
1054 .rate_max = 48000,
1055 },
1056 .ops = &msm_dai_q6_ops,
1057 .probe = msm_dai_q6_dai_probe,
1058 .remove = msm_dai_q6_dai_remove,
1059};
1060
Helen Zenge3d716a2011-10-14 16:32:16 -07001061static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
1062 .capture = {
1063 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1064 SNDRV_PCM_RATE_16000,
1065 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1066 .channels_min = 1,
1067 .channels_max = 2,
1068 .rate_min = 8000,
1069 .rate_max = 48000,
1070 },
1071 .ops = &msm_dai_q6_ops,
1072 .probe = msm_dai_q6_dai_probe,
1073 .remove = msm_dai_q6_dai_remove,
1074};
1075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
1077 .playback = {
1078 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1079 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1080 .channels_min = 1,
1081 .channels_max = 1,
1082 .rate_max = 16000,
1083 .rate_min = 8000,
1084 },
1085 .ops = &msm_dai_q6_ops,
1086 .probe = msm_dai_q6_dai_probe,
1087 .remove = msm_dai_q6_dai_remove,
1088};
1089
1090static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
1091 .playback = {
1092 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1093 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1094 .channels_min = 1,
1095 .channels_max = 1,
1096 .rate_max = 16000,
1097 .rate_min = 8000,
1098 },
1099 .ops = &msm_dai_q6_ops,
1100 .probe = msm_dai_q6_dai_probe,
1101 .remove = msm_dai_q6_dai_remove,
1102};
1103
1104static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
1105 .playback = {
1106 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1107 SNDRV_PCM_RATE_16000,
1108 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1109 .channels_min = 2,
1110 .channels_max = 2,
1111 .rate_max = 48000,
1112 .rate_min = 8000,
1113 },
1114 .ops = &msm_dai_q6_ops,
1115 .probe = msm_dai_q6_dai_probe,
1116 .remove = msm_dai_q6_dai_remove,
1117};
1118
1119static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
1120 .playback = {
1121 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1122 SNDRV_PCM_RATE_16000,
1123 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1124 .channels_min = 2,
1125 .channels_max = 2,
1126 .rate_max = 48000,
1127 .rate_min = 8000,
1128 },
1129 .ops = &msm_dai_q6_ops,
1130 .probe = msm_dai_q6_dai_probe,
1131 .remove = msm_dai_q6_dai_remove,
1132};
1133
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001134static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
1135 .playback = {
1136 .rates = SNDRV_PCM_RATE_8000,
1137 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1138 .channels_min = 1,
1139 .channels_max = 1,
1140 .rate_max = 8000,
1141 .rate_min = 8000,
1142 },
1143 .ops = &msm_dai_q6_auxpcm_ops,
1144 .probe = msm_dai_q6_dai_auxpcm_probe,
1145 .remove = msm_dai_q6_dai_auxpcm_remove,
1146};
1147
1148static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
1149 .capture = {
1150 .rates = SNDRV_PCM_RATE_8000,
1151 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1152 .channels_min = 1,
1153 .channels_max = 1,
1154 .rate_max = 8000,
1155 .rate_min = 8000,
1156 },
Kiran Kandi5f4ab692012-02-23 11:23:56 -08001157 .ops = &msm_dai_q6_auxpcm_ops,
1158 .probe = msm_dai_q6_dai_auxpcm_probe,
1159 .remove = msm_dai_q6_dai_auxpcm_remove,
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001160};
1161
Kuirong Wang274f21a2011-12-15 21:29:08 -08001162static struct snd_soc_dai_driver msm_dai_q6_mi2s_rx_dai = {
1163 .playback = {
1164 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1165 SNDRV_PCM_RATE_16000,
1166 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1167 .channels_min = 1,
1168 .rate_min = 8000,
1169 .rate_max = 48000,
1170 },
1171 .ops = &msm_dai_q6_ops,
1172 .probe = msm_dai_q6_dai_mi2s_probe,
1173 .remove = msm_dai_q6_dai_probe,
1174};
1175
Neema Shetty3c9d2862012-03-11 01:25:32 -08001176static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_rx_dai = {
1177 .playback = {
1178 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1179 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1180 .channels_min = 1,
1181 .channels_max = 1,
1182 .rate_min = 8000,
1183 .rate_max = 16000,
1184 },
1185 .ops = &msm_dai_q6_ops,
1186 .probe = msm_dai_q6_dai_probe,
1187 .remove = msm_dai_q6_dai_remove,
1188};
1189
1190static struct snd_soc_dai_driver msm_dai_q6_slimbus_1_tx_dai = {
1191 .capture = {
1192 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1193 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1194 .channels_min = 1,
1195 .channels_max = 1,
1196 .rate_min = 8000,
1197 .rate_max = 16000,
1198 },
1199 .ops = &msm_dai_q6_ops,
1200 .probe = msm_dai_q6_dai_probe,
1201 .remove = msm_dai_q6_dai_remove,
1202};
1203
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001204static struct snd_soc_dai_driver msm_dai_q6_slimbus_2_tx_dai = {
1205 .capture = {
1206 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
1207 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 |
1208 SNDRV_PCM_RATE_192000,
1209 .formats = SNDRV_PCM_FMTBIT_S16_LE,
1210 .channels_min = 1,
1211 .channels_max = 4,
1212 .rate_min = 8000,
1213 .rate_max = 192000,
1214 },
1215 .ops = &msm_dai_q6_ops,
1216 .probe = msm_dai_q6_dai_probe,
1217 .remove = msm_dai_q6_dai_remove,
1218};
1219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220/* To do: change to register DAIs as batch */
1221static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
1222{
1223 int rc = 0;
1224
1225 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
1226
1227 switch (pdev->id) {
1228 case PRIMARY_I2S_RX:
Kuirong Wang9bbf6132012-01-10 18:28:49 -08001229 case SECONDARY_I2S_RX:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
1231 break;
1232 case PRIMARY_I2S_TX:
1233 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
1234 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -07001235 case PCM_RX:
1236 rc = snd_soc_register_dai(&pdev->dev,
1237 &msm_dai_q6_aux_pcm_rx_dai);
1238 break;
1239 case PCM_TX:
1240 rc = snd_soc_register_dai(&pdev->dev,
1241 &msm_dai_q6_aux_pcm_tx_dai);
1242 break;
Kuirong Wang274f21a2011-12-15 21:29:08 -08001243 case MI2S_RX:
1244 rc = snd_soc_register_dai(&pdev->dev,
1245 &msm_dai_q6_mi2s_rx_dai);
1246 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247 case SLIMBUS_0_RX:
1248 rc = snd_soc_register_dai(&pdev->dev,
1249 &msm_dai_q6_slimbus_rx_dai);
1250 break;
1251 case SLIMBUS_0_TX:
1252 rc = snd_soc_register_dai(&pdev->dev,
1253 &msm_dai_q6_slimbus_tx_dai);
Neema Shetty3c9d2862012-03-11 01:25:32 -08001254 break;
Neema Shetty3c9d2862012-03-11 01:25:32 -08001255 case SLIMBUS_1_RX:
1256 rc = snd_soc_register_dai(&pdev->dev,
1257 &msm_dai_q6_slimbus_1_rx_dai);
1258 break;
1259 case SLIMBUS_1_TX:
1260 rc = snd_soc_register_dai(&pdev->dev,
1261 &msm_dai_q6_slimbus_1_tx_dai);
1262 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001263 case SLIMBUS_2_TX:
1264 rc = snd_soc_register_dai(&pdev->dev,
1265 &msm_dai_q6_slimbus_2_tx_dai);
1266 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 case INT_BT_SCO_RX:
1268 rc = snd_soc_register_dai(&pdev->dev,
1269 &msm_dai_q6_bt_sco_rx_dai);
1270 break;
1271 case INT_BT_SCO_TX:
1272 rc = snd_soc_register_dai(&pdev->dev,
1273 &msm_dai_q6_bt_sco_tx_dai);
1274 break;
1275 case INT_FM_RX:
1276 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
1277 break;
1278 case INT_FM_TX:
1279 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
1280 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +05301281 case RT_PROXY_DAI_001_RX:
1282 case RT_PROXY_DAI_002_RX:
1283 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
1284 break;
1285 case RT_PROXY_DAI_001_TX:
1286 case RT_PROXY_DAI_002_TX:
1287 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
1288 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -07001289 case VOICE_PLAYBACK_TX:
1290 rc = snd_soc_register_dai(&pdev->dev,
1291 &msm_dai_q6_voice_playback_tx_dai);
1292 break;
Helen Zenge3d716a2011-10-14 16:32:16 -07001293 case VOICE_RECORD_RX:
1294 case VOICE_RECORD_TX:
1295 rc = snd_soc_register_dai(&pdev->dev,
1296 &msm_dai_q6_incall_record_dai);
1297 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 default:
1299 rc = -ENODEV;
1300 break;
1301 }
1302 return rc;
1303}
1304
1305static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
1306{
1307 snd_soc_unregister_dai(&pdev->dev);
1308 return 0;
1309}
1310
1311static struct platform_driver msm_dai_q6_driver = {
1312 .probe = msm_dai_q6_dev_probe,
1313 .remove = msm_dai_q6_dev_remove,
1314 .driver = {
1315 .name = "msm-dai-q6",
1316 .owner = THIS_MODULE,
1317 },
1318};
1319
1320static int __init msm_dai_q6_init(void)
1321{
1322 return platform_driver_register(&msm_dai_q6_driver);
1323}
1324module_init(msm_dai_q6_init);
1325
1326static void __exit msm_dai_q6_exit(void)
1327{
1328 platform_driver_unregister(&msm_dai_q6_driver);
1329}
1330module_exit(msm_dai_q6_exit);
1331
1332/* Module information */
1333MODULE_DESCRIPTION("MSM DSP DAI driver");
1334MODULE_LICENSE("GPL v2");