blob: 5e02797c83c70d571b03a54a5370ec858d48cf59 [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;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 default:
304 dev_err(dai->dev, "invalid AFE port ID\n");
305 rc = -EINVAL;
306 break;
307 }
308
309 return rc;
310}
311
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700312static void msm_dai_q6_auxpcm_shutdown(struct snd_pcm_substream *substream,
313 struct snd_soc_dai *dai)
314{
315 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
316 int rc = 0;
317
318 rc = adm_close(dai->id);
319 if (IS_ERR_VALUE(rc))
320 dev_err(dai->dev, "fail to close ADM COPP\n");
321
322 pr_debug("%s: dai->id = %d", __func__, dai->id);
323
324 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
325 clk_disable(pcm_clk);
326 rc = afe_close(dai->id); /* can block */
327 if (IS_ERR_VALUE(rc))
328 dev_err(dai->dev, "fail to close AFE port\n");
329 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
330 *dai_data->status_mask);
331 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
332
333 rc = afe_close(PCM_TX);
334 if (IS_ERR_VALUE(rc))
335 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
336 }
337}
338
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700339static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
340 struct snd_soc_dai *dai)
341{
342 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530343 int rc = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
346 rc = afe_close(dai->id); /* can block */
347 if (IS_ERR_VALUE(rc))
348 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530349 pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
350 *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
352 }
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700353}
354
355static int msm_dai_q6_auxpcm_prepare(struct snd_pcm_substream *substream,
356 struct snd_soc_dai *dai)
357{
358 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
359 int rc = 0;
360
361 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
362 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
363
364 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700365 rc = afe_q6_interface_prepare();
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700366 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700367 dev_err(dai->dev, "fail to open AFE APR\n");
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700368
Patrick Laicf999112011-08-23 11:27:20 -0700369 rc = afe_q6_interface_prepare();
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700370 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700371 dev_err(dai->dev, "fail to open AFE APR\n");
372
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700373 pr_debug("%s:dai->id:%d dai_data->status_mask = %ld\n",
374 __func__, dai->id, *dai_data->status_mask);
375
376 /*
377 * For AUX PCM Interface the below sequence of clk
378 * settings and afe_open is a strict requirement.
379 *
380 * Also using afe_open instead of afe_port_start_nowait
381 * to make sure the port is open before deasserting the
382 * clock line. This is required because pcm register is
383 * not written before clock deassert. Hence the hw does
384 * not get updated with new setting if the below clock
385 * assert/deasset and afe_open sequence is not followed.
386 */
387
388 clk_reset(pcm_clk, CLK_RESET_ASSERT);
389
390 afe_open(dai->id, &dai_data->port_config,
391 dai_data->rate);
392 set_bit(STATUS_PORT_STARTED,
393 dai_data->status_mask);
394
395 afe_open(PCM_TX, &dai_data->port_config, dai_data->rate);
396
397 rc = clk_set_rate(pcm_clk, auxpcm_pdata->pcm_clk_rate);
398 if (rc < 0) {
399 pr_err("%s: clk_set_rate failed\n", __func__);
400 return rc;
401 }
402
403 clk_enable(pcm_clk);
404 clk_reset(pcm_clk, CLK_RESET_DEASSERT);
405
406 }
407 return rc;
408}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700409
410static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
411 struct snd_soc_dai *dai)
412{
413 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
414 int rc = 0;
415
Patrick Lai831561e2011-07-26 22:51:27 -0700416 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
Patrick Laicf999112011-08-23 11:27:20 -0700417 /* PORT START should be set if prepare called in active state */
418 rc = afe_q6_interface_prepare();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700419 if (IS_ERR_VALUE(rc))
Patrick Laicf999112011-08-23 11:27:20 -0700420 dev_err(dai->dev, "fail to open AFE APR\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700421 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700423}
424
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700425static int msm_dai_q6_auxpcm_trigger(struct snd_pcm_substream *substream,
426 int cmd, struct snd_soc_dai *dai)
427{
428 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
429 int rc = 0;
430
431 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
432 __func__, dai->id, cmd, *dai_data->status_mask);
433
434 switch (cmd) {
435
436 case SNDRV_PCM_TRIGGER_START:
437 case SNDRV_PCM_TRIGGER_RESUME:
438 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
439 /* afe_open will be called from prepare */
440 return 0;
441
442 case SNDRV_PCM_TRIGGER_STOP:
443 case SNDRV_PCM_TRIGGER_SUSPEND:
444 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
445 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
446
447 clk_disable(pcm_clk);
448 afe_port_stop_nowait(dai->id);
449 clear_bit(STATUS_PORT_STARTED,
450 dai_data->status_mask);
451
452 afe_port_stop_nowait(PCM_TX);
453 }
454 break;
455
456 default:
457 rc = -EINVAL;
458 }
459
460 return rc;
461
462}
463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
465 struct snd_soc_dai *dai)
466{
467 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
468 int rc = 0;
469
470 /* Start/stop port without waiting for Q6 AFE response. Need to have
471 * native q6 AFE driver propagates AFE response in order to handle
472 * port start/stop command error properly if error does arise.
473 */
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530474 pr_debug("%s:port:%d cmd:%d dai_data->status_mask = %ld",
475 __func__, dai->id, cmd, *dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 switch (cmd) {
477 case SNDRV_PCM_TRIGGER_START:
478 case SNDRV_PCM_TRIGGER_RESUME:
479 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
480 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
481 afe_port_start_nowait(dai->id, &dai_data->port_config,
482 dai_data->rate);
483 set_bit(STATUS_PORT_STARTED,
484 dai_data->status_mask);
485 }
486 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 case SNDRV_PCM_TRIGGER_STOP:
488 case SNDRV_PCM_TRIGGER_SUSPEND:
489 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
490 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
491 afe_port_stop_nowait(dai->id);
492 clear_bit(STATUS_PORT_STARTED,
493 dai_data->status_mask);
494 }
495 break;
496
497 default:
498 rc = -EINVAL;
499 }
500
501 return rc;
502}
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700503static int msm_dai_q6_dai_auxpcm_probe(struct snd_soc_dai *dai)
504{
505 struct msm_dai_q6_dai_data *dai_data;
506 int rc = 0;
507
508 struct msm_dai_auxpcm_pdata *auxpcm_pdata =
509 (struct msm_dai_auxpcm_pdata *) dai->dev->platform_data;
510
511 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
512 GFP_KERNEL);
513
514 if (!dai_data) {
515 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
516 dai->id);
517 rc = -ENOMEM;
518 } else
519 dev_set_drvdata(dai->dev, dai_data);
520
521 /*
522 * The clk name for AUX PCM operation is passed as platform
523 * data to the cpu driver, since cpu drive is unaware of any
524 * boarc specific configuration.
525 */
526 pcm_clk = clk_get(NULL, auxpcm_pdata->clk);
527 if (IS_ERR(pcm_clk)) {
528 pr_err("%s: could not get pcm_clk\n", __func__);
529 return PTR_ERR(pcm_clk);
530 kfree(dai_data);
531 }
532
533 return rc;
534}
535
536static int msm_dai_q6_dai_auxpcm_remove(struct snd_soc_dai *dai)
537{
538 struct msm_dai_q6_dai_data *dai_data;
539 int rc;
540
541 dai_data = dev_get_drvdata(dai->dev);
542
543 /* If AFE port is still up, close it */
544 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
545 rc = afe_close(dai->id); /* can block */
546 if (IS_ERR_VALUE(rc))
547 dev_err(dai->dev, "fail to close AFE port\n");
548 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
549
550 rc = afe_close(PCM_TX);
551 if (IS_ERR_VALUE(rc))
552 dev_err(dai->dev, "fail to close AUX PCM TX port\n");
553 }
554
555
556 kfree(dai_data);
557 snd_soc_unregister_dai(dai->dev);
558
559 return 0;
560}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561
562static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
563{
564 struct msm_dai_q6_dai_data *dai_data;
565 int rc = 0;
566
567 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
568 GFP_KERNEL);
569
570 if (!dai_data) {
571 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
572 dai->id);
573 rc = -ENOMEM;
574 } else
575 dev_set_drvdata(dai->dev, dai_data);
576
577 return rc;
578}
579
580static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
581{
582 struct msm_dai_q6_dai_data *dai_data;
583 int rc;
584
585 dai_data = dev_get_drvdata(dai->dev);
586
587 /* If AFE port is still up, close it */
588 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
589 rc = afe_close(dai->id); /* can block */
590 if (IS_ERR_VALUE(rc))
591 dev_err(dai->dev, "fail to close AFE port\n");
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530592 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593 }
594 kfree(dai_data);
595 snd_soc_unregister_dai(dai->dev);
596
597 return 0;
598}
599
Lei Zhou157c1842011-08-19 13:05:04 -0400600static int msm_dai_q6_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
601{
602 int rc = 0;
603
604 dev_dbg(dai->dev, "enter %s, id = %d\n", __func__, dai->id);
605 switch (dai->id) {
606 case PRIMARY_I2S_TX:
607 case PRIMARY_I2S_RX:
608 rc = msm_dai_q6_cdc_set_fmt(dai, fmt);
609 break;
610 default:
611 dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
612 rc = -EINVAL;
613 break;
614 }
615
616 return rc;
617}
618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619static struct snd_soc_dai_ops msm_dai_q6_ops = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 .prepare = msm_dai_q6_prepare,
621 .trigger = msm_dai_q6_trigger,
622 .hw_params = msm_dai_q6_hw_params,
623 .shutdown = msm_dai_q6_shutdown,
Lei Zhou157c1842011-08-19 13:05:04 -0400624 .set_fmt = msm_dai_q6_set_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700625};
626
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700627static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
628 .prepare = msm_dai_q6_auxpcm_prepare,
629 .trigger = msm_dai_q6_auxpcm_trigger,
630 .hw_params = msm_dai_q6_auxpcm_hw_params,
631 .shutdown = msm_dai_q6_auxpcm_shutdown,
632};
633
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700634static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
635 .playback = {
636 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
637 SNDRV_PCM_RATE_16000,
638 .formats = SNDRV_PCM_FMTBIT_S16_LE,
639 .channels_min = 1,
640 .channels_max = 2,
641 .rate_min = 8000,
642 .rate_max = 48000,
643 },
644 .ops = &msm_dai_q6_ops,
645 .probe = msm_dai_q6_dai_probe,
646 .remove = msm_dai_q6_dai_remove,
647};
648
649static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
650 .capture = {
651 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
652 SNDRV_PCM_RATE_16000,
653 .formats = SNDRV_PCM_FMTBIT_S16_LE,
654 .channels_min = 1,
655 .channels_max = 2,
656 .rate_min = 8000,
657 .rate_max = 48000,
658 },
659 .ops = &msm_dai_q6_ops,
660 .probe = msm_dai_q6_dai_probe,
661 .remove = msm_dai_q6_dai_remove,
662};
663
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530664static struct snd_soc_dai_driver msm_dai_q6_afe_rx_dai = {
665 .playback = {
666 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
667 SNDRV_PCM_RATE_16000,
668 .formats = SNDRV_PCM_FMTBIT_S16_LE,
669 .channels_min = 1,
670 .channels_max = 2,
671 .rate_min = 8000,
672 .rate_max = 48000,
673 },
674 .ops = &msm_dai_q6_ops,
675 .probe = msm_dai_q6_dai_probe,
676 .remove = msm_dai_q6_dai_remove,
677};
678
679static struct snd_soc_dai_driver msm_dai_q6_afe_tx_dai = {
680 .capture = {
681 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
682 SNDRV_PCM_RATE_16000,
683 .formats = SNDRV_PCM_FMTBIT_S16_LE,
684 .channels_min = 1,
685 .channels_max = 2,
686 .rate_min = 8000,
687 .rate_max = 48000,
688 },
689 .ops = &msm_dai_q6_ops,
690 .probe = msm_dai_q6_dai_probe,
691 .remove = msm_dai_q6_dai_remove,
692};
693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694static struct snd_soc_dai_driver msm_dai_q6_hdmi_rx_dai = {
695 .playback = {
696 .rates = SNDRV_PCM_RATE_48000,
697 .formats = SNDRV_PCM_FMTBIT_S16_LE,
698 .channels_min = 2,
699 .channels_max = 2,
700 .rate_max = 48000,
701 .rate_min = 48000,
702 },
703 .ops = &msm_dai_q6_ops,
704 .probe = msm_dai_q6_dai_probe,
705 .remove = msm_dai_q6_dai_remove,
706};
707
708static struct snd_soc_dai_driver msm_dai_q6_slimbus_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_slimbus_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
738static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
739 .playback = {
740 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
741 .formats = SNDRV_PCM_FMTBIT_S16_LE,
742 .channels_min = 1,
743 .channels_max = 1,
744 .rate_max = 16000,
745 .rate_min = 8000,
746 },
747 .ops = &msm_dai_q6_ops,
748 .probe = msm_dai_q6_dai_probe,
749 .remove = msm_dai_q6_dai_remove,
750};
751
752static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
753 .playback = {
754 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
755 .formats = SNDRV_PCM_FMTBIT_S16_LE,
756 .channels_min = 1,
757 .channels_max = 1,
758 .rate_max = 16000,
759 .rate_min = 8000,
760 },
761 .ops = &msm_dai_q6_ops,
762 .probe = msm_dai_q6_dai_probe,
763 .remove = msm_dai_q6_dai_remove,
764};
765
766static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
767 .playback = {
768 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
769 SNDRV_PCM_RATE_16000,
770 .formats = SNDRV_PCM_FMTBIT_S16_LE,
771 .channels_min = 2,
772 .channels_max = 2,
773 .rate_max = 48000,
774 .rate_min = 8000,
775 },
776 .ops = &msm_dai_q6_ops,
777 .probe = msm_dai_q6_dai_probe,
778 .remove = msm_dai_q6_dai_remove,
779};
780
781static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
782 .playback = {
783 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
784 SNDRV_PCM_RATE_16000,
785 .formats = SNDRV_PCM_FMTBIT_S16_LE,
786 .channels_min = 2,
787 .channels_max = 2,
788 .rate_max = 48000,
789 .rate_min = 8000,
790 },
791 .ops = &msm_dai_q6_ops,
792 .probe = msm_dai_q6_dai_probe,
793 .remove = msm_dai_q6_dai_remove,
794};
795
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700796static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_rx_dai = {
797 .playback = {
798 .rates = SNDRV_PCM_RATE_8000,
799 .formats = SNDRV_PCM_FMTBIT_S16_LE,
800 .channels_min = 1,
801 .channels_max = 1,
802 .rate_max = 8000,
803 .rate_min = 8000,
804 },
805 .ops = &msm_dai_q6_auxpcm_ops,
806 .probe = msm_dai_q6_dai_auxpcm_probe,
807 .remove = msm_dai_q6_dai_auxpcm_remove,
808};
809
810static struct snd_soc_dai_driver msm_dai_q6_aux_pcm_tx_dai = {
811 .capture = {
812 .rates = SNDRV_PCM_RATE_8000,
813 .formats = SNDRV_PCM_FMTBIT_S16_LE,
814 .channels_min = 1,
815 .channels_max = 1,
816 .rate_max = 8000,
817 .rate_min = 8000,
818 },
819};
820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821/* To do: change to register DAIs as batch */
822static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
823{
824 int rc = 0;
825
826 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
827
828 switch (pdev->id) {
829 case PRIMARY_I2S_RX:
830 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
831 break;
832 case PRIMARY_I2S_TX:
833 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
834 break;
Bhalchandra Gajare0e795c42011-08-15 18:10:30 -0700835 case PCM_RX:
836 rc = snd_soc_register_dai(&pdev->dev,
837 &msm_dai_q6_aux_pcm_rx_dai);
838 break;
839 case PCM_TX:
840 rc = snd_soc_register_dai(&pdev->dev,
841 &msm_dai_q6_aux_pcm_tx_dai);
842 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843 case HDMI_RX:
844 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_hdmi_rx_dai);
845 break;
846 case SLIMBUS_0_RX:
847 rc = snd_soc_register_dai(&pdev->dev,
848 &msm_dai_q6_slimbus_rx_dai);
849 break;
850 case SLIMBUS_0_TX:
851 rc = snd_soc_register_dai(&pdev->dev,
852 &msm_dai_q6_slimbus_tx_dai);
853 case INT_BT_SCO_RX:
854 rc = snd_soc_register_dai(&pdev->dev,
855 &msm_dai_q6_bt_sco_rx_dai);
856 break;
857 case INT_BT_SCO_TX:
858 rc = snd_soc_register_dai(&pdev->dev,
859 &msm_dai_q6_bt_sco_tx_dai);
860 break;
861 case INT_FM_RX:
862 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
863 break;
864 case INT_FM_TX:
865 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
866 break;
Laxminath Kasam32657ec2011-08-01 19:26:57 +0530867 case RT_PROXY_DAI_001_RX:
868 case RT_PROXY_DAI_002_RX:
869 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_rx_dai);
870 break;
871 case RT_PROXY_DAI_001_TX:
872 case RT_PROXY_DAI_002_TX:
873 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
874 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875 default:
876 rc = -ENODEV;
877 break;
878 }
879 return rc;
880}
881
882static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
883{
884 snd_soc_unregister_dai(&pdev->dev);
885 return 0;
886}
887
888static struct platform_driver msm_dai_q6_driver = {
889 .probe = msm_dai_q6_dev_probe,
890 .remove = msm_dai_q6_dev_remove,
891 .driver = {
892 .name = "msm-dai-q6",
893 .owner = THIS_MODULE,
894 },
895};
896
897static int __init msm_dai_q6_init(void)
898{
899 return platform_driver_register(&msm_dai_q6_driver);
900}
901module_init(msm_dai_q6_init);
902
903static void __exit msm_dai_q6_exit(void)
904{
905 platform_driver_unregister(&msm_dai_q6_driver);
906}
907module_exit(msm_dai_q6_exit);
908
909/* Module information */
910MODULE_DESCRIPTION("MSM DSP DAI driver");
911MODULE_LICENSE("GPL v2");