blob: 049f8b6f182851ba5875d8ab60529309b4e5c468 [file] [log] [blame]
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001/*
2 * omap-abe.c -- OMAP ALSA SoC DAI driver using Audio Backend
3 *
4 * Copyright (C) 2010 Texas Instruments
5 *
Liam Girdwoode708bea2011-02-03 15:17:26 +00006 * Contact: Liam Girdwood <lrg@ti.com>
7 * Misael Lopez Cruz <misael.lopez@ti.com>
8 * Sebastien Guiriec <s-guiriec@ti.com>
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00009 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 *
24 */
25
26#define DEBUG
27
28#include <linux/init.h>
29#include <linux/module.h>
30#include <linux/device.h>
31#include <linux/slab.h>
32#include <linux/platform_device.h>
33#include <linux/delay.h>
34#include <sound/core.h>
35#include <sound/pcm.h>
36#include <sound/pcm_params.h>
37#include <sound/initval.h>
38#include <sound/soc.h>
39#include <sound/soc-dapm.h>
40#include <sound/soc-dsp.h>
41
Liam Girdwoodc60eacc2011-02-03 15:12:22 +000042#include <plat/dma-44xx.h>
43#include <plat/dma.h>
44#include "omap-pcm.h"
45#include "omap-abe.h"
46#include "omap-abe-dsp.h"
47#include "abe/abe_main.h"
48#include "abe/port_mgr.h"
49
50#define OMAP_ABE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
51
52struct omap_abe_data {
53 /* MODEM FE*/
54 struct snd_pcm_substream *modem_substream[2];
55 struct snd_soc_dai *modem_dai;
56
57 struct abe *abe;
58
59 /* BE & FE Ports */
60 struct omap_abe_port *port[OMAP_ABE_MAX_PORT_ID + 1];
61};
62
63/*
64 * Stream DMA parameters
65 */
66static struct omap_pcm_dma_data omap_abe_dai_dma_params[7][2] = {
67{
68 {
69 .name = "Media Playback",
70 .dma_req = OMAP44XX_DMA_ABE_REQ_0,
71 .data_type = OMAP_DMA_DATA_TYPE_S32,
72 .sync_mode = OMAP_DMA_SYNC_PACKET,
73 },
74 {
75 .name = "Media Capture1",
76 .dma_req = OMAP44XX_DMA_ABE_REQ_3,
77 .data_type = OMAP_DMA_DATA_TYPE_S32,
78 .sync_mode = OMAP_DMA_SYNC_PACKET,
79 },
80},
81{
82 {},
83 {
84 .name = "Media Capture2",
85 .dma_req = OMAP44XX_DMA_ABE_REQ_4,
86 .data_type = OMAP_DMA_DATA_TYPE_S32,
87 .sync_mode = OMAP_DMA_SYNC_PACKET,
88 },
89},
90{
91 {
92 .name = "Voice Playback",
93 .dma_req = OMAP44XX_DMA_ABE_REQ_1,
94 .data_type = OMAP_DMA_DATA_TYPE_S32,
95 .sync_mode = OMAP_DMA_SYNC_PACKET,
96 },
97 {
98 .name = "Voice Capture",
99 .dma_req = OMAP44XX_DMA_ABE_REQ_2,
100 .data_type = OMAP_DMA_DATA_TYPE_S32,
101 .sync_mode = OMAP_DMA_SYNC_PACKET,
102 },
103},
104{
105 {
106 .name = "Tones Playback",
107 .dma_req = OMAP44XX_DMA_ABE_REQ_5,
108 .data_type = OMAP_DMA_DATA_TYPE_S32,
109 .sync_mode = OMAP_DMA_SYNC_PACKET,
110 },{},
111},
112{
113 {
114 .name = "Vibra Playback",
115 .dma_req = OMAP44XX_DMA_ABE_REQ_6,
116 .data_type = OMAP_DMA_DATA_TYPE_S32,
117 .sync_mode = OMAP_DMA_SYNC_PACKET,
118 },{},
119},
120{
121 {
122 .name = "MODEM Playback",
123 .dma_req = OMAP44XX_DMA_ABE_REQ_1,
124 .data_type = OMAP_DMA_DATA_TYPE_S32,
125 .sync_mode = OMAP_DMA_SYNC_PACKET,
126 },
127 {
128 .name = "MODEM Capture",
129 .dma_req = OMAP44XX_DMA_ABE_REQ_2,
130 .data_type = OMAP_DMA_DATA_TYPE_S32,
131 .sync_mode = OMAP_DMA_SYNC_PACKET,
132 },
133},
134{
135 {
136 .name = "Low Power Playback",
137 .dma_req = OMAP44XX_DMA_ABE_REQ_0,
138 .data_type = OMAP_DMA_DATA_TYPE_S32,
139 .sync_mode = OMAP_DMA_SYNC_PACKET,
140 },{},
141},};
142
143static int modem_get_dai(struct snd_pcm_substream *substream,
144 struct snd_soc_dai *dai)
145{
146 struct snd_soc_pcm_runtime *rtd = substream->private_data;
147 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
148 struct snd_soc_pcm_runtime *modem_rtd;
149
150 abe_priv->modem_substream[substream->stream] =
151 snd_soc_get_dai_substream(rtd->card,
152 OMAP_ABE_BE_MM_EXT1, substream->stream);
153
154 if (abe_priv->modem_substream[substream->stream] == NULL)
155 return -ENODEV;
156
157 modem_rtd = abe_priv->modem_substream[substream->stream]->private_data;
158 abe_priv->modem_substream[substream->stream]->runtime = substream->runtime;
159 abe_priv->modem_dai = modem_rtd->cpu_dai;
160
161 return 0;
162}
163
164static void mute_be(struct snd_soc_pcm_runtime *be,
165 struct snd_soc_dai *dai, int stream)
166{
167 dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream);
168
169 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
170 switch (be->dai_link->be_id) {
171 case OMAP_ABE_DAI_PDM_DL1:
172 abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
173 GAIN_LEFT_OFFSET);
174 abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
175 GAIN_RIGHT_OFFSET);
176 break;
177 case OMAP_ABE_DAI_PDM_DL2:
178 abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
179 GAIN_LEFT_OFFSET);
180 abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
181 GAIN_RIGHT_OFFSET);
182 break;
183 case OMAP_ABE_DAI_PDM_VIB:
184 case OMAP_ABE_DAI_BT_VX:
185 case OMAP_ABE_DAI_MM_FM:
186 case OMAP_ABE_DAI_MODEM:
187 break;
188 }
189 } else {
190 switch (be->dai_link->be_id) {
191 case OMAP_ABE_DAI_PDM_UL:
192 break;
193 case OMAP_ABE_DAI_BT_VX:
194 case OMAP_ABE_DAI_MM_FM:
195 case OMAP_ABE_DAI_MODEM:
196 case OMAP_ABE_DAI_DMIC0:
197 case OMAP_ABE_DAI_DMIC1:
198 case OMAP_ABE_DAI_DMIC2:
199 break;
200 }
201 }
202}
203
204static void unmute_be(struct snd_soc_pcm_runtime *be,
205 struct snd_soc_dai *dai, int stream)
206{
207 dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream);
208
209 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
210 switch (be->dai_link->be_id) {
211 case OMAP_ABE_DAI_PDM_DL1:
212 abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS,
213 GAIN_LEFT_OFFSET);
214 abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS,
215 GAIN_RIGHT_OFFSET);
216 break;
217 case OMAP_ABE_DAI_PDM_DL2:
218 abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_5MS,
219 GAIN_LEFT_OFFSET);
220 abe_write_gain(GAINS_DL2, GAIN_0dB, RAMP_5MS,
221 GAIN_RIGHT_OFFSET);
222 break;
223 case OMAP_ABE_DAI_PDM_VIB:
224 case OMAP_ABE_DAI_BT_VX:
225 case OMAP_ABE_DAI_MM_FM:
226 case OMAP_ABE_DAI_MODEM:
227 break;
228 }
229 } else {
230
231 switch (be->dai_link->be_id) {
232 case OMAP_ABE_DAI_PDM_UL:
233 break;
234 case OMAP_ABE_DAI_BT_VX:
235 case OMAP_ABE_DAI_MM_FM:
236 case OMAP_ABE_DAI_MODEM:
237 case OMAP_ABE_DAI_DMIC0:
238 case OMAP_ABE_DAI_DMIC1:
239 case OMAP_ABE_DAI_DMIC2:
240 break;
241 }
242 }
243}
244
245static void enable_be_port(struct snd_soc_pcm_runtime *be,
246 struct snd_soc_dai *dai, int stream)
247{
248 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
249 abe_data_format_t format;
250
251 dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream);
252
253 switch (be->dai_link->be_id) {
254 /* McPDM Downlink is special case and handled by McPDM driver */
255 case OMAP_ABE_DAI_PDM_DL1:
256 case OMAP_ABE_DAI_PDM_DL2:
257 case OMAP_ABE_DAI_PDM_VIB:
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000258 case OMAP_ABE_DAI_PDM_UL:
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000259 break;
260 case OMAP_ABE_DAI_BT_VX:
261 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
262
263 /* port can only be configured if it's not running */
264 if (omap_abe_port_is_enabled(abe_priv->abe,
265 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]))
266 return;
267
268 /* BT_DL connection to McBSP 1 ports */
269 format.f = 8000;
270 format.samp_format = MONO_RSHIFTED_16;
271 abe_connect_serial_port(BT_VX_DL_PORT, &format, MCBSP1_TX);
272 omap_abe_port_enable(abe_priv->abe,
273 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]);
274 } else {
275
276 /* port can only be configured if it's not running */
277 if (omap_abe_port_is_enabled(abe_priv->abe,
278 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL]))
279 return;
280
281 /* BT_UL connection to McBSP 1 ports */
282 format.f = 8000;
283 format.samp_format = MONO_RSHIFTED_16;
284 abe_connect_serial_port(BT_VX_UL_PORT, &format, MCBSP1_RX);
285 omap_abe_port_enable(abe_priv->abe,
286 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL]);
287 }
288 break;
289 case OMAP_ABE_DAI_MM_FM:
290 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
291
292 /* port can only be configured if it's not running */
293 if (omap_abe_port_is_enabled(abe_priv->abe,
294 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]))
295 return;
296
297 /* MM_EXT connection to McBSP 2 ports */
298 format.f = 48000;
299 format.samp_format = STEREO_RSHIFTED_16;
300 abe_connect_serial_port(MM_EXT_OUT_PORT, &format, MCBSP2_TX);
301 omap_abe_port_enable(abe_priv->abe,
302 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]);
303 } else {
304
305 /* port can only be configured if it's not running */
306 if (omap_abe_port_is_enabled(abe_priv->abe,
307 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL]))
308 return;
309
310 /* MM_EXT connection to McBSP 2 ports */
311 format.f = 48000;
312 format.samp_format = STEREO_RSHIFTED_16;
313 abe_connect_serial_port(MM_EXT_IN_PORT, &format, MCBSP2_RX);
314 omap_abe_port_enable(abe_priv->abe,
315 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL]);
316 }
317 break;
318 case OMAP_ABE_DAI_DMIC0:
319 omap_abe_port_enable(abe_priv->abe,
320 abe_priv->port[OMAP_ABE_BE_PORT_DMIC0]);
321 break;
322 case OMAP_ABE_DAI_DMIC1:
323 omap_abe_port_enable(abe_priv->abe,
324 abe_priv->port[OMAP_ABE_BE_PORT_DMIC1]);
325 break;
326 case OMAP_ABE_DAI_DMIC2:
327 omap_abe_port_enable(abe_priv->abe,
328 abe_priv->port[OMAP_ABE_BE_PORT_DMIC2]);
329 break;
330 }
331}
332
333static void enable_fe_port(struct snd_pcm_substream *substream,
334 struct snd_soc_dai *dai, int stream)
335{
336 struct snd_soc_pcm_runtime *fe = substream->private_data;
337 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
338
339 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
340
341 switch(dai->id) {
342 case ABE_FRONTEND_DAI_MEDIA:
343 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
344 omap_abe_port_enable(abe_priv->abe,
345 abe_priv->port[OMAP_ABE_FE_PORT_MM_DL1]);
346 else
347 omap_abe_port_enable(abe_priv->abe,
348 abe_priv->port[OMAP_ABE_FE_PORT_MM_UL1]);
349 break;
350 case ABE_FRONTEND_DAI_LP_MEDIA:
351 abe_enable_data_transfer(MM_DL_PORT);
352 break;
353 case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
354 if (stream == SNDRV_PCM_STREAM_CAPTURE)
355 omap_abe_port_enable(abe_priv->abe,
356 abe_priv->port[OMAP_ABE_FE_PORT_MM_UL2]);
357 break;
358 case ABE_FRONTEND_DAI_MODEM:
359 case ABE_FRONTEND_DAI_VOICE:
360 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
361 omap_abe_port_enable(abe_priv->abe,
362 abe_priv->port[OMAP_ABE_FE_PORT_VX_DL]);
363 else
364 omap_abe_port_enable(abe_priv->abe,
365 abe_priv->port[OMAP_ABE_FE_PORT_VX_UL]);
366 break;
367 case ABE_FRONTEND_DAI_TONES:
368 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
369 omap_abe_port_enable(abe_priv->abe,
370 abe_priv->port[OMAP_ABE_FE_PORT_TONES]);
371 break;
372 case ABE_FRONTEND_DAI_VIBRA:
373 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
374 omap_abe_port_enable(abe_priv->abe,
375 abe_priv->port[OMAP_ABE_FE_PORT_VIB]);
376 break;
377 }
378}
379
380static void disable_be_port(struct snd_soc_pcm_runtime *be,
381 struct snd_soc_dai *dai, int stream)
382{
383 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
384
385 dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream);
386
387 switch (be->dai_link->be_id) {
388 /* McPDM Downlink is special case and handled by McPDM driver */
389 case OMAP_ABE_DAI_PDM_DL1:
390 case OMAP_ABE_DAI_PDM_DL2:
391 case OMAP_ABE_DAI_PDM_VIB:
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000392 case OMAP_ABE_DAI_PDM_UL:
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000393 break;
394 case OMAP_ABE_DAI_BT_VX:
395 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
396 omap_abe_port_disable(abe_priv->abe,
397 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]);
398 else
399 omap_abe_port_disable(abe_priv->abe,
400 abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_UL]);
401 break;
402 case OMAP_ABE_DAI_MM_FM:
403 case OMAP_ABE_DAI_MODEM:
404 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
405 omap_abe_port_disable(abe_priv->abe,
406 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]);
407 else
408 omap_abe_port_disable(abe_priv->abe,
409 abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_UL]);
410 break;
411 case OMAP_ABE_DAI_DMIC0:
412 omap_abe_port_disable(abe_priv->abe,
413 abe_priv->port[OMAP_ABE_BE_PORT_DMIC0]);
414 break;
415 case OMAP_ABE_DAI_DMIC1:
416 omap_abe_port_disable(abe_priv->abe,
417 abe_priv->port[OMAP_ABE_BE_PORT_DMIC1]);
418 break;
419 case OMAP_ABE_DAI_DMIC2:
420 omap_abe_port_disable(abe_priv->abe,
421 abe_priv->port[OMAP_ABE_BE_PORT_DMIC2]);
422 break;
423 }
424}
425
426static void disable_fe_port(struct snd_pcm_substream *substream,
427 struct snd_soc_dai *dai, int stream)
428{
429 struct snd_soc_pcm_runtime *fe = substream->private_data;
430 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
431
432 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
433
434 switch(dai->id) {
435 case ABE_FRONTEND_DAI_MEDIA:
436 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
437 omap_abe_port_disable(abe_priv->abe,
438 abe_priv->port[OMAP_ABE_FE_PORT_MM_DL1]);
439 else
440 omap_abe_port_disable(abe_priv->abe,
441 abe_priv->port[OMAP_ABE_FE_PORT_MM_UL1]);
442 break;
443 case ABE_FRONTEND_DAI_LP_MEDIA:
444 abe_disable_data_transfer(MM_DL_PORT);
445 break;
446 case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
447 if (stream == SNDRV_PCM_STREAM_CAPTURE)
448 omap_abe_port_disable(abe_priv->abe,
449 abe_priv->port[OMAP_ABE_FE_PORT_MM_UL2]);
450 break;
451 case ABE_FRONTEND_DAI_MODEM:
452 case ABE_FRONTEND_DAI_VOICE:
453 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
454 omap_abe_port_disable(abe_priv->abe,
455 abe_priv->port[OMAP_ABE_FE_PORT_VX_DL]);
456 else
457 omap_abe_port_disable(abe_priv->abe,
458 abe_priv->port[OMAP_ABE_FE_PORT_VX_UL]);
459 break;
460 case ABE_FRONTEND_DAI_TONES:
461 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
462 omap_abe_port_disable(abe_priv->abe,
463 abe_priv->port[OMAP_ABE_FE_PORT_TONES]);
464 break;
465 case ABE_FRONTEND_DAI_VIBRA:
466 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
467 omap_abe_port_disable(abe_priv->abe,
468 abe_priv->port[OMAP_ABE_FE_PORT_VIB]);
469 break;
470 }
471}
472
473static void mute_fe_port(struct snd_pcm_substream *substream,
474 struct snd_soc_dai *dai, int stream)
475{
476 struct snd_soc_pcm_runtime *fe = substream->private_data;
477 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
478
479 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
480
481 switch(dai->id) {
482 case ABE_FRONTEND_DAI_MEDIA:
483 case ABE_FRONTEND_DAI_LP_MEDIA:
484 if (omap_abe_port_is_enabled(abe_priv->abe,
485 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
486 abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
487 if (omap_abe_port_is_enabled(abe_priv->abe,
488 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
489 abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
490 break;
491 case ABE_FRONTEND_DAI_VOICE:
492 if (omap_abe_port_is_enabled(abe_priv->abe,
493 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
494 abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
495 if (omap_abe_port_is_enabled(abe_priv->abe,
496 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
497 abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
498 break;
499 case ABE_FRONTEND_DAI_TONES:
500 if (omap_abe_port_is_enabled(abe_priv->abe,
501 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
502 abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
503 if (omap_abe_port_is_enabled(abe_priv->abe,
504 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
505 abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
506 break;
507 case ABE_FRONTEND_DAI_VIBRA:
508 case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
509 break;
510 }
511}
512
513static void unmute_fe_port(struct snd_pcm_substream *substream,
514 struct snd_soc_dai *dai, int stream)
515{
516 struct snd_soc_pcm_runtime *fe = substream->private_data;
517 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
518
519 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
520
521 switch(dai->id) {
522 case ABE_FRONTEND_DAI_MEDIA:
523 case ABE_FRONTEND_DAI_LP_MEDIA:
524 if (omap_abe_port_is_enabled(abe_priv->abe,
525 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
526 abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
527 if (omap_abe_port_is_enabled(abe_priv->abe,
528 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
529 abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
530 break;
531 case ABE_FRONTEND_DAI_VOICE:
532 if (omap_abe_port_is_enabled(abe_priv->abe,
533 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
534 abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
535 if (omap_abe_port_is_enabled(abe_priv->abe,
536 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
537 abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
538 break;
539 case ABE_FRONTEND_DAI_TONES:
540 if (omap_abe_port_is_enabled(abe_priv->abe,
541 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
542 abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
543 if (omap_abe_port_is_enabled(abe_priv->abe,
544 abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
545 abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
546 break;
547 case ABE_FRONTEND_DAI_VIBRA:
548 case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
549 break;
550 }
551}
552
553static void capture_trigger(struct snd_pcm_substream *substream,
554 struct snd_soc_dai *dai, int cmd)
555{
556 struct snd_soc_pcm_runtime *fe = substream->private_data;
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500557 struct snd_soc_dsp_params *dsp_params, *tmp;
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000558 struct snd_pcm_substream *be_substream;
559 int stream = substream->stream;
560
561 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, fe->cpu_dai->name, stream);
562
563 switch (cmd) {
564 case SNDRV_PCM_TRIGGER_START:
565
566 /* mute and enable BE ports */
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500567 list_for_each_entry_safe(dsp_params, tmp, &fe->dsp[stream].be_clients, list_be) {
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000568 struct snd_soc_pcm_runtime *be = dsp_params->be;
569
570 /* does this trigger() apply to this BE and stream ? */
571 if (!snd_soc_dsp_is_trigger_for_be(fe, be, stream))
572 continue;
573
574 /* is the BE already in the trigger START state ? */
575 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_START)
576 continue;
577
578 be_substream = snd_soc_dsp_get_substream(dsp_params->be, stream);
579
580 /* mute the BE port */
581 mute_be(be, dai, stream);
582
583 /* enable the BE port */
584 enable_be_port(be, dai, stream);
585
586 /* DAI work must be started/stopped at least 250us after ABE */
587 udelay(250);
588
589 /* trigger the BE port */
590 snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai);
591 }
592
593 /* does this trigger() apply to the FE ? */
594 if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
595 /* Enable Frontend sDMA */
596 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
597 enable_fe_port(substream, dai, stream);
598 }
599
600 /* Restore ABE GAINS AMIC */
601 list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
602 struct snd_soc_pcm_runtime *be = dsp_params->be;
603
604 /* does this trigger() apply to this BE and stream ? */
605 if (!snd_soc_dsp_is_trigger_for_be(fe, be, stream))
606 continue;
607
608 /* unmute this BE port */
609 unmute_be(be, dai, stream);
610 }
611 break;
612 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
613 /* Enable sDMA */
614 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
615 enable_fe_port(substream, dai, stream);
616 break;
617 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
618 /* Disable sDMA */
619 disable_fe_port(substream, dai, stream);
620 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
621 break;
622 case SNDRV_PCM_TRIGGER_STOP:
623
624 /* does this trigger() apply to the FE ? */
625 if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
626 /* Disable sDMA */
627 disable_fe_port(substream, dai, stream);
628 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
629 }
630
631 /* disable BE ports */
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500632 list_for_each_entry_safe(dsp_params, tmp, &fe->dsp[stream].be_clients, list_be) {
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000633 struct snd_soc_pcm_runtime *be = dsp_params->be;
634
635 /* does this trigger() apply to this BE and stream ? */
636 if (!snd_soc_dsp_is_trigger_for_be(fe, be, stream))
637 continue;
638
639 /* only STOP BE in FREE state */
640 /* REVISIT: Investigate the appropriate state to check against */
641 //if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
642 // continue;
643
644 be_substream = snd_soc_dsp_get_substream(dsp_params->be, stream);
645
646 /* disable the BE port */
647 disable_be_port(be, dai, stream);
648
649 /* DAI work must be started/stopped at least 250us after ABE */
650 udelay(250);
651
652 /* trigger BE port */
653 snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai);
654 }
655 break;
656 default:
657 break;
658 }
659}
660
661static void playback_trigger(struct snd_pcm_substream *substream,
662 struct snd_soc_dai *dai, int cmd)
663{
664 struct snd_soc_pcm_runtime *fe = substream->private_data;
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500665 struct snd_soc_dsp_params *dsp_params, *tmp;
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000666 struct snd_pcm_substream *be_substream;
667 int stream = substream->stream;
668
669 dev_dbg(&fe->dev, "%s: %s %d\n", __func__, fe->cpu_dai->name, stream);
670
671 switch (cmd) {
672 case SNDRV_PCM_TRIGGER_START:
673
674 /* mute and enable ports */
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500675 list_for_each_entry_safe(dsp_params, tmp, &fe->dsp[stream].be_clients, list_be) {
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000676 struct snd_soc_pcm_runtime *be = dsp_params->be;
677
678 /* does this trigger() apply to the FE ? */
679 if (!snd_soc_dsp_is_trigger_for_be(fe, be, stream))
680 continue;
681
682 /* is the BE already in the trigger START state ? */
683 if (dsp_params->state == SND_SOC_DSP_LINK_STATE_START)
684 continue;
685
686 be_substream = snd_soc_dsp_get_substream(dsp_params->be, stream);
687
688 /* mute BE port */
689 mute_be(be, dai, stream);
690
691 /* enabled BE port */
692 enable_be_port(be, dai, stream);
693
694 /* DAI work must be started/stopped at least 250us after ABE */
695 udelay(250);
696
697 /* trigger BE port */
698 snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai);
699
700 /* unmute the BE port */
701 unmute_be(be, dai, stream);
702 }
703
704 /* does this trigger() apply to the FE ? */
705 if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
706
707 /* Enable Frontend sDMA */
708 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
709 enable_fe_port(substream, dai, stream);
710
711 /* unmute FE port */
712 unmute_fe_port(substream, dai, stream);
713 }
714 break;
715 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
716 /* Enable Frontend sDMA */
717 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
718 enable_fe_port(substream, dai, stream);
719
720 /* unmute FE port */
721 unmute_fe_port(substream, dai, stream);
722 break;
723 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
724 /* disable Frontend sDMA */
725 disable_fe_port(substream, dai, stream);
726 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
727
728 /* mute FE port */
729 mute_fe_port(substream, dai, stream);
730 break;
731 case SNDRV_PCM_TRIGGER_STOP:
732
733 /* does this trigger() apply to the FE ? */
734 if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
735
736 /* disable the transfer */
737 disable_fe_port(substream, dai, stream);
738 snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
739
740 /* mute FE port */
741 mute_fe_port(substream, dai, stream);
742 }
743
744 /* disable BE ports */
Misael Lopez Cruz6074ef92011-07-26 22:52:29 -0500745 list_for_each_entry_safe(dsp_params, tmp, &fe->dsp[stream].be_clients, list_be) {
Liam Girdwoodc60eacc2011-02-03 15:12:22 +0000746 struct snd_soc_pcm_runtime *be = dsp_params->be;
747
748 /* does this trigger() apply to this BE and stream ? */
749 if (!snd_soc_dsp_is_trigger_for_be(fe, be, stream))
750 continue;
751
752 /* only STOP BE in FREE state */
753 if (dsp_params->state != SND_SOC_DSP_LINK_STATE_FREE)
754 continue;
755
756 be_substream = snd_soc_dsp_get_substream(dsp_params->be, stream);
757
758 /* disable the BE */
759 disable_be_port(be, dai, stream);
760
761 /* DAI work must be started/stopped at least 250us after ABE */
762 udelay(250);
763
764 /* trigger the BE port */
765 snd_soc_dai_trigger(be_substream, cmd, be->cpu_dai);
766 }
767 break;
768 default:
769 break;
770 }
771}
772
773static int omap_abe_dai_startup(struct snd_pcm_substream *substream,
774 struct snd_soc_dai *dai)
775{
776 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
777 int ret = 0;
778
779 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
780
781 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
782
783 ret = modem_get_dai(substream, dai);
784 if (ret < 0) {
785 dev_err(dai->dev, "failed to get MODEM DAI\n");
786 return ret;
787 }
788 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n",
789 __func__, substream->stream);
790
791 ret = snd_soc_dai_startup(abe_priv->modem_substream[substream->stream],
792 abe_priv->modem_dai);
793 if (ret < 0) {
794 dev_err(abe_priv->modem_dai->dev, "failed to open DAI %d\n", ret);
795 return ret;
796 }
797 }
798
799 return ret;
800}
801
802static int omap_abe_dai_hw_params(struct snd_pcm_substream *substream,
803 struct snd_pcm_hw_params *params,
804 struct snd_soc_dai *dai)
805{
806 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
807 abe_data_format_t format;
808 abe_dma_t dma_sink;
809 abe_dma_t dma_params;
810 int ret;
811
812 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
813
814 switch (params_channels(params)) {
815 case 1:
816 if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
817 format.samp_format = MONO_RSHIFTED_16;
818 else
819 format.samp_format = MONO_MSB;
820 break;
821 case 2:
822 if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
823 format.samp_format = STEREO_16_16;
824 else
825 format.samp_format = STEREO_MSB;
826 break;
827 case 3:
828 format.samp_format = THREE_MSB;
829 break;
830 case 4:
831 format.samp_format = FOUR_MSB;
832 break;
833 case 5:
834 format.samp_format = FIVE_MSB;
835 break;
836 case 6 :
837 format.samp_format = SIX_MSB;
838 break;
839 case 7 :
840 format.samp_format = SEVEN_MSB;
841 break;
842 case 8:
843 format.samp_format = EIGHT_MSB;
844 break;
845 default:
846 dev_err(dai->dev, "%d channels not supported",
847 params_channels(params));
848 return -EINVAL;
849 }
850
851 format.f = params_rate(params);
852
853 switch (dai->id) {
854 case ABE_FRONTEND_DAI_MEDIA:
855 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
856 abe_connect_cbpr_dmareq_port(MM_DL_PORT, &format, ABE_CBPR0_IDX,
857 &dma_sink);
858 abe_read_port_address(MM_DL_PORT, &dma_params);
859 } else {
860 abe_connect_cbpr_dmareq_port(MM_UL_PORT, &format, ABE_CBPR3_IDX,
861 &dma_sink);
862 abe_read_port_address(MM_UL_PORT, &dma_params);
863 }
864 break;
865 case ABE_FRONTEND_DAI_LP_MEDIA:
866 return 0;
867 break;
868 case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
869 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
870 return -EINVAL;
871 else {
872 abe_connect_cbpr_dmareq_port(MM_UL2_PORT, &format, ABE_CBPR4_IDX,
873 &dma_sink);
874 abe_read_port_address(MM_UL2_PORT, &dma_params);
875 }
876 break;
877 case ABE_FRONTEND_DAI_VOICE:
878 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
879 abe_connect_cbpr_dmareq_port(VX_DL_PORT, &format, ABE_CBPR1_IDX,
880 &dma_sink);
881 abe_read_port_address(VX_DL_PORT, &dma_params);
882 } else {
883 abe_connect_cbpr_dmareq_port(VX_UL_PORT, &format, ABE_CBPR2_IDX,
884 &dma_sink);
885 abe_read_port_address(VX_UL_PORT, &dma_params);
886 }
887 break;
888 case ABE_FRONTEND_DAI_TONES:
889 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
890 abe_connect_cbpr_dmareq_port(TONES_DL_PORT, &format, ABE_CBPR5_IDX,
891 &dma_sink);
892 abe_read_port_address(TONES_DL_PORT, &dma_params);
893 } else
894 return -EINVAL;
895 break;
896 case ABE_FRONTEND_DAI_VIBRA:
897 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
898 abe_connect_cbpr_dmareq_port(VIB_DL_PORT, &format, ABE_CBPR6_IDX,
899 &dma_sink);
900 abe_read_port_address(VIB_DL_PORT, &dma_params);
901 } else
902 return -EINVAL;
903 break;
904 case ABE_FRONTEND_DAI_MODEM:
905 /* MODEM is special case where data IO is performed by McBSP2
906 * directly onto VX_DL and VX_UL (instead of SDMA).
907 */
908 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
909 /* Vx_DL connection to McBSP 2 ports */
910 format.samp_format = STEREO_RSHIFTED_16;
911 abe_connect_serial_port(VX_DL_PORT, &format, MCBSP2_RX);
912 abe_read_port_address(VX_DL_PORT, &dma_params);
913 } else {
914 /* Vx_UL connection to McBSP 2 ports */
915 format.samp_format = STEREO_RSHIFTED_16;
916 abe_connect_serial_port(VX_UL_PORT, &format, MCBSP2_TX);
917 abe_read_port_address(VX_UL_PORT, &dma_params);
918 }
919 break;
920 }
921
922 /* configure frontend SDMA data */
923 omap_abe_dai_dma_params[dai->id][substream->stream].port_addr =
924 (unsigned long)dma_params.data;
925 omap_abe_dai_dma_params[dai->id][substream->stream].packet_size =
926 dma_params.iter;
927
928 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
929 /* call hw_params on McBSP with correct DMA data */
930 snd_soc_dai_set_dma_data(abe_priv->modem_dai, substream,
931 &omap_abe_dai_dma_params[dai->id][substream->stream]);
932
933 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n",
934 __func__, substream->stream);
935
936 ret = snd_soc_dai_hw_params(abe_priv->modem_substream[substream->stream],
937 params, abe_priv->modem_dai);
938 if (ret < 0)
939 dev_err(abe_priv->modem_dai->dev, "MODEM hw_params failed\n");
940 return ret;
941 }
942
943 snd_soc_dai_set_dma_data(dai, substream,
944 &omap_abe_dai_dma_params[dai->id][substream->stream]);
945
946 return 0;
947}
948
949static int omap_abe_dai_prepare(struct snd_pcm_substream *substream,
950 struct snd_soc_dai *dai)
951{
952 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
953 int ret = 0;
954
955 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
956
957 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
958 ret = snd_soc_dai_prepare(abe_priv->modem_substream[substream->stream],
959 abe_priv->modem_dai);
960
961 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n",
962 __func__, substream->stream);
963
964 if (ret < 0) {
965 dev_err(abe_priv->modem_dai->dev, "MODEM prepare failed\n");
966 return ret;
967 }
968 }
969 return ret;
970}
971
972static int omap_abe_dai_trigger(struct snd_pcm_substream *substream,
973 int cmd, struct snd_soc_dai *dai)
974{
975 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
976 int ret = 0;
977
978 dev_dbg(dai->dev, "%s: %s cmd %d\n", __func__, dai->name, cmd);
979
980 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
981
982 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d cmd %d\n",
983 __func__, substream->stream, cmd);
984
985 ret = snd_soc_dai_trigger(abe_priv->modem_substream[substream->stream],
986 cmd, abe_priv->modem_dai);
987 if (ret < 0) {
988 dev_err(abe_priv->modem_dai->dev, "MODEM trigger failed\n");
989 return ret;
990 }
991 }
992
993 return ret;
994}
995
996static int omap_abe_dai_bespoke_trigger(struct snd_pcm_substream *substream,
997 int cmd, struct snd_soc_dai *dai)
998{
Misael Lopez Cruza3168ef2011-06-17 18:32:11 -0500999 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
1000 int ret = 0;
1001
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001002 dev_dbg(dai->dev, "%s: %s cmd %d\n", __func__, dai->name, cmd);
1003
Misael Lopez Cruza3168ef2011-06-17 18:32:11 -05001004 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
1005
1006 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d cmd %d\n",
1007 __func__, substream->stream, cmd);
1008
1009 ret = snd_soc_dai_trigger(abe_priv->modem_substream[substream->stream],
1010 cmd, abe_priv->modem_dai);
1011 if (ret < 0) {
1012 dev_err(abe_priv->modem_dai->dev, "MODEM trigger failed\n");
1013 return ret;
1014 }
1015 }
1016
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001017 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1018 playback_trigger(substream, dai, cmd);
1019 else
1020 capture_trigger(substream, dai, cmd);
1021
Misael Lopez Cruza3168ef2011-06-17 18:32:11 -05001022 return ret;
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001023}
1024
1025static int omap_abe_dai_hw_free(struct snd_pcm_substream *substream,
1026 struct snd_soc_dai *dai)
1027{
1028 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
1029 int ret = 0;
1030
1031 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
1032
1033 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
1034
1035 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n",
1036 __func__, substream->stream);
1037
1038 ret = snd_soc_dai_hw_free(abe_priv->modem_substream[substream->stream],
1039 abe_priv->modem_dai);
1040 if (ret < 0) {
1041 dev_err(abe_priv->modem_dai->dev, "MODEM hw_free failed\n");
1042 return ret;
1043 }
1044 }
1045 return ret;
1046}
1047
1048static void omap_abe_dai_shutdown(struct snd_pcm_substream *substream,
1049 struct snd_soc_dai *dai)
1050{
1051 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
1052
1053 dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);
1054
1055 if (dai->id == ABE_FRONTEND_DAI_MODEM) {
1056 dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d\n",
1057 __func__, substream->stream);
1058
1059 snd_soc_dai_shutdown(abe_priv->modem_substream[substream->stream],
1060 abe_priv->modem_dai);
1061 }
1062}
1063
1064static int omap_abe_dai_probe(struct snd_soc_dai *dai)
1065{
1066 struct omap_abe_data *abe_priv;
1067 int i;
1068
1069 abe_priv = kzalloc(sizeof(struct omap_abe_data), GFP_KERNEL);
1070 if (abe_priv == NULL)
1071 return -ENOMEM;
1072
1073 abe_priv->abe = omap_abe_port_mgr_get();
1074 if (!abe_priv->abe)
1075 goto err;
1076
1077 for (i = 0; i <= OMAP_ABE_MAX_PORT_ID; i++) {
1078
1079 abe_priv->port[i] = omap_abe_port_open(abe_priv->abe, i);
1080 if (abe_priv->port[i] == NULL) {
1081 for (--i; i >= 0; i--)
1082 omap_abe_port_close(abe_priv->abe, abe_priv->port[i]);
1083
1084 goto err_port;
1085 }
1086 }
1087
1088 snd_soc_dai_set_drvdata(dai, abe_priv);
1089 return 0;
1090
1091err_port:
1092 omap_abe_port_mgr_put(abe_priv->abe);
1093err:
1094 kfree(abe_priv);
1095 return -ENOMEM;
1096}
1097
1098static int omap_abe_dai_remove(struct snd_soc_dai *dai)
1099{
1100 struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
1101
1102 omap_abe_port_mgr_put(abe_priv->abe);
1103 kfree(abe_priv);
1104 return 0;
1105}
1106
1107static struct snd_soc_dai_ops omap_abe_dai_ops = {
1108 .startup = omap_abe_dai_startup,
1109 .shutdown = omap_abe_dai_shutdown,
1110 .hw_params = omap_abe_dai_hw_params,
1111 .hw_free = omap_abe_dai_hw_free,
1112 .prepare = omap_abe_dai_prepare,
1113 .trigger = omap_abe_dai_trigger,
1114 .bespoke_trigger = omap_abe_dai_bespoke_trigger,
1115};
1116
1117static struct snd_soc_dai_driver omap_abe_dai[] = {
1118 { /* Multimedia Playback and Capture */
1119 .name = "MultiMedia1",
1120 .probe = omap_abe_dai_probe,
1121 .remove = omap_abe_dai_remove,
1122 .playback = {
1123 .stream_name = "MultiMedia1 Playback",
1124 .channels_min = 1,
1125 .channels_max = 2,
1126 .rates = SNDRV_PCM_RATE_48000,
1127 .formats = OMAP_ABE_FORMATS,
1128 },
1129 .capture = {
1130 .stream_name = "MultiMedia1 Capture",
1131 .channels_min = 2,
1132 .channels_max = 8,
1133 .rates = SNDRV_PCM_RATE_48000,
1134 .formats = OMAP_ABE_FORMATS,
1135 },
1136 .ops = &omap_abe_dai_ops,
1137 },
1138 { /* Multimedia Capture */
1139 .name = "MultiMedia2",
1140 .capture = {
1141 .stream_name = "MultiMedia2 Capture",
1142 .channels_min = 1,
1143 .channels_max = 2,
1144 .rates = SNDRV_PCM_RATE_48000,
1145 .formats = OMAP_ABE_FORMATS,
1146 },
1147 .ops = &omap_abe_dai_ops,
1148 },
1149 { /* Voice Playback and Capture */
1150 .name = "Voice",
1151 .playback = {
1152 .stream_name = "Voice Playback",
1153 .channels_min = 1,
1154 .channels_max = 2,
1155 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1156 .formats = OMAP_ABE_FORMATS,
1157 },
1158 .capture = {
1159 .stream_name = "Voice Capture",
1160 .channels_min = 1,
1161 .channels_max = 2,
1162 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1163 .formats = OMAP_ABE_FORMATS,
1164 },
1165 .ops = &omap_abe_dai_ops,
1166 },
1167 { /* Tones Playback */
1168 .name = "Tones",
1169 .playback = {
1170 .stream_name = "Tones Playback",
1171 .channels_min = 1,
1172 .channels_max = 2,
1173 .rates = SNDRV_PCM_RATE_48000,
1174 .formats = OMAP_ABE_FORMATS,
1175 },
1176 .ops = &omap_abe_dai_ops,
1177 },
1178 { /* Vibra */
1179 .name = "Vibra",
1180 .playback = {
1181 .stream_name = "Vibra Playback",
1182 .channels_min = 2,
1183 .channels_max = 2,
1184 .rates = SNDRV_PCM_RATE_CONTINUOUS,
1185 .formats = OMAP_ABE_FORMATS,
1186 },
1187 .ops = &omap_abe_dai_ops,
1188 },
1189 { /* MODEM Voice Playback and Capture */
1190 .name = "MODEM",
1191 .playback = {
1192 .stream_name = "Voice Playback",
1193 .channels_min = 1,
Francois Mazard0014f452011-06-17 15:07:12 +02001194 .channels_max = 2,
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001195 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1196 .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
1197 },
1198 .capture = {
1199 .stream_name = "Voice Capture",
1200 .channels_min = 1,
Francois Mazard0014f452011-06-17 15:07:12 +02001201 .channels_max = 2,
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001202 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000,
1203 .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
1204 },
1205 .ops = &omap_abe_dai_ops,
1206 },
1207 { /* Low Power HiFi Playback */
1208 .name = "MultiMedia1 LP",
1209 .playback = {
1210 .stream_name = "MultiMedia1 LP Playback",
1211 .channels_min = 2,
1212 .channels_max = 2,
1213 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
1214 .formats = OMAP_ABE_FORMATS | SNDRV_PCM_FMTBIT_S16_LE,
1215 },
1216 .ops = &omap_abe_dai_ops,
1217 },
1218};
1219
1220static int __devinit omap_abe_probe(struct platform_device *pdev)
1221{
1222 return snd_soc_register_dais(&pdev->dev, omap_abe_dai,
1223 ARRAY_SIZE(omap_abe_dai));
1224}
1225
1226static int __devexit omap_abe_remove(struct platform_device *pdev)
1227{
1228 snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(omap_abe_dai));
1229 return 0;
1230}
1231
1232static struct platform_driver omap_abe_driver = {
1233 .driver = {
1234 .name = "omap-abe-dai",
1235 .owner = THIS_MODULE,
1236 },
1237 .probe = omap_abe_probe,
1238 .remove = __devexit_p(omap_abe_remove),
1239};
1240
1241static int __init omap_abe_init(void)
1242{
1243 return platform_driver_register(&omap_abe_driver);
1244}
1245module_init(omap_abe_init);
1246
1247static void __exit omap_abe_exit(void)
1248{
1249 platform_driver_unregister(&omap_abe_driver);
1250}
1251module_exit(omap_abe_exit);
1252
Liam Girdwoode708bea2011-02-03 15:17:26 +00001253MODULE_AUTHOR("Liam Girdwood <lrg@ti.com>");
Liam Girdwoodc60eacc2011-02-03 15:12:22 +00001254MODULE_DESCRIPTION("OMAP ABE SoC Interface");
1255MODULE_LICENSE("GPL");