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