blob: 197811858025b2d0f93808a537e7ac9b258f0c03 [file] [log] [blame]
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -05001/*
2 * sdp4430.c -- SoC audio for TI OMAP4430 SDP
3 *
Liam Girdwood63a06702011-05-01 13:45:18 +01004 * Author: Misael Lopez Cruz <misael.lopez@ti.com>
5 * Liam Girdwood <lrg@ti.com>
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -05006 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#include <linux/clk.h>
24#include <linux/platform_device.h>
Misael Lopez Cruzf4b3dc32011-05-01 21:27:00 -050025#include <linux/mfd/twl6040.h>
26
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050027#include <sound/core.h>
28#include <sound/pcm.h>
Liam Girdwoodede6aa92011-02-07 21:07:48 +000029#include <sound/pcm_params.h>
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050030#include <sound/soc.h>
Liam Girdwoodede6aa92011-02-07 21:07:48 +000031#include <sound/soc-dapm.h>
Jorge Eduardo Candelaria96dc2272010-12-10 20:45:19 -060032#include <sound/jack.h>
Liam Girdwoodede6aa92011-02-07 21:07:48 +000033#include <sound/soc-dsp.h>
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050034
35#include <asm/mach-types.h>
36#include <plat/hardware.h>
37#include <plat/mux.h>
38
Liam Girdwoodede6aa92011-02-07 21:07:48 +000039#include "omap-mcpdm.h"
40#include "omap-abe.h"
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050041#include "omap-pcm.h"
Liam Girdwoodede6aa92011-02-07 21:07:48 +000042#include "omap-mcbsp.h"
43#include "omap-dmic.h"
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050044#include "../codecs/twl6040.h"
45
46static int twl6040_power_mode;
Liam Girdwoodede6aa92011-02-07 21:07:48 +000047static int mcbsp_cfg;
Liam Girdwood8cc57052011-02-07 21:18:06 +000048static struct i2c_client *tps6130x_client;
49static struct i2c_board_info tps6130x_hwmon_info = {
50 I2C_BOARD_INFO("tps6130x", 0x33),
51};
52
53/* configure the TPS6130x Handsfree Boost Converter */
54static int sdp4430_tps6130x_configure(void)
55{
56 u8 data[2];
57
58 data[0] = 0x01;
59 data[1] = 0x60;
60 if (i2c_master_send(tps6130x_client, data, 2) != 2)
61 printk(KERN_ERR "I2C write to TPS6130x failed\n");
62
63 data[0] = 0x02;
64 if (i2c_master_send(tps6130x_client, data, 2) != 2)
65 printk(KERN_ERR "I2C write to TPS6130x failed\n");
66
67 return 0;
68}
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050069
Liam Girdwoodede6aa92011-02-07 21:07:48 +000070static int sdp4430_mcpdm_hw_params(struct snd_pcm_substream *substream,
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050071 struct snd_pcm_hw_params *params)
72{
73 struct snd_soc_pcm_runtime *rtd = substream->private_data;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +000074 struct snd_soc_dai *codec_dai = rtd->codec_dai;
Liam Girdwoodede6aa92011-02-07 21:07:48 +000075 struct snd_soc_pcm_runtime *modem_rtd;
76 struct snd_pcm_substream *modem_substream[2];
77 struct snd_soc_dsp_params *dsp_params;
78 int clk_id, freq, ret, stream = substream->stream;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -050079
80 if (twl6040_power_mode) {
81 clk_id = TWL6040_SYSCLK_SEL_HPPLL;
82 freq = 38400000;
83 } else {
84 clk_id = TWL6040_SYSCLK_SEL_LPPLL;
85 freq = 32768;
86 }
87
88 /* set the codec mclk */
89 ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
90 SND_SOC_CLOCK_IN);
91 if (ret) {
92 printk(KERN_ERR "can't set codec system clock\n");
93 return ret;
94 }
Liam Girdwoodede6aa92011-02-07 21:07:48 +000095 list_for_each_entry(dsp_params, &rtd->dsp[stream].fe_clients, list_fe) {
96
97 if (dsp_params->fe->cpu_dai->id != ABE_FRONTEND_DAI_MODEM)
98 continue;
99
100 if (!mcbsp_cfg) {
101 modem_substream[stream] =
102 snd_soc_get_dai_substream(rtd->card,
103 OMAP_ABE_BE_MM_EXT1,
104 substream->stream);
105 if (modem_substream[stream] == NULL)
106 return -ENODEV;
107
108 modem_rtd = modem_substream[stream]->private_data;
109
110 /* Set cpu DAI configuration */
111 ret = snd_soc_dai_set_fmt(modem_rtd->cpu_dai,
112 SND_SOC_DAIFMT_I2S |
113 SND_SOC_DAIFMT_NB_NF |
114 SND_SOC_DAIFMT_CBM_CFM);
115 mcbsp_cfg = 1;
116 }
117 if (ret < 0) {
118 printk(KERN_ERR "can't set Modem cpu DAI configuration\n");
119 return ret;
120 }
121 }
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000122 return ret;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500123}
124
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000125static struct snd_soc_ops sdp4430_mcpdm_ops = {
126 .hw_params = sdp4430_mcpdm_hw_params,
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500127};
128
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000129static int sdp4430_mcbsp_hw_params(struct snd_pcm_substream *substream,
130 struct snd_pcm_hw_params *params)
131{
132 struct snd_soc_pcm_runtime *rtd = substream->private_data;
133 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
134 int ret = 0;
135 unsigned int be_id;
136
137 be_id = rtd->dai_link->be_id;
138
139 if (be_id == OMAP_ABE_DAI_MM_FM) {
140 /* Set cpu DAI configuration */
141 ret = snd_soc_dai_set_fmt(cpu_dai,
142 SND_SOC_DAIFMT_I2S |
143 SND_SOC_DAIFMT_NB_NF |
144 SND_SOC_DAIFMT_CBM_CFM);
145 } else if (be_id == OMAP_ABE_DAI_BT_VX) {
146 ret = snd_soc_dai_set_fmt(cpu_dai,
147 SND_SOC_DAIFMT_DSP_B |
148 SND_SOC_DAIFMT_NB_IF |
149 SND_SOC_DAIFMT_CBM_CFM);
150 }
151
152 if (ret < 0) {
153 printk(KERN_ERR "can't set cpu DAI configuration\n");
154 return ret;
155 }
156
157 /*
158 * TODO: where does this clock come from (external source??) -
159 * do we need to enable it.
160 */
161 /* Set McBSP clock to external */
162 ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK,
163 64 * params_rate(params),
164 SND_SOC_CLOCK_IN);
165 if (ret < 0) {
166 printk(KERN_ERR "can't set cpu system clock\n");
167 return ret;
168 }
169 return 0;
170}
171
172static struct snd_soc_ops sdp4430_mcbsp_ops = {
173 .hw_params = sdp4430_mcbsp_hw_params,
174};
175
176static int sdp4430_dmic_hw_params(struct snd_pcm_substream *substream,
177 struct snd_pcm_hw_params *params)
178{
179 struct snd_soc_pcm_runtime *rtd = substream->private_data;
180 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
181 int ret = 0;
182
183 ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
184 19200000, SND_SOC_CLOCK_IN);
185 if (ret < 0) {
186 printk(KERN_ERR "can't set DMIC cpu system clock\n");
187 return ret;
188 }
189 ret = snd_soc_dai_set_clkdiv(cpu_dai, OMAP_DMIC_CLKDIV, 8);
190 if (ret < 0) {
191 printk(KERN_ERR "can't set DMIC cpu clock divider\n");
192 return ret;
193 }
194 return 0;
195}
196
197static struct snd_soc_ops sdp4430_dmic_ops = {
198 .hw_params = sdp4430_dmic_hw_params,
199};
200
201static int mcbsp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
202 struct snd_pcm_hw_params *params)
203{
204 struct snd_interval *channels = hw_param_interval(params,
205 SNDRV_PCM_HW_PARAM_CHANNELS);
206 unsigned int be_id = rtd->dai_link->be_id;
207
208 if (be_id == OMAP_ABE_DAI_MM_FM)
209 channels->min = 2;
210 else if (be_id == OMAP_ABE_DAI_BT_VX)
211 channels->min = 1;
212 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
213 SNDRV_PCM_HW_PARAM_FIRST_MASK],
214 SNDRV_PCM_FORMAT_S16_LE);
215 return 0;
216}
217
218static int dmic_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
219 struct snd_pcm_hw_params *params)
220{
221 struct snd_interval *rate = hw_param_interval(params,
222 SNDRV_PCM_HW_PARAM_RATE);
223
224 /* The ABE will covert the FE rate to 96k */
225 rate->min = rate->max = 96000;
226
227 snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
228 SNDRV_PCM_HW_PARAM_FIRST_MASK],
229 SNDRV_PCM_FORMAT_S32_LE);
230 return 0;
231}
232
Jorge Eduardo Candelaria96dc2272010-12-10 20:45:19 -0600233/* Headset jack */
234static struct snd_soc_jack hs_jack;
235
236/*Headset jack detection DAPM pins */
237static struct snd_soc_jack_pin hs_jack_pins[] = {
238 {
239 .pin = "Headset Mic",
240 .mask = SND_JACK_MICROPHONE,
241 },
242 {
243 .pin = "Headset Stereophone",
244 .mask = SND_JACK_HEADPHONE,
245 },
246};
247
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500248static int sdp4430_get_power_mode(struct snd_kcontrol *kcontrol,
249 struct snd_ctl_elem_value *ucontrol)
250{
251 ucontrol->value.integer.value[0] = twl6040_power_mode;
252 return 0;
253}
254
255static int sdp4430_set_power_mode(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_value *ucontrol)
257{
258 if (twl6040_power_mode == ucontrol->value.integer.value[0])
259 return 0;
260
261 twl6040_power_mode = ucontrol->value.integer.value[0];
262
263 return 1;
264}
265
266static const char *power_texts[] = {"Low-Power", "High-Performance"};
267
268static const struct soc_enum sdp4430_enum[] = {
269 SOC_ENUM_SINGLE_EXT(2, power_texts),
270};
271
272static const struct snd_kcontrol_new sdp4430_controls[] = {
273 SOC_ENUM_EXT("TWL6040 Power Mode", sdp4430_enum[0],
274 sdp4430_get_power_mode, sdp4430_set_power_mode),
275};
276
277/* SDP4430 machine DAPM */
278static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
279 SND_SOC_DAPM_MIC("Ext Mic", NULL),
280 SND_SOC_DAPM_SPK("Ext Spk", NULL),
281 SND_SOC_DAPM_MIC("Headset Mic", NULL),
282 SND_SOC_DAPM_HP("Headset Stereophone", NULL),
Jorge Eduardo Candelaria7254e2b2010-05-18 12:44:17 -0500283 SND_SOC_DAPM_SPK("Earphone Spk", NULL),
Jorge Eduardo Candelaria23ac3b62010-12-08 10:55:05 -0600284 SND_SOC_DAPM_INPUT("Aux/FM Stereo In"),
Misael Lopez Cruz685a4732011-04-25 20:23:20 -0500285 SND_SOC_DAPM_MIC("Digital Mic 0", NULL),
286 SND_SOC_DAPM_MIC("Digital Mic 1", NULL),
287 SND_SOC_DAPM_MIC("Digital Mic 2", NULL),
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500288};
289
290static const struct snd_soc_dapm_route audio_map[] = {
291 /* External Mics: MAINMIC, SUBMIC with bias*/
292 {"MAINMIC", NULL, "Main Mic Bias"},
293 {"SUBMIC", NULL, "Main Mic Bias"},
294 {"Main Mic Bias", NULL, "Ext Mic"},
295
296 /* External Speakers: HFL, HFR */
297 {"Ext Spk", NULL, "HFL"},
298 {"Ext Spk", NULL, "HFR"},
299
300 /* Headset Mic: HSMIC with bias */
301 {"HSMIC", NULL, "Headset Mic Bias"},
302 {"Headset Mic Bias", NULL, "Headset Mic"},
303
304 /* Headset Stereophone (Headphone): HSOL, HSOR */
305 {"Headset Stereophone", NULL, "HSOL"},
306 {"Headset Stereophone", NULL, "HSOR"},
Jorge Eduardo Candelaria7254e2b2010-05-18 12:44:17 -0500307
308 /* Earphone speaker */
309 {"Earphone Spk", NULL, "EP"},
Jorge Eduardo Candelaria23ac3b62010-12-08 10:55:05 -0600310
311 /* Aux/FM Stereo In: AFML, AFMR */
312 {"AFML", NULL, "Aux/FM Stereo In"},
313 {"AFMR", NULL, "Aux/FM Stereo In"},
Misael Lopez Cruz685a4732011-04-25 20:23:20 -0500314
315 /* Digital Mics: DMic0, DMic1, DMic2 with bias */
316 {"DMIC0", NULL, "Digital Mic1 Bias"},
317 {"Digital Mic1 Bias", NULL, "Digital Mic 0"},
318
319 {"DMIC1", NULL, "Digital Mic1 Bias"},
320 {"Digital Mic1 Bias", NULL, "Digital Mic 1"},
321
322 {"DMIC2", NULL, "Digital Mic1 Bias"},
323 {"Digital Mic1 Bias", NULL, "Digital Mic 2"},
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500324};
325
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000326static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500327{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000328 struct snd_soc_codec *codec = rtd->codec;
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200329 struct snd_soc_dapm_context *dapm = &codec->dapm;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500330 int ret;
331
332 /* Add SDP4430 specific controls */
333 ret = snd_soc_add_controls(codec, sdp4430_controls,
334 ARRAY_SIZE(sdp4430_controls));
335 if (ret)
336 return ret;
337
338 /* Add SDP4430 specific widgets */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200339 ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500340 ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
341 if (ret)
342 return ret;
343
344 /* Set up SDP4430 specific audio path audio_map */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200345 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500346
347 /* SDP4430 connected pins */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200348 snd_soc_dapm_enable_pin(dapm, "Ext Mic");
349 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
Jorge Eduardo Candelaria23ac3b62010-12-08 10:55:05 -0600350 snd_soc_dapm_enable_pin(dapm, "AFML");
351 snd_soc_dapm_enable_pin(dapm, "AFMR");
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200352 snd_soc_dapm_enable_pin(dapm, "Headset Mic");
353 snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500354
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000355 /* allow audio paths from the audio modem to run during suspend */
356 snd_soc_dapm_ignore_suspend(dapm, "Ext Mic");
357 snd_soc_dapm_ignore_suspend(dapm, "Ext Spk");
358 snd_soc_dapm_ignore_suspend(dapm, "AFML");
359 snd_soc_dapm_ignore_suspend(dapm, "AFMR");
360 snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
361 snd_soc_dapm_ignore_suspend(dapm, "Headset Stereophone");
Misael Lopez Cruz685a4732011-04-25 20:23:20 -0500362 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 0");
363 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 1");
364 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 2");
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000365
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200366 ret = snd_soc_dapm_sync(dapm);
Jorge Eduardo Candelaria96dc2272010-12-10 20:45:19 -0600367 if (ret)
368 return ret;
369
370 /* Headset jack detection */
371 ret = snd_soc_jack_new(codec, "Headset Jack",
372 SND_JACK_HEADSET, &hs_jack);
373 if (ret)
374 return ret;
375
376 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
377 hs_jack_pins);
378
379 if (machine_is_omap_4430sdp())
380 twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
381 else
382 snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500383
384 return ret;
385}
386
Misael Lopez Cruz47415f02011-04-27 23:56:32 -0500387/* SDP4430 digital microphones DAPM */
388static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
389 SND_SOC_DAPM_MIC("Digital Mic Legacy", NULL),
390};
391
392static const struct snd_soc_dapm_route dmic_audio_map[] = {
393 {"DMic", NULL, "Digital Mic1 Bias"},
394 {"Digital Mic1 Bias", NULL, "Digital Mic Legacy"},
395};
396
397static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
398{
399 struct snd_soc_codec *codec = rtd->codec;
400 struct snd_soc_dapm_context *dapm = &codec->dapm;
401 int ret;
402
403 ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
404 ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
405 if (ret)
406 return ret;
407
408 ret = snd_soc_dapm_add_routes(dapm, dmic_audio_map,
409 ARRAY_SIZE(dmic_audio_map));
410 if (ret)
411 return ret;
412
413 snd_soc_dapm_enable_pin(dapm, "Digital Mic Legacy");
414
415 ret = snd_soc_dapm_sync(dapm);
416
417 return ret;
418}
419
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000420/* TODO: make this a separate BT CODEC driver or DUMMY */
421static struct snd_soc_dai_driver dai[] = {
422{
423 .name = "Bluetooth",
424 .playback = {
425 .stream_name = "Playback",
426 .channels_min = 1,
427 .channels_max = 2,
428 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
429 SNDRV_PCM_RATE_48000,
430 .formats = SNDRV_PCM_FMTBIT_S16_LE,
431 },
432 .capture = {
433 .stream_name = "Capture",
434 .channels_min = 1,
435 .channels_max = 2,
436 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
437 SNDRV_PCM_RATE_48000,
438 .formats = SNDRV_PCM_FMTBIT_S16_LE,
439 },
440},
441/* TODO: make this a separate FM CODEC driver or DUMMY */
442{
443 .name = "FM Digital",
444 .playback = {
445 .stream_name = "Playback",
446 .channels_min = 1,
447 .channels_max = 2,
448 .rates = SNDRV_PCM_RATE_48000,
449 .formats = SNDRV_PCM_FMTBIT_S16_LE,
450 },
451 .capture = {
452 .stream_name = "Capture",
453 .channels_min = 1,
454 .channels_max = 2,
455 .rates = SNDRV_PCM_RATE_48000,
456 .formats = SNDRV_PCM_FMTBIT_S16_LE,
457 },
458},
459{
460 .name = "HDMI",
461 .playback = {
462 .stream_name = "Playback",
463 .channels_min = 2,
464 .channels_max = 8,
465 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
466 SNDRV_PCM_RATE_48000,
467 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
468 },
469},
470};
471
472static const char *mm1_be[] = {
473 OMAP_ABE_BE_PDM_DL1,
474 OMAP_ABE_BE_PDM_UL1,
475 OMAP_ABE_BE_PDM_DL2,
476 OMAP_ABE_BE_BT_VX,
477 OMAP_ABE_BE_MM_EXT0,
478 OMAP_ABE_BE_DMIC0,
479 OMAP_ABE_BE_DMIC1,
480 OMAP_ABE_BE_DMIC2,
481};
482
483struct snd_soc_dsp_link fe_media = {
484 .supported_be = mm1_be,
485 .num_be = ARRAY_SIZE(mm1_be),
486 .fe_playback_channels = 2,
487 .fe_capture_channels = 8,
488 .trigger =
489 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
490};
491
492static const char *mm2_be[] = {
493 OMAP_ABE_BE_PDM_UL1,
494 OMAP_ABE_BE_BT_VX,
495 OMAP_ABE_BE_MM_EXT0,
496 OMAP_ABE_BE_DMIC0,
497 OMAP_ABE_BE_DMIC1,
498 OMAP_ABE_BE_DMIC2,
499};
500
501struct snd_soc_dsp_link fe_media_capture = {
502 .supported_be = mm2_be,
503 .num_be = ARRAY_SIZE(mm2_be),
504 .fe_capture_channels = 8,
505 .trigger =
506 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
507};
508
509static const char *tones_be[] = {
510 OMAP_ABE_BE_PDM_DL1,
511 OMAP_ABE_BE_PDM_DL2,
512 OMAP_ABE_BE_BT_VX,
513 OMAP_ABE_BE_MM_EXT0,
514};
515
516struct snd_soc_dsp_link fe_tones = {
517 .supported_be = tones_be,
518 .num_be = ARRAY_SIZE(tones_be),
519 .fe_playback_channels = 2,
520 .trigger =
521 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
522};
523
524static const char *vib_be[] = {
525 OMAP_ABE_BE_PDM_VIB,
526};
527
528struct snd_soc_dsp_link fe_vib = {
529 .supported_be = vib_be,
530 .num_be = ARRAY_SIZE(vib_be),
531 .fe_playback_channels = 2,
532 .trigger =
533 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
534};
535
536static const char *modem_be[] = {
537 OMAP_ABE_BE_PDM_DL1,
538 OMAP_ABE_BE_PDM_UL1,
539 OMAP_ABE_BE_PDM_DL2,
540 OMAP_ABE_BE_BT_VX,
541 OMAP_ABE_BE_DMIC0,
542 OMAP_ABE_BE_DMIC1,
543 OMAP_ABE_BE_DMIC2,
544};
545
546struct snd_soc_dsp_link fe_modem = {
547 .supported_be = modem_be,
548 .num_be = ARRAY_SIZE(modem_be),
549 .fe_playback_channels = 2,
550 .fe_capture_channels = 2,
551 .trigger =
552 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
553};
554
555static const char *mm_lp_be[] = {
556 OMAP_ABE_BE_PDM_DL1,
557 OMAP_ABE_BE_PDM_DL2,
558 OMAP_ABE_BE_BT_VX,
559 OMAP_ABE_BE_MM_EXT0,
560};
561
562struct snd_soc_dsp_link fe_lp_media = {
563 .supported_be = mm_lp_be,
564 .num_be = ARRAY_SIZE(mm_lp_be),
565 .fe_playback_channels = 2,
566 .trigger =
567 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
568};
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500569/* Digital audio interface glue - connects codec <--> CPU */
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000570static struct snd_soc_dai_link sdp4430_dai[] = {
571
572/*
573 * Frontend DAIs - i.e. userspace visible interfaces (ALSA PCMs)
574 */
575
576 {
577 .name = "SDP4430 Media",
578 .stream_name = "Multimedia",
579
580 /* ABE components - MM-UL & MM_DL */
581 .cpu_dai_name = "MultiMedia1",
582 .platform_name = "omap-pcm-audio",
583
584 .dynamic = 1, /* BE is dynamic */
585 .dsp_link = &fe_media,
586 },
587 {
588 .name = "SDP4430 Media Capture",
589 .stream_name = "Multimedia Capture",
590
591 /* ABE components - MM-UL2 */
592 .cpu_dai_name = "MultiMedia2",
593 .platform_name = "omap-pcm-audio",
594
595 .dynamic = 1, /* BE is dynamic */
596 .dsp_link = &fe_media_capture,
597 },
598 {
599 .name = "SDP4430 Voice",
600 .stream_name = "Voice",
601
602 /* ABE components - VX-UL & VX-DL */
603 .cpu_dai_name = "Voice",
604 .platform_name = "omap-pcm-audio",
605
606 .dynamic = 1, /* BE is dynamic */
607 .dsp_link = &fe_media,
608 .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST,
609 },
610 {
611 .name = "SDP4430 Tones Playback",
612 .stream_name = "Tone Playback",
613
614 /* ABE components - TONES_DL */
615 .cpu_dai_name = "Tones",
616 .platform_name = "omap-pcm-audio",
617
618 .dynamic = 1, /* BE is dynamic */
619 .dsp_link = &fe_tones,
620 },
621 {
622 .name = "SDP4430 Vibra Playback",
623 .stream_name = "VIB-DL",
624
625 /* ABE components - DMIC UL 2 */
626 .cpu_dai_name = "Vibra",
627 .platform_name = "omap-pcm-audio",
628
629 .dynamic = 1, /* BE is dynamic */
630 .dsp_link = &fe_vib,
631 },
632 {
633 .name = "SDP4430 MODEM",
634 .stream_name = "MODEM",
635
636 /* ABE components - MODEM <-> McBSP2 */
637 .cpu_dai_name = "MODEM",
638 .platform_name = "aess",
639
640 .dynamic = 1, /* BE is dynamic */
641 .dsp_link = &fe_modem,
642 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
643 .ignore_suspend = 1,
644 },
645 {
646 .name = "SDP4430 Media LP",
647 .stream_name = "Multimedia",
648
649 /* ABE components - MM-DL (mmap) */
650 .cpu_dai_name = "MultiMedia1 LP",
651 .platform_name = "aess",
652
653 .dynamic = 1, /* BE is dynamic */
654 .dsp_link = &fe_lp_media,
655 },
656 {
657 .name = "Legacy McBSP",
658 .stream_name = "Multimedia",
659
660 /* ABE components - MCBSP2 - MM-EXT */
661 .cpu_dai_name = "omap-mcbsp-dai.1",
662 .platform_name = "omap-pcm-audio",
663
664 /* FM */
665 .codec_dai_name = "FM Digital",
666
667 .no_codec = 1, /* TODO: have a dummy CODEC */
668 .ops = &sdp4430_mcbsp_ops,
669 },
670 {
671 .name = "Legacy McPDM",
672 .stream_name = "Headset Playback",
673
674 /* ABE components - DL1 */
675 .cpu_dai_name = "mcpdm-dl",
676 .platform_name = "omap-pcm-audio",
677
678 /* Phoenix - DL1 DAC */
679 .codec_dai_name = "twl6040-dl1",
680 .codec_name = "twl6040-codec",
681
682 .ops = &sdp4430_mcpdm_ops,
683 },
684 {
685 .name = "Legacy DMIC",
686 .stream_name = "DMIC Capture",
687
688 /* ABE components - DMIC0 */
689 .cpu_dai_name = "omap-dmic-dai-0",
690 .platform_name = "omap-pcm-audio",
691
692 /* DMIC codec */
693 .codec_dai_name = "dmic-hifi",
694 .codec_name = "dmic-codec.0",
695
Misael Lopez Cruz47415f02011-04-27 23:56:32 -0500696 .init = sdp4430_dmic_init,
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000697 .ops = &sdp4430_dmic_ops,
698 },
699
700/*
701 * Backend DAIs - i.e. dynamically matched interfaces, invisible to userspace.
702 * Matched to above interfaces at runtime, based upon use case.
703 */
704
705 {
706 .name = OMAP_ABE_BE_PDM_DL1,
707 .stream_name = "HS Playback",
708
709 /* ABE components - DL1 */
710 .cpu_dai_name = "mcpdm-dl1",
711 .platform_name = "aess",
712
713 /* Phoenix - DL1 DAC */
714 .codec_dai_name = "twl6040-dl1",
715 .codec_name = "twl6040-codec",
716
717 .no_pcm = 1, /* don't create ALSA pcm for this */
718 .init = sdp4430_twl6040_init,
719 .ops = &sdp4430_mcpdm_ops,
720 .be_id = OMAP_ABE_DAI_PDM_DL1,
721 },
722 {
723 .name = OMAP_ABE_BE_PDM_UL1,
724 .stream_name = "Analog Capture",
725
726 /* ABE components - UL1 */
727 .cpu_dai_name = "mcpdm-ul1",
728 .platform_name = "aess",
729
730 /* Phoenix - UL ADC */
731 .codec_dai_name = "twl6040-ul",
732 .codec_name = "twl6040-codec",
733
734 .no_pcm = 1, /* don't create ALSA pcm for this */
735 .ops = &sdp4430_mcpdm_ops,
736 .be_id = OMAP_ABE_DAI_PDM_UL,
737 },
738 {
739 .name = OMAP_ABE_BE_PDM_DL2,
740 .stream_name = "HF Playback",
741
742 /* ABE components - DL2 */
743 .cpu_dai_name = "mcpdm-dl2",
744 .platform_name = "aess",
745
746 /* Phoenix - DL2 DAC */
747 .codec_dai_name = "twl6040-dl2",
748 .codec_name = "twl6040-codec",
749
750 .no_pcm = 1, /* don't create ALSA pcm for this */
751 .ops = &sdp4430_mcpdm_ops,
752 .be_id = OMAP_ABE_DAI_PDM_DL2,
753 },
754 {
755 .name = OMAP_ABE_BE_PDM_VIB,
756 .stream_name = "Vibra",
757
758 /* ABE components - VIB1 DL */
759 .cpu_dai_name = "mcpdm-vib",
760 .platform_name = "aess",
761
762 /* Phoenix - PDM to PWM */
763 .codec_dai_name = "twl6040-vib",
764 .codec_name = "twl6040-codec",
765
766 .no_pcm = 1, /* don't create ALSA pcm for this */
767 .ops = &sdp4430_mcpdm_ops,
768 .be_id = OMAP_ABE_DAI_PDM_VIB,
769 },
770 {
771 .name = OMAP_ABE_BE_BT_VX,
772 .stream_name = "BT",
773
774 /* ABE components - MCBSP1 - BT-VX */
775 .cpu_dai_name = "omap-mcbsp-dai.0",
776 .platform_name = "aess",
777
778 /* Bluetooth */
779 .codec_dai_name = "Bluetooth",
780
781 .no_pcm = 1, /* don't create ALSA pcm for this */
782 .no_codec = 1, /* TODO: have a dummy CODEC */
783 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
784 .ops = &sdp4430_mcbsp_ops,
785 .be_id = OMAP_ABE_DAI_BT_VX,
786 },
787 {
788 .name = OMAP_ABE_BE_MM_EXT0,
789 .stream_name = "FM",
790
791 /* ABE components - MCBSP2 - MM-EXT */
792 .cpu_dai_name = "omap-mcbsp-dai.1",
793 .platform_name = "aess",
794
795 /* FM */
796 .codec_dai_name = "FM Digital",
797
798 .no_pcm = 1, /* don't create ALSA pcm for this */
799 .no_codec = 1, /* TODO: have a dummy CODEC */
800 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
801 .ops = &sdp4430_mcbsp_ops,
802 .be_id = OMAP_ABE_DAI_MM_FM,
803 },
804 {
805 .name = OMAP_ABE_BE_MM_EXT1,
806 .stream_name = "MODEM",
807
808 /* ABE components - MCBSP2 - MM-EXT */
809 .cpu_dai_name = "omap-mcbsp-dai.1",
810 .platform_name = "aess",
811
812 /* MODEM */
813 .codec_dai_name = "MODEM",
814
815 .no_pcm = 1, /* don't create ALSA pcm for this */
816 .no_codec = 1, /* TODO: have a dummy CODEC */
817 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
818 .ops = &sdp4430_mcbsp_ops,
819 .be_id = OMAP_ABE_DAI_MODEM,
820 .ignore_suspend = 1,
821 },
822 {
823 .name = OMAP_ABE_BE_DMIC0,
824 .stream_name = "DMIC0",
825
826 /* ABE components - DMIC UL 1 */
827 .cpu_dai_name = "omap-dmic-abe-dai-0",
828 .platform_name = "aess",
829
830 /* DMIC 0 */
831 .codec_dai_name = "dmic-hifi",
832 .codec_name = "dmic-codec.0",
833 .ops = &sdp4430_dmic_ops,
834
835 .no_pcm = 1, /* don't create ALSA pcm for this */
836 .be_hw_params_fixup = dmic_be_hw_params_fixup,
837 .be_id = OMAP_ABE_DAI_DMIC0,
838 },
839 {
840 .name = OMAP_ABE_BE_DMIC1,
841 .stream_name = "DMIC1",
842
843 /* ABE components - DMIC UL 1 */
844 .cpu_dai_name = "omap-dmic-abe-dai-1",
845 .platform_name = "aess",
846
847 /* DMIC 1 */
848 .codec_dai_name = "dmic-hifi",
849 .codec_name = "dmic-codec.1",
850 .ops = &sdp4430_dmic_ops,
851
852 .no_pcm = 1, /* don't create ALSA pcm for this */
853 .be_hw_params_fixup = dmic_be_hw_params_fixup,
854 .be_id = OMAP_ABE_DAI_DMIC1,
855 },
856 {
857 .name = OMAP_ABE_BE_DMIC2,
858 .stream_name = "DMIC2",
859
860 /* ABE components - DMIC UL 2 */
861 .cpu_dai_name = "omap-dmic-abe-dai-2",
862 .platform_name = "aess",
863
864 /* DMIC 2 */
865 .codec_dai_name = "dmic-hifi",
866 .codec_name = "dmic-codec.2",
867 .ops = &sdp4430_dmic_ops,
868
869 .no_pcm = 1, /* don't create ALSA pcm for this */
870 .be_hw_params_fixup = dmic_be_hw_params_fixup,
871 .be_id = OMAP_ABE_DAI_DMIC2,
872 },
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500873};
874
875/* Audio machine driver */
876static struct snd_soc_card snd_soc_sdp4430 = {
Liam Girdwood62e16e82011-02-07 21:09:59 +0000877 .driver_name = "OMAP4",
878 .long_name = "TI OMAP4 Board",
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000879 .dai_link = sdp4430_dai,
880 .num_links = ARRAY_SIZE(sdp4430_dai),
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500881};
882
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500883static struct platform_device *sdp4430_snd_device;
Liam Girdwood8cc57052011-02-07 21:18:06 +0000884static struct i2c_adapter *adapter;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500885
886static int __init sdp4430_soc_init(void)
887{
888 int ret;
889
Liam Girdwood62e16e82011-02-07 21:09:59 +0000890 if (!machine_is_omap_4430sdp() && !machine_is_omap4_panda()) {
891 pr_debug("Not SDP4430 or PandaBoard!\n");
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500892 return -ENODEV;
Liam Girdwood62e16e82011-02-07 21:09:59 +0000893 }
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500894 printk(KERN_INFO "SDP4430 SoC init\n");
Liam Girdwood62e16e82011-02-07 21:09:59 +0000895 if (machine_is_omap_4430sdp())
896 snd_soc_sdp4430.name = "SDP4430";
897 else if (machine_is_omap4_panda())
898 snd_soc_sdp4430.name = "Panda";
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500899
900 sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
901 if (!sdp4430_snd_device) {
902 printk(KERN_ERR "Platform device allocation failed\n");
903 return -ENOMEM;
904 }
905
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000906 ret = snd_soc_register_dais(&sdp4430_snd_device->dev, dai, ARRAY_SIZE(dai));
907 if (ret < 0)
Liam Girdwood8cc57052011-02-07 21:18:06 +0000908 goto err_dai;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000909 platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500910
911 ret = platform_device_add(sdp4430_snd_device);
912 if (ret)
Liam Girdwood8cc57052011-02-07 21:18:06 +0000913 goto err_dev;
914
915 adapter = i2c_get_adapter(1);
916 if (!adapter) {
917 printk(KERN_ERR "can't get i2c adapter\n");
918 ret = -ENODEV;
919 goto err_adap;
920 }
921
922 tps6130x_client = i2c_new_device(adapter, &tps6130x_hwmon_info);
923 if (!tps6130x_client) {
924 printk(KERN_ERR "can't add i2c device\n");
925 ret = -ENODEV;
926 goto err_i2c;
927 }
928
929 /* Only configure the TPS6130x on SDP4430 */
930 if (machine_is_omap_4430sdp())
931 sdp4430_tps6130x_configure();
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500932
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500933 return 0;
934
Liam Girdwood8cc57052011-02-07 21:18:06 +0000935err_i2c:
936 i2c_put_adapter(adapter);
937err_adap:
938 platform_device_del(sdp4430_snd_device);
939err_dev:
940 snd_soc_unregister_dais(&sdp4430_snd_device->dev, ARRAY_SIZE(dai));
941err_dai:
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500942 platform_device_put(sdp4430_snd_device);
943 return ret;
944}
945module_init(sdp4430_soc_init);
946
947static void __exit sdp4430_soc_exit(void)
948{
949 platform_device_unregister(sdp4430_snd_device);
Liam Girdwood8cc57052011-02-07 21:18:06 +0000950 snd_soc_unregister_dais(&sdp4430_snd_device->dev, ARRAY_SIZE(dai));
951 i2c_unregister_device(tps6130x_client);
952 i2c_put_adapter(adapter);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500953}
954module_exit(sdp4430_soc_exit);
955
956MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
957MODULE_DESCRIPTION("ALSA SoC SDP4430");
958MODULE_LICENSE("GPL");
959