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