blob: 7dca4d454e0dfc7a509867bd999d08f824d792a1 [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>
20#include <sound/core.h>
21#include <sound/pcm.h>
22#include <sound/soc.h>
23#include <sound/apr_audio.h>
24#include <sound/q6afe.h>
25#include <sound/q6adm.h>
26
27enum {
28 STATUS_PORT_STARTED, /* track if AFE port has started */
29 STATUS_MAX
30};
31
32struct msm_dai_q6_dai_data {
33 DECLARE_BITMAP(status_mask, STATUS_MAX);
34 u32 rate;
35 u32 channels;
36 union afe_port_config port_config;
37};
38
39static int msm_dai_q6_cdc_hw_params(struct snd_pcm_hw_params *params,
40 struct snd_soc_dai *dai, int stream)
41{
42 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
43
44 dai_data->channels = params_channels(params);
45 switch (dai_data->channels) {
46 case 2:
47 dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
48 break;
49 case 1:
50 dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
51 break;
52 default:
53 return -EINVAL;
54 break;
55 }
56 dai_data->rate = params_rate(params);
57
58 dev_dbg(dai->dev, " channel %d sample rate %d entered\n",
59 dai_data->channels, dai_data->rate);
60
61 /* Q6 only supports 16 as now */
62 dai_data->port_config.mi2s.bitwidth = 16;
63 dai_data->port_config.mi2s.line = 1;
64 dai_data->port_config.mi2s.ws = 1; /* I2S master mode for now */
65
66 return 0;
67}
68
69static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_hw_params *params,
70 struct snd_soc_dai *dai)
71{
72 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
73
74 dev_dbg(dai->dev, "%s start HDMI port\n", __func__);
75
76 dai_data->channels = params_channels(params);
77 switch (dai_data->channels) {
78 case 2:
79 dai_data->port_config.hdmi.channel_mode = 0; /* Put in macro */
80 break;
81 default:
82 return -EINVAL;
83 break;
84 }
85
86 /* Q6 only supports 16 as now */
87 dai_data->port_config.hdmi.bitwidth = 16;
88 dai_data->port_config.hdmi.data_type = 0;
89 dai_data->rate = params_rate(params);
90
91 return 0;
92}
93
94static int msm_dai_q6_slim_bus_hw_params(struct snd_pcm_hw_params *params,
95 struct snd_soc_dai *dai, int stream)
96{
97 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
98 u8 pgd_la, inf_la;
99
100 memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
101 sizeof(dai_data->port_config.slimbus.slave_port_mapping));
102
103 dai_data->channels = params_channels(params);
104 switch (dai_data->channels) {
105 case 2:
106 if (dai->id == SLIMBUS_0_RX) {
107 dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
108 dai_data->port_config.slimbus.slave_port_mapping[1] = 2;
109 } else {
110 dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
111 dai_data->port_config.slimbus.slave_port_mapping[1] = 8;
112 }
113 break;
114 case 1:
115 if (dai->id == SLIMBUS_0_RX)
116 dai_data->port_config.slimbus.slave_port_mapping[0] = 1;
117 else
118 dai_data->port_config.slimbus.slave_port_mapping[0] = 7;
119 break;
120 default:
121 return -EINVAL;
122 break;
123 }
124 dai_data->rate = params_rate(params);
125 tabla_get_logical_addresses(&pgd_la, &inf_la);
126
127 dai_data->port_config.slimbus.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1;
128 dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
129 dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
130 /* Q6 only supports 16 as now */
131 dai_data->port_config.slimbus.bit_width = 16;
132 dai_data->port_config.slimbus.data_format = 0;
133 dai_data->port_config.slimbus.num_channels = dai_data->channels;
134 dai_data->port_config.slimbus.reserved = 0;
135
136 dev_dbg(dai->dev, "slimbus_dev_id %hu slave_dev_pgd_la 0x%hx\n"
137 "slave_dev_intfdev_la 0x%hx bit_width %hu data_format %hu\n"
138 "num_channel %hu slave_port_mapping[0] %hu\n"
139 "slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
140 "sample_rate %d\n",
141 dai_data->port_config.slimbus.slimbus_dev_id,
142 dai_data->port_config.slimbus.slave_dev_pgd_la,
143 dai_data->port_config.slimbus.slave_dev_intfdev_la,
144 dai_data->port_config.slimbus.bit_width,
145 dai_data->port_config.slimbus.data_format,
146 dai_data->port_config.slimbus.num_channels,
147 dai_data->port_config.slimbus.slave_port_mapping[0],
148 dai_data->port_config.slimbus.slave_port_mapping[1],
149 dai_data->port_config.slimbus.slave_port_mapping[2],
150 dai_data->rate);
151
152 return 0;
153}
154
155static int msm_dai_q6_bt_fm_hw_params(struct snd_pcm_hw_params *params,
156 struct snd_soc_dai *dai, int stream)
157{
158 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
159
160 dai_data->channels = params_channels(params);
161 dai_data->rate = params_rate(params);
162
163 dev_dbg(dai->dev, "channels %d sample rate %d entered\n",
164 dai_data->channels, dai_data->rate);
165
166 memset(&dai_data->port_config, 0, sizeof(dai_data->port_config));
167
168 return 0;
169}
170
171/* Current implementation assumes hw_param is called once
172 * This may not be the case but what to do when ADM and AFE
173 * port are already opened and parameter changes
174 */
175static int msm_dai_q6_hw_params(struct snd_pcm_substream *substream,
176 struct snd_pcm_hw_params *params,
177 struct snd_soc_dai *dai)
178{
179 int rc = 0;
180
181 switch (dai->id) {
182 case PRIMARY_I2S_TX:
183 case PRIMARY_I2S_RX:
184 rc = msm_dai_q6_cdc_hw_params(params, dai, substream->stream);
185 break;
186 case HDMI_RX:
187 rc = msm_dai_q6_hdmi_hw_params(params, dai);
188 break;
189
190 case SLIMBUS_0_RX:
191 case SLIMBUS_0_TX:
192 rc = msm_dai_q6_slim_bus_hw_params(params, dai,
193 substream->stream);
194 break;
195 case INT_BT_SCO_RX:
196 case INT_BT_SCO_TX:
197 case INT_FM_RX:
198 case INT_FM_TX:
199 rc = msm_dai_q6_bt_fm_hw_params(params, dai, substream->stream);
200 break;
201 default:
202 dev_err(dai->dev, "invalid AFE port ID\n");
203 rc = -EINVAL;
204 break;
205 }
206
207 return rc;
208}
209
210static void msm_dai_q6_shutdown(struct snd_pcm_substream *substream,
211 struct snd_soc_dai *dai)
212{
213 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
214 int rc;
215
216 rc = adm_close(dai->id);
217
218 if (IS_ERR_VALUE(rc))
219 dev_err(dai->dev, "fail to close ADM COPP\n");
220
221 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
222 rc = afe_close(dai->id); /* can block */
223 if (IS_ERR_VALUE(rc))
224 dev_err(dai->dev, "fail to close AFE port\n");
225 clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
226 }
227};
228
229static int msm_dai_q6_prepare(struct snd_pcm_substream *substream,
230 struct snd_soc_dai *dai)
231{
232 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
233 int rc = 0;
234
Patrick Lai831561e2011-07-26 22:51:27 -0700235 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
236 /* PORT START should be set if prepare called in active state */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
238 rc = adm_open_mixer(dai->id, 1, dai_data->rate,
239 dai_data->channels, DEFAULT_COPP_TOPOLOGY);
240 else
241 rc = adm_open_mixer(dai->id, 2, dai_data->rate,
242 dai_data->channels, DEFAULT_COPP_TOPOLOGY);
243 if (IS_ERR_VALUE(rc))
244 dev_err(dai->dev, "fail to open ADM\n");
245 }
246
247 return rc;
248
249}
250
251static int msm_dai_q6_trigger(struct snd_pcm_substream *substream, int cmd,
252 struct snd_soc_dai *dai)
253{
254 struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
255 int rc = 0;
256
257 /* Start/stop port without waiting for Q6 AFE response. Need to have
258 * native q6 AFE driver propagates AFE response in order to handle
259 * port start/stop command error properly if error does arise.
260 */
261 switch (cmd) {
262 case SNDRV_PCM_TRIGGER_START:
263 case SNDRV_PCM_TRIGGER_RESUME:
264 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
265 if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
266 afe_port_start_nowait(dai->id, &dai_data->port_config,
267 dai_data->rate);
268 set_bit(STATUS_PORT_STARTED,
269 dai_data->status_mask);
270 }
271 break;
272
273 case SNDRV_PCM_TRIGGER_STOP:
274 case SNDRV_PCM_TRIGGER_SUSPEND:
275 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
276 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
277 afe_port_stop_nowait(dai->id);
278 clear_bit(STATUS_PORT_STARTED,
279 dai_data->status_mask);
280 }
281 break;
282
283 default:
284 rc = -EINVAL;
285 }
286
287 return rc;
288}
289
290static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
291{
292 struct msm_dai_q6_dai_data *dai_data;
293 int rc = 0;
294
295 dai_data = kzalloc(sizeof(struct msm_dai_q6_dai_data),
296 GFP_KERNEL);
297
298 if (!dai_data) {
299 dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
300 dai->id);
301 rc = -ENOMEM;
302 } else
303 dev_set_drvdata(dai->dev, dai_data);
304
305 return rc;
306}
307
308static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
309{
310 struct msm_dai_q6_dai_data *dai_data;
311 int rc;
312
313 dai_data = dev_get_drvdata(dai->dev);
314
315 /* If AFE port is still up, close it */
316 if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
317 rc = afe_close(dai->id); /* can block */
318 if (IS_ERR_VALUE(rc))
319 dev_err(dai->dev, "fail to close AFE port\n");
320 }
321 kfree(dai_data);
322 snd_soc_unregister_dai(dai->dev);
323
324 return 0;
325}
326
327static struct snd_soc_dai_ops msm_dai_q6_ops = {
328 /*
329 * DSP only handles 16-bit and support only I2S
330 * master mode for now. leave set_fmt function
331 * unimplemented for now.
332 */
333 .prepare = msm_dai_q6_prepare,
334 .trigger = msm_dai_q6_trigger,
335 .hw_params = msm_dai_q6_hw_params,
336 .shutdown = msm_dai_q6_shutdown,
337};
338
339static struct snd_soc_dai_driver msm_dai_q6_i2s_rx_dai = {
340 .playback = {
341 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
342 SNDRV_PCM_RATE_16000,
343 .formats = SNDRV_PCM_FMTBIT_S16_LE,
344 .channels_min = 1,
345 .channels_max = 2,
346 .rate_min = 8000,
347 .rate_max = 48000,
348 },
349 .ops = &msm_dai_q6_ops,
350 .probe = msm_dai_q6_dai_probe,
351 .remove = msm_dai_q6_dai_remove,
352};
353
354static struct snd_soc_dai_driver msm_dai_q6_i2s_tx_dai = {
355 .capture = {
356 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
357 SNDRV_PCM_RATE_16000,
358 .formats = SNDRV_PCM_FMTBIT_S16_LE,
359 .channels_min = 1,
360 .channels_max = 2,
361 .rate_min = 8000,
362 .rate_max = 48000,
363 },
364 .ops = &msm_dai_q6_ops,
365 .probe = msm_dai_q6_dai_probe,
366 .remove = msm_dai_q6_dai_remove,
367};
368
369static struct snd_soc_dai_driver msm_dai_q6_hdmi_rx_dai = {
370 .playback = {
371 .rates = SNDRV_PCM_RATE_48000,
372 .formats = SNDRV_PCM_FMTBIT_S16_LE,
373 .channels_min = 2,
374 .channels_max = 2,
375 .rate_max = 48000,
376 .rate_min = 48000,
377 },
378 .ops = &msm_dai_q6_ops,
379 .probe = msm_dai_q6_dai_probe,
380 .remove = msm_dai_q6_dai_remove,
381};
382
383static struct snd_soc_dai_driver msm_dai_q6_slimbus_rx_dai = {
384 .playback = {
385 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
386 SNDRV_PCM_RATE_16000,
387 .formats = SNDRV_PCM_FMTBIT_S16_LE,
388 .channels_min = 1,
389 .channels_max = 2,
390 .rate_min = 8000,
391 .rate_max = 48000,
392 },
393 .ops = &msm_dai_q6_ops,
394 .probe = msm_dai_q6_dai_probe,
395 .remove = msm_dai_q6_dai_remove,
396};
397
398static struct snd_soc_dai_driver msm_dai_q6_slimbus_tx_dai = {
399 .capture = {
400 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
401 SNDRV_PCM_RATE_16000,
402 .formats = SNDRV_PCM_FMTBIT_S16_LE,
403 .channels_min = 1,
404 .channels_max = 2,
405 .rate_min = 8000,
406 .rate_max = 48000,
407 },
408 .ops = &msm_dai_q6_ops,
409 .probe = msm_dai_q6_dai_probe,
410 .remove = msm_dai_q6_dai_remove,
411};
412
413static struct snd_soc_dai_driver msm_dai_q6_bt_sco_rx_dai = {
414 .playback = {
415 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
416 .formats = SNDRV_PCM_FMTBIT_S16_LE,
417 .channels_min = 1,
418 .channels_max = 1,
419 .rate_max = 16000,
420 .rate_min = 8000,
421 },
422 .ops = &msm_dai_q6_ops,
423 .probe = msm_dai_q6_dai_probe,
424 .remove = msm_dai_q6_dai_remove,
425};
426
427static struct snd_soc_dai_driver msm_dai_q6_bt_sco_tx_dai = {
428 .playback = {
429 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
430 .formats = SNDRV_PCM_FMTBIT_S16_LE,
431 .channels_min = 1,
432 .channels_max = 1,
433 .rate_max = 16000,
434 .rate_min = 8000,
435 },
436 .ops = &msm_dai_q6_ops,
437 .probe = msm_dai_q6_dai_probe,
438 .remove = msm_dai_q6_dai_remove,
439};
440
441static struct snd_soc_dai_driver msm_dai_q6_fm_rx_dai = {
442 .playback = {
443 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
444 SNDRV_PCM_RATE_16000,
445 .formats = SNDRV_PCM_FMTBIT_S16_LE,
446 .channels_min = 2,
447 .channels_max = 2,
448 .rate_max = 48000,
449 .rate_min = 8000,
450 },
451 .ops = &msm_dai_q6_ops,
452 .probe = msm_dai_q6_dai_probe,
453 .remove = msm_dai_q6_dai_remove,
454};
455
456static struct snd_soc_dai_driver msm_dai_q6_fm_tx_dai = {
457 .playback = {
458 .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
459 SNDRV_PCM_RATE_16000,
460 .formats = SNDRV_PCM_FMTBIT_S16_LE,
461 .channels_min = 2,
462 .channels_max = 2,
463 .rate_max = 48000,
464 .rate_min = 8000,
465 },
466 .ops = &msm_dai_q6_ops,
467 .probe = msm_dai_q6_dai_probe,
468 .remove = msm_dai_q6_dai_remove,
469};
470
471/* To do: change to register DAIs as batch */
472static __devinit int msm_dai_q6_dev_probe(struct platform_device *pdev)
473{
474 int rc = 0;
475
476 dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
477
478 switch (pdev->id) {
479 case PRIMARY_I2S_RX:
480 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_rx_dai);
481 break;
482 case PRIMARY_I2S_TX:
483 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_i2s_tx_dai);
484 break;
485 case HDMI_RX:
486 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_hdmi_rx_dai);
487 break;
488 case SLIMBUS_0_RX:
489 rc = snd_soc_register_dai(&pdev->dev,
490 &msm_dai_q6_slimbus_rx_dai);
491 break;
492 case SLIMBUS_0_TX:
493 rc = snd_soc_register_dai(&pdev->dev,
494 &msm_dai_q6_slimbus_tx_dai);
495 case INT_BT_SCO_RX:
496 rc = snd_soc_register_dai(&pdev->dev,
497 &msm_dai_q6_bt_sco_rx_dai);
498 break;
499 case INT_BT_SCO_TX:
500 rc = snd_soc_register_dai(&pdev->dev,
501 &msm_dai_q6_bt_sco_tx_dai);
502 break;
503 case INT_FM_RX:
504 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_rx_dai);
505 break;
506 case INT_FM_TX:
507 rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_fm_tx_dai);
508 break;
509 default:
510 rc = -ENODEV;
511 break;
512 }
513 return rc;
514}
515
516static __devexit int msm_dai_q6_dev_remove(struct platform_device *pdev)
517{
518 snd_soc_unregister_dai(&pdev->dev);
519 return 0;
520}
521
522static struct platform_driver msm_dai_q6_driver = {
523 .probe = msm_dai_q6_dev_probe,
524 .remove = msm_dai_q6_dev_remove,
525 .driver = {
526 .name = "msm-dai-q6",
527 .owner = THIS_MODULE,
528 },
529};
530
531static int __init msm_dai_q6_init(void)
532{
533 return platform_driver_register(&msm_dai_q6_driver);
534}
535module_init(msm_dai_q6_init);
536
537static void __exit msm_dai_q6_exit(void)
538{
539 platform_driver_unregister(&msm_dai_q6_driver);
540}
541module_exit(msm_dai_q6_exit);
542
543/* Module information */
544MODULE_DESCRIPTION("MSM DSP DAI driver");
545MODULE_LICENSE("GPL v2");