blob: 4af4f06f8fee491bb79df3798816c25876b30f38 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
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>
17#include <linux/mfd/wcd9310/core.h>
18#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>
26#include <sound/q6adm.h>
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -070027#include <sound/msm-dai-q6.h>
28#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;
43
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
45 struct snd_soc_dai *dai, int stream)
46{
47 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
48
49 dai_data->channels = params_channels(params);
50 switch (dai_data->channels) {
51 case 2:
52 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
53 break;
54 case 1:
55 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
56 break;
57 default:
58 return -EINVAL;
59 break;
60 }
61 dai_data->rate = params_rate(params);
62
63 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
64 dai_data->channels, dai_data->rate);
65
66 /* Q6 only supports 16 as now */
67 dai_data->port_config.mi2s.bitwidth = 16;
68 dai_data->port_config.mi2s.line = 1;
Lei Zhou157c1842011-08-19 13:05:04 -040069
70 return 0;
71}
72
73static int msm_dai_q6_cdc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
74{
75 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
76
77 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
78 case SND_SOC_DAIFMT_CBS_CFS:
79 dai_data->port_config.mi2s.ws = 1; /* CPU is master */
80 break;
81 case SND_SOC_DAIFMT_CBM_CFM:
82 dai_data->port_config.mi2s.ws = 0; /* CPU is slave */
83 break;
84 default:
85 return -EINVAL;
86 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087
88 return 0;
89}
90
91static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_hw_params *params,
92 struct snd_soc_dai *dai)
93{
94 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
95
96 dev_dbg(dai->dev, "%s start HDMI port\n", __func__);
97
98 dai_data->channels = params_channels(params);
99 switch (dai_data->channels) {
100 case 2:
101 dai_data->port_config.hdmi.channel_mode = 0; /* Put in macro */
102 break;
103 default:
104 return -EINVAL;
105 break;
106 }
107
108 /* Q6 only supports 16 as now */
109 dai_data->port_config.hdmi.bitwidth = 16;
110 dai_data->port_config.hdmi.data_type = 0;
111 dai_data->rate = params_rate(params);
112
113 return 0;
114}
115
116static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
117 struct snd_soc_dai *dai, int stream)
118{
119 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
120 u8 pgd_la, inf_la;
121
122 memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
123 sizeof(dai_data->port_config.slimbus.slave_port_mapping));
124
125 dai_data->channels = params_channels(params);
126 switch (dai_data->channels) {
127 case 2:
128 if (dai->id == SLIMBUS_0_RX) {
129 dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
130 dai_data->port_config.slimbus.slave_port_mapping[1] = 2;
131 } else {
132 dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
133 dai_data->port_config.slimbus.slave_port_mapping[1] = 8;
134 }
135 break;
136 case 1:
137 if (dai->id == SLIMBUS_0_RX)
138 dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
139 else
140 dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
141 break;
142 default:
143 return -EINVAL;
144 break;
145 }
146 dai_data->rate = params_rate(params);
147 tabla_get_logical_addresses(&pgd_la, &inf_la);
148
149 dai_data->port_config.slimbus.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1;
150 dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
151 dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
152 /* Q6 only supports 16 as now */
153 dai_data->port_config.slimbus.bit_width = 16;
154 dai_data->port_config.slimbus.data_format = 0;
155 dai_data->port_config.slimbus.num_channels = dai_data->channels;
156 dai_data->port_config.slimbus.reserved = 0;
157
158 dev_dbg(dai->dev, "slimbus_dev_id %hu slave_dev_pgd_la 0x%hx\n"
159 "slave_dev_intfdev_la 0x%hx bit_width %hu data_format %hu\n"
160 "num_channel %hu slave_port_mapping[0] %hu\n"
161 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
162 "sample_rate %d\n",
163 dai_data->port_config.slimbus.slimbus_dev_id,
164 dai_data->port_config.slimbus.slave_dev_pgd_la,
165 dai_data->port_config.slimbus.slave_dev_intfdev_la,
166 dai_data->port_config.slimbus.bit_width,
167 dai_data->port_config.slimbus.data_format,
168 dai_data->port_config.slimbus.num_channels,
169 dai_data->port_config.slimbus.slave_port_mapping[0],
170 dai_data->port_config.slimbus.slave_port_mapping[1],
171 dai_data->port_config.slimbus.slave_port_mapping[2],
172 dai_data->rate);
173
174 return 0;
175}
176
177static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
178 struct snd_soc_dai *dai, int stream)
179{
180 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
181
182 dai_data->channels = params_channels(params);
183 dai_data->rate = params_rate(params);
184
185 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
186 dai_data->channels, dai_data->rate);
187
188 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
189
190 return 0;
191}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700192static int msm_dai_q6_auxpcm_hw_params(
193 struct snd_pcm_substream *substream,
194 struct snd_pcm_hw_params *params,
195 struct snd_soc_dai *dai)
196{
197 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
198 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
199 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
200
201 if (params_channels(params) != 1) {
202 dev_err(dai->dev, "AUX PCM supports only mono stream\n");
203 return -EINVAL;
204 }
205 dai_data->channels = params_channels(params);
206
207 if (params_rate(params) != 8000) {
208 dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
209 return -EINVAL;
210 }
211 dai_data->rate = params_rate(params);
212 dai_data->port_config.pcm.mode = auxpcm_pdata->mode;
213 dai_data->port_config.pcm.sync = auxpcm_pdata->sync;
214 dai_data->port_config.pcm.frame = auxpcm_pdata->frame;
215 dai_data->port_config.pcm.quant = auxpcm_pdata->quant;
216 dai_data->port_config.pcm.slot = auxpcm_pdata->slot;
217 dai_data->port_config.pcm.data = auxpcm_pdata->data;
218
219 return 0;
220}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530222static int get_frame_size(u16 rate, u16 ch)
223{
224 if (rate == 8000) {
225 if (ch == 1)
226 return 128 * 2;
227 else
228 return 128 * 2 * 2;
229 } else if (rate == 16000) {
230 if (ch == 1)
231 return 128 * 2 * 2;
232 else
233 return 128 * 2 * 4;
234 } else if (rate == 48000) {
235 if (ch == 1)
236 return 128 * 2 * 6;
237 else
238 return 128 * 2 * 12;
239 } else
240 return 128 * 2 * 12;
241}
242
243static int msm_dai_q6_afe_rtproxy_hw_params(struct snd_pcm_hw_params *params,
244 struct snd_soc_dai *dai)
245{
246 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
247
248 dai_data->rate = params_rate(params);
249 dai_data->port_config.rtproxy.num_ch =
250 params_channels(params);
251
252 pr_debug("channel %d entered,dai_id: %d,rate: %d\n",
253 dai_data->port_config.rtproxy.num_ch, dai->id, dai_data->rate);
254
255 dai_data->port_config.rtproxy.bitwidth = 16; /* Q6 only supports 16 */
256 dai_data->port_config.rtproxy.interleaved = 1;
257 dai_data->port_config.rtproxy.frame_sz = get_frame_size(dai_data->rate,
258 dai_data->port_config.rtproxy.num_ch);
259 dai_data->port_config.rtproxy.jitter =
260 dai_data->port_config.rtproxy.frame_sz/2;
261 dai_data->port_config.rtproxy.lw_mark = 0;
262 dai_data->port_config.rtproxy.hw_mark = 0;
263 dai_data->port_config.rtproxy.rsvd = 0;
264
265 return 0;
266}
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268/* Current implementation assumes hw_param is called once
269 * This may not be the case but what to do when ADM and AFE
270 * port are already opened and parameter changes
271 */
272static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
273 struct snd_pcm_hw_params *params,
274 struct snd_soc_dai *dai)
275{
276 int rc = 0;
277
278 switch (dai->id) {
279 case PRIMARY_I2S_TX:
280 case PRIMARY_I2S_RX:
281 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
282 break;
283 case HDMI_RX:
284 rc = msm_dai_q6_hdmi_hw_params(params, dai);
285 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700286 case SLIMBUS_0_RX:
287 case SLIMBUS_0_TX:
288 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
289 substream->stream);
290 break;
291 case INT_BT_SCO_RX:
292 case INT_BT_SCO_TX:
293 case INT_FM_RX:
294 case INT_FM_TX:
295 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
296 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530297 case RT_PROXY_DAI_001_TX:
298 case RT_PROXY_DAI_001_RX:
299 case RT_PROXY_DAI_002_TX:
300 case RT_PROXY_DAI_002_RX:
301 rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
302 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700303 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700304 case VOICE_RECORD_RX:
305 case VOICE_RECORD_TX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700306 rc = 0;
307 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700308 default:
309 dev_err(dai->dev, "invalid AFE port ID\n");
310 rc = -EINVAL;
311 break;
312 }
313
314 return rc;
315}
316
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700317static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
318 struct snd_soc_dai *dai)
319{
320 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
321 int rc = 0;
322
323 rc = adm_close(dai->id);
324 if (IS_ERR_VALUE(rc))
325 dev_err(dai->dev, "fail to close ADM COPP\n");
326
327 pr_debug("%s: dai->id = %d", __func__, dai->id);
328
329 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
330 clk_disable(pcm_clk);
331 rc = afe_close(dai->id); /* can block */
332 if (IS_ERR_VALUE(rc))
333 dev_err(dai->dev, "fail to close AFE port\n");
334 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
335 *dai_data->status_mask);
336 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
337
338 rc = afe_close(PCM_TX);
339 if (IS_ERR_VALUE(rc))
340 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
341 }
342}
343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
345 struct snd_soc_dai *dai)
346{
347 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530348 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700351 switch (dai->id) {
352 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700353 case VOICE_RECORD_TX:
354 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700355 pr_debug("%s, stop pseudo port:%d\n",
356 __func__, dai->id);
357 rc = afe_stop_pseudo_port(dai->id);
358 break;
359 default:
360 rc = afe_close(dai->id); /* can block */
361 break;
362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 if (IS_ERR_VALUE(rc))
364 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530365 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
366 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
368 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700369}
370
371static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
372 struct snd_soc_dai *dai)
373{
374 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
375 int rc = 0;
376
377 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
378 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
379
380 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700381 rc = afe_q6_interface_prepare();
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700382 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700383 dev_err(dai->dev, "fail to open AFE APR\n");
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700384
Patrick Laicf999112011-08-23 11:27:20 -0700385 rc = afe_q6_interface_prepare();
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700386 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700387 dev_err(dai->dev, "fail to open AFE APR\n");
388
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700389 pr_debug("%s:dai->id:%d dai_data->status_mask = %ld\n",
390 __func__, dai->id, *dai_data->status_mask);
391
392 /*
393 * For AUX PCM Interface the below sequence of clk
394 * settings and afe_open is a strict requirement.
395 *
396 * Also using afe_open instead of afe_port_start_nowait
397 * to make sure the port is open before deasserting the
398 * clock line. This is required because pcm register is
399 * not written before clock deassert. Hence the hw does
400 * not get updated with new setting if the below clock
401 * assert/deasset and afe_open sequence is not followed.
402 */
403
404 clk_reset(pcm_clk, CLK_RESET_ASSERT);
405
406 afe_open(dai->id, &dai_data->port_config,
407 dai_data->rate);
408 set_bit(STATUS_PORT_STARTED,
409 dai_data->status_mask);
410
411 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
412
413 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
414 if (rc < 0) {
415 pr_err("%s: clk_set_rate failed\n", __func__);
416 return rc;
417 }
418
419 clk_enable(pcm_clk);
420 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
421
422 }
423 return rc;
424}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700425
426static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
427 struct snd_soc_dai *dai)
428{
429 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
430 int rc = 0;
431
Patrick Lai831561e2011-07-26 22:51:27 -0700432 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700433 /* PORT START should be set if prepare called in active state */
434 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700435 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700436 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700437 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700438 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439}
440
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700441static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
442 int cmd, struct snd_soc_dai *dai)
443{
444 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
445 int rc = 0;
446
447 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
448 __func__, dai->id, cmd, *dai_data->status_mask);
449
450 switch (cmd) {
451
452 case SNDRV_PCM_TRIGGER_START:
453 case SNDRV_PCM_TRIGGER_RESUME:
454 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
455 /* afe_open will be called from prepare */
456 return 0;
457
458 case SNDRV_PCM_TRIGGER_STOP:
459 case SNDRV_PCM_TRIGGER_SUSPEND:
460 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
461 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
462
463 clk_disable(pcm_clk);
464 afe_port_stop_nowait(dai->id);
465 clear_bit(STATUS_PORT_STARTED,
466 dai_data->status_mask);
467
468 afe_port_stop_nowait(PCM_TX);
469 }
470 break;
471
472 default:
473 rc = -EINVAL;
474 }
475
476 return rc;
477
478}
479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
481 struct snd_soc_dai *dai)
482{
483 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
484 int rc = 0;
485
486 /* Start/stop port without waiting for Q6 AFE response. Need to have
487 * native q6 AFE driver propagates AFE response in order to handle
488 * port start/stop command error properly if error does arise.
489 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530490 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
491 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 switch (cmd) {
493 case SNDRV_PCM_TRIGGER_START:
494 case SNDRV_PCM_TRIGGER_RESUME:
495 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
496 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700497 switch (dai->id) {
498 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700499 case VOICE_RECORD_TX:
500 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700501 afe_pseudo_port_start_nowait(dai->id);
502 break;
503 default:
504 afe_port_start_nowait(dai->id,
505 &dai_data->port_config, dai_data->rate);
506 break;
507 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508 set_bit(STATUS_PORT_STARTED,
509 dai_data->status_mask);
510 }
511 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700512 case SNDRV_PCM_TRIGGER_STOP:
513 case SNDRV_PCM_TRIGGER_SUSPEND:
514 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
515 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700516 switch (dai->id) {
517 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700518 case VOICE_RECORD_TX:
519 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700520 afe_pseudo_port_stop_nowait(dai->id);
521 break;
522 default:
523 afe_port_stop_nowait(dai->id);
524 break;
525 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 clear_bit(STATUS_PORT_STARTED,
527 dai_data->status_mask);
528 }
529 break;
530
531 default:
532 rc = -EINVAL;
533 }
534
535 return rc;
536}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700537static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
538{
539 struct msm_dai_q6_dai_data *dai_data;
540 int rc = 0;
541
542 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
543 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
544
545 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
546 GFP_KERNEL);
547
548 if (!dai_data) {
549 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
550 dai->id);
551 rc = -ENOMEM;
552 } else
553 dev_set_drvdata(dai->dev, dai_data);
554
555 /*
556 * The clk name for AUX PCM operation is passed as platform
557 * data to the cpu driver, since cpu drive is unaware of any
558 * boarc specific configuration.
559 */
560 pcm_clk = clk_get(NULL, auxpcm_pdata->clk);
561 if (IS_ERR(pcm_clk)) {
562 pr_err("%s: could not get pcm_clk\n", __func__);
563 return PTR_ERR(pcm_clk);
564 kfree(dai_data);
565 }
566
567 return rc;
568}
569
570static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
571{
572 struct msm_dai_q6_dai_data *dai_data;
573 int rc;
574
575 dai_data = dev_get_drvdata(dai->dev);
576
577 /* If AFE port is still up, close it */
578 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
579 rc = afe_close(dai->id); /* can block */
580 if (IS_ERR_VALUE(rc))
581 dev_err(dai->dev, "fail to close AFE port\n");
582 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
583
584 rc = afe_close(PCM_TX);
585 if (IS_ERR_VALUE(rc))
586 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
587 }
588
589
590 kfree(dai_data);
591 snd_soc_unregister_dai(dai->dev);
592
593 return 0;
594}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595
596static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
597{
598 struct msm_dai_q6_dai_data *dai_data;
599 int rc = 0;
600
601 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
602 GFP_KERNEL);
603
604 if (!dai_data) {
605 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
606 dai->id);
607 rc = -ENOMEM;
608 } else
609 dev_set_drvdata(dai->dev, dai_data);
610
611 return rc;
612}
613
614static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
615{
616 struct msm_dai_q6_dai_data *dai_data;
617 int rc;
618
619 dai_data = dev_get_drvdata(dai->dev);
620
621 /* If AFE port is still up, close it */
622 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Helen Zeng0705a5f2011-10-14 15:29:52 -0700623 switch (dai->id) {
624 case VOICE_PLAYBACK_TX:
Helen Zenge3d716a2011-10-14 16:32:16 -0700625 case VOICE_RECORD_TX:
626 case VOICE_RECORD_RX:
Helen Zeng0705a5f2011-10-14 15:29:52 -0700627 pr_debug("%s, stop pseudo port:%d\n",
628 __func__, dai->id);
629 rc = afe_stop_pseudo_port(dai->id);
630 break;
631 default:
632 rc = afe_close(dai->id); /* can block */
633 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634 if (IS_ERR_VALUE(rc))
635 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530636 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 }
638 kfree(dai_data);
639 snd_soc_unregister_dai(dai->dev);
640
641 return 0;
642}
643
Lei Zhou157c1842011-08-19 13:05:04 -0400644static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
645{
646 int rc = 0;
647
648 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__, dai->id);
649 switch (dai->id) {
650 case PRIMARY_I2S_TX:
651 case PRIMARY_I2S_RX:
652 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
653 break;
654 default:
655 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
656 rc = -EINVAL;
657 break;
658 }
659
660 return rc;
661}
662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700664 .prepare = msm_dai_q6_prepare,
665 .trigger = msm_dai_q6_trigger,
666 .hw_params = msm_dai_q6_hw_params,
667 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400668 .set_fmt = msm_dai_q6_set_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669};
670
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700671static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
672 .prepare = msm_dai_q6_auxpcm_prepare,
673 .trigger = msm_dai_q6_auxpcm_trigger,
674 .hw_params = msm_dai_q6_auxpcm_hw_params,
675 .shutdown = msm_dai_q6_auxpcm_shutdown,
676};
677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700678static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
679 .playback = {
680 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
681 SNDRV_PCM_RATE_16000,
682 .formats = SNDRV_PCM_FMTBIT_S16_LE,
683 .channels_min = 1,
684 .channels_max = 2,
685 .rate_min = 8000,
686 .rate_max = 48000,
687 },
688 .ops = &msm_dai_q6_ops,
689 .probe = msm_dai_q6_dai_probe,
690 .remove = msm_dai_q6_dai_remove,
691};
692
693static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
694 .capture = {
695 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
696 SNDRV_PCM_RATE_16000,
697 .formats = SNDRV_PCM_FMTBIT_S16_LE,
698 .channels_min = 1,
699 .channels_max = 2,
700 .rate_min = 8000,
701 .rate_max = 48000,
702 },
703 .ops = &msm_dai_q6_ops,
704 .probe = msm_dai_q6_dai_probe,
705 .remove = msm_dai_q6_dai_remove,
706};
707
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530708static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
709 .playback = {
710 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
711 SNDRV_PCM_RATE_16000,
712 .formats = SNDRV_PCM_FMTBIT_S16_LE,
713 .channels_min = 1,
714 .channels_max = 2,
715 .rate_min = 8000,
716 .rate_max = 48000,
717 },
718 .ops = &msm_dai_q6_ops,
719 .probe = msm_dai_q6_dai_probe,
720 .remove = msm_dai_q6_dai_remove,
721};
722
723static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
724 .capture = {
725 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
726 SNDRV_PCM_RATE_16000,
727 .formats = SNDRV_PCM_FMTBIT_S16_LE,
728 .channels_min = 1,
729 .channels_max = 2,
730 .rate_min = 8000,
731 .rate_max = 48000,
732 },
733 .ops = &msm_dai_q6_ops,
734 .probe = msm_dai_q6_dai_probe,
735 .remove = msm_dai_q6_dai_remove,
736};
737
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738static struct snd_soc_dai_driver msm_dai_q6_hdmi_rx_dai = {
739 .playback = {
740 .rates = SNDRV_PCM_RATE_48000,
741 .formats = SNDRV_PCM_FMTBIT_S16_LE,
742 .channels_min = 2,
743 .channels_max = 2,
744 .rate_max = 48000,
745 .rate_min = 48000,
746 },
747 .ops = &msm_dai_q6_ops,
748 .probe = msm_dai_q6_dai_probe,
749 .remove = msm_dai_q6_dai_remove,
750};
751
Helen Zeng0705a5f2011-10-14 15:29:52 -0700752static struct snd_soc_dai_driver msm_dai_q6_voice_playback_tx_dai = {
753 .playback = {
754 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
755 SNDRV_PCM_RATE_16000,
756 .formats = SNDRV_PCM_FMTBIT_S16_LE,
757 .channels_min = 1,
758 .channels_max = 2,
759 .rate_max = 48000,
760 .rate_min = 8000,
761 },
762 .ops = &msm_dai_q6_ops,
763 .probe = msm_dai_q6_dai_probe,
764 .remove = msm_dai_q6_dai_remove,
765};
766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
768 .playback = {
769 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
770 SNDRV_PCM_RATE_16000,
771 .formats = SNDRV_PCM_FMTBIT_S16_LE,
772 .channels_min = 1,
773 .channels_max = 2,
774 .rate_min = 8000,
775 .rate_max = 48000,
776 },
777 .ops = &msm_dai_q6_ops,
778 .probe = msm_dai_q6_dai_probe,
779 .remove = msm_dai_q6_dai_remove,
780};
781
782static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
783 .capture = {
784 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
785 SNDRV_PCM_RATE_16000,
786 .formats = SNDRV_PCM_FMTBIT_S16_LE,
787 .channels_min = 1,
788 .channels_max = 2,
789 .rate_min = 8000,
790 .rate_max = 48000,
791 },
792 .ops = &msm_dai_q6_ops,
793 .probe = msm_dai_q6_dai_probe,
794 .remove = msm_dai_q6_dai_remove,
795};
796
Helen Zenge3d716a2011-10-14 16:32:16 -0700797static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
798 .capture = {
799 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
800 SNDRV_PCM_RATE_16000,
801 .formats = SNDRV_PCM_FMTBIT_S16_LE,
802 .channels_min = 1,
803 .channels_max = 2,
804 .rate_min = 8000,
805 .rate_max = 48000,
806 },
807 .ops = &msm_dai_q6_ops,
808 .probe = msm_dai_q6_dai_probe,
809 .remove = msm_dai_q6_dai_remove,
810};
811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
813 .playback = {
814 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
815 .formats = SNDRV_PCM_FMTBIT_S16_LE,
816 .channels_min = 1,
817 .channels_max = 1,
818 .rate_max = 16000,
819 .rate_min = 8000,
820 },
821 .ops = &msm_dai_q6_ops,
822 .probe = msm_dai_q6_dai_probe,
823 .remove = msm_dai_q6_dai_remove,
824};
825
826static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
827 .playback = {
828 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
829 .formats = SNDRV_PCM_FMTBIT_S16_LE,
830 .channels_min = 1,
831 .channels_max = 1,
832 .rate_max = 16000,
833 .rate_min = 8000,
834 },
835 .ops = &msm_dai_q6_ops,
836 .probe = msm_dai_q6_dai_probe,
837 .remove = msm_dai_q6_dai_remove,
838};
839
840static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
841 .playback = {
842 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
843 SNDRV_PCM_RATE_16000,
844 .formats = SNDRV_PCM_FMTBIT_S16_LE,
845 .channels_min = 2,
846 .channels_max = 2,
847 .rate_max = 48000,
848 .rate_min = 8000,
849 },
850 .ops = &msm_dai_q6_ops,
851 .probe = msm_dai_q6_dai_probe,
852 .remove = msm_dai_q6_dai_remove,
853};
854
855static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
856 .playback = {
857 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
858 SNDRV_PCM_RATE_16000,
859 .formats = SNDRV_PCM_FMTBIT_S16_LE,
860 .channels_min = 2,
861 .channels_max = 2,
862 .rate_max = 48000,
863 .rate_min = 8000,
864 },
865 .ops = &msm_dai_q6_ops,
866 .probe = msm_dai_q6_dai_probe,
867 .remove = msm_dai_q6_dai_remove,
868};
869
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700870static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
871 .playback = {
872 .rates = SNDRV_PCM_RATE_8000,
873 .formats = SNDRV_PCM_FMTBIT_S16_LE,
874 .channels_min = 1,
875 .channels_max = 1,
876 .rate_max = 8000,
877 .rate_min = 8000,
878 },
879 .ops = &msm_dai_q6_auxpcm_ops,
880 .probe = msm_dai_q6_dai_auxpcm_probe,
881 .remove = msm_dai_q6_dai_auxpcm_remove,
882};
883
884static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
885 .capture = {
886 .rates = SNDRV_PCM_RATE_8000,
887 .formats = SNDRV_PCM_FMTBIT_S16_LE,
888 .channels_min = 1,
889 .channels_max = 1,
890 .rate_max = 8000,
891 .rate_min = 8000,
892 },
893};
894
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895/* To do: change to register DAIs as batch */
896static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
897{
898 int rc = 0;
899
900 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
901
902 switch (pdev->id) {
903 case PRIMARY_I2S_RX:
904 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
905 break;
906 case PRIMARY_I2S_TX:
907 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
908 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700909 case PCM_RX:
910 rc = snd_soc_register_dai(&pdev->dev,
911 &msm_dai_q6_aux_pcm_rx_dai);
912 break;
913 case PCM_TX:
914 rc = snd_soc_register_dai(&pdev->dev,
915 &msm_dai_q6_aux_pcm_tx_dai);
916 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 case HDMI_RX:
918 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_hdmi_rx_dai);
919 break;
920 case SLIMBUS_0_RX:
921 rc = snd_soc_register_dai(&pdev->dev,
922 &msm_dai_q6_slimbus_rx_dai);
923 break;
924 case SLIMBUS_0_TX:
925 rc = snd_soc_register_dai(&pdev->dev,
926 &msm_dai_q6_slimbus_tx_dai);
927 case INT_BT_SCO_RX:
928 rc = snd_soc_register_dai(&pdev->dev,
929 &msm_dai_q6_bt_sco_rx_dai);
930 break;
931 case INT_BT_SCO_TX:
932 rc = snd_soc_register_dai(&pdev->dev,
933 &msm_dai_q6_bt_sco_tx_dai);
934 break;
935 case INT_FM_RX:
936 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
937 break;
938 case INT_FM_TX:
939 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
940 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530941 case RT_PROXY_DAI_001_RX:
942 case RT_PROXY_DAI_002_RX:
943 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
944 break;
945 case RT_PROXY_DAI_001_TX:
946 case RT_PROXY_DAI_002_TX:
947 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
948 break;
Helen Zeng0705a5f2011-10-14 15:29:52 -0700949 case VOICE_PLAYBACK_TX:
950 rc = snd_soc_register_dai(&pdev->dev,
951 &msm_dai_q6_voice_playback_tx_dai);
952 break;
Helen Zenge3d716a2011-10-14 16:32:16 -0700953 case VOICE_RECORD_RX:
954 case VOICE_RECORD_TX:
955 rc = snd_soc_register_dai(&pdev->dev,
956 &msm_dai_q6_incall_record_dai);
957 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 default:
959 rc = -ENODEV;
960 break;
961 }
962 return rc;
963}
964
965static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
966{
967 snd_soc_unregister_dai(&pdev->dev);
968 return 0;
969}
970
971static struct platform_driver msm_dai_q6_driver = {
972 .probe = msm_dai_q6_dev_probe,
973 .remove = msm_dai_q6_dev_remove,
974 .driver = {
975 .name = "msm-dai-q6",
976 .owner = THIS_MODULE,
977 },
978};
979
980static int __init msm_dai_q6_init(void)
981{
982 return platform_driver_register(&msm_dai_q6_driver);
983}
984module_init(msm_dai_q6_init);
985
986static void __exit msm_dai_q6_exit(void)
987{
988 platform_driver_unregister(&msm_dai_q6_driver);
989}
990module_exit(msm_dai_q6_exit);
991
992/* Module information */
993MODULE_DESCRIPTION("MSM DSP DAI driver");
994MODULE_LICENSE("GPL v2");