blob: 0581685cfac8f9c9feca9c6a1e9027b21dcafc1f [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 Cruz685a4732011-04-25 20:23:20 -0500284 SND_SOC_DAPM_MIC("Digital Mic 0", NULL),
285 SND_SOC_DAPM_MIC("Digital Mic 1", NULL),
286 SND_SOC_DAPM_MIC("Digital Mic 2", NULL),
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500287};
288
289static const struct snd_soc_dapm_route audio_map[] = {
290 /* External Mics: MAINMIC, SUBMIC with bias*/
291 {"MAINMIC", NULL, "Main Mic Bias"},
292 {"SUBMIC", NULL, "Main Mic Bias"},
293 {"Main Mic Bias", NULL, "Ext Mic"},
294
295 /* External Speakers: HFL, HFR */
296 {"Ext Spk", NULL, "HFL"},
297 {"Ext Spk", NULL, "HFR"},
298
299 /* Headset Mic: HSMIC with bias */
300 {"HSMIC", NULL, "Headset Mic Bias"},
301 {"Headset Mic Bias", NULL, "Headset Mic"},
302
303 /* Headset Stereophone (Headphone): HSOL, HSOR */
304 {"Headset Stereophone", NULL, "HSOL"},
305 {"Headset Stereophone", NULL, "HSOR"},
Jorge Eduardo Candelaria7254e2b2010-05-18 12:44:17 -0500306
307 /* Earphone speaker */
308 {"Earphone Spk", NULL, "EP"},
Jorge Eduardo Candelaria23ac3b62010-12-08 10:55:05 -0600309
310 /* Aux/FM Stereo In: AFML, AFMR */
311 {"AFML", NULL, "Aux/FM Stereo In"},
312 {"AFMR", NULL, "Aux/FM Stereo In"},
Misael Lopez Cruz685a4732011-04-25 20:23:20 -0500313
314 /* Digital Mics: DMic0, DMic1, DMic2 with bias */
315 {"DMIC0", NULL, "Digital Mic1 Bias"},
316 {"Digital Mic1 Bias", NULL, "Digital Mic 0"},
317
318 {"DMIC1", NULL, "Digital Mic1 Bias"},
319 {"Digital Mic1 Bias", NULL, "Digital Mic 1"},
320
321 {"DMIC2", NULL, "Digital Mic1 Bias"},
322 {"Digital Mic1 Bias", NULL, "Digital Mic 2"},
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500323};
324
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000325static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500326{
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000327 struct snd_soc_codec *codec = rtd->codec;
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200328 struct snd_soc_dapm_context *dapm = &codec->dapm;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500329 int ret;
330
331 /* Add SDP4430 specific controls */
332 ret = snd_soc_add_controls(codec, sdp4430_controls,
333 ARRAY_SIZE(sdp4430_controls));
334 if (ret)
335 return ret;
336
337 /* Add SDP4430 specific widgets */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200338 ret = snd_soc_dapm_new_controls(dapm, sdp4430_twl6040_dapm_widgets,
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500339 ARRAY_SIZE(sdp4430_twl6040_dapm_widgets));
340 if (ret)
341 return ret;
342
343 /* Set up SDP4430 specific audio path audio_map */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200344 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500345
346 /* SDP4430 connected pins */
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200347 snd_soc_dapm_enable_pin(dapm, "Ext Mic");
348 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
Jorge Eduardo Candelaria23ac3b62010-12-08 10:55:05 -0600349 snd_soc_dapm_enable_pin(dapm, "AFML");
350 snd_soc_dapm_enable_pin(dapm, "AFMR");
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200351 snd_soc_dapm_enable_pin(dapm, "Headset Mic");
352 snd_soc_dapm_enable_pin(dapm, "Headset Stereophone");
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500353
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000354 /* allow audio paths from the audio modem to run during suspend */
355 snd_soc_dapm_ignore_suspend(dapm, "Ext Mic");
356 snd_soc_dapm_ignore_suspend(dapm, "Ext Spk");
357 snd_soc_dapm_ignore_suspend(dapm, "AFML");
358 snd_soc_dapm_ignore_suspend(dapm, "AFMR");
359 snd_soc_dapm_ignore_suspend(dapm, "Headset Mic");
360 snd_soc_dapm_ignore_suspend(dapm, "Headset Stereophone");
Misael Lopez Cruz685a4732011-04-25 20:23:20 -0500361 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 0");
362 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 1");
363 snd_soc_dapm_ignore_suspend(dapm, "Digital Mic 2");
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000364
Liam Girdwoodce6120c2010-11-05 15:53:46 +0200365 ret = snd_soc_dapm_sync(dapm);
Jorge Eduardo Candelaria96dc2272010-12-10 20:45:19 -0600366 if (ret)
367 return ret;
368
369 /* Headset jack detection */
370 ret = snd_soc_jack_new(codec, "Headset Jack",
371 SND_JACK_HEADSET, &hs_jack);
372 if (ret)
373 return ret;
374
375 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
376 hs_jack_pins);
377
378 if (machine_is_omap_4430sdp())
379 twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
380 else
381 snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500382
383 return ret;
384}
385
Misael Lopez Cruz47415f02011-04-27 23:56:32 -0500386/* SDP4430 digital microphones DAPM */
387static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
388 SND_SOC_DAPM_MIC("Digital Mic Legacy", NULL),
389};
390
391static const struct snd_soc_dapm_route dmic_audio_map[] = {
392 {"DMic", NULL, "Digital Mic1 Bias"},
393 {"Digital Mic1 Bias", NULL, "Digital Mic Legacy"},
394};
395
396static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
397{
398 struct snd_soc_codec *codec = rtd->codec;
399 struct snd_soc_dapm_context *dapm = &codec->dapm;
400 int ret;
401
402 ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
403 ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
404 if (ret)
405 return ret;
406
407 ret = snd_soc_dapm_add_routes(dapm, dmic_audio_map,
408 ARRAY_SIZE(dmic_audio_map));
409 if (ret)
410 return ret;
411
412 snd_soc_dapm_enable_pin(dapm, "Digital Mic Legacy");
413
414 ret = snd_soc_dapm_sync(dapm);
415
416 return ret;
417}
418
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000419/* TODO: make this a separate BT CODEC driver or DUMMY */
420static struct snd_soc_dai_driver dai[] = {
421{
422 .name = "Bluetooth",
423 .playback = {
424 .stream_name = "Playback",
425 .channels_min = 1,
426 .channels_max = 2,
427 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
428 SNDRV_PCM_RATE_48000,
429 .formats = SNDRV_PCM_FMTBIT_S16_LE,
430 },
431 .capture = {
432 .stream_name = "Capture",
433 .channels_min = 1,
434 .channels_max = 2,
435 .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |
436 SNDRV_PCM_RATE_48000,
437 .formats = SNDRV_PCM_FMTBIT_S16_LE,
438 },
439},
440/* TODO: make this a separate FM CODEC driver or DUMMY */
441{
442 .name = "FM Digital",
443 .playback = {
444 .stream_name = "Playback",
445 .channels_min = 1,
446 .channels_max = 2,
447 .rates = SNDRV_PCM_RATE_48000,
448 .formats = SNDRV_PCM_FMTBIT_S16_LE,
449 },
450 .capture = {
451 .stream_name = "Capture",
452 .channels_min = 1,
453 .channels_max = 2,
454 .rates = SNDRV_PCM_RATE_48000,
455 .formats = SNDRV_PCM_FMTBIT_S16_LE,
456 },
457},
458{
459 .name = "HDMI",
460 .playback = {
461 .stream_name = "Playback",
462 .channels_min = 2,
463 .channels_max = 8,
464 .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
465 SNDRV_PCM_RATE_48000,
466 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
467 },
468},
469};
470
471static const char *mm1_be[] = {
472 OMAP_ABE_BE_PDM_DL1,
473 OMAP_ABE_BE_PDM_UL1,
474 OMAP_ABE_BE_PDM_DL2,
475 OMAP_ABE_BE_BT_VX,
476 OMAP_ABE_BE_MM_EXT0,
477 OMAP_ABE_BE_DMIC0,
478 OMAP_ABE_BE_DMIC1,
479 OMAP_ABE_BE_DMIC2,
480};
481
482struct snd_soc_dsp_link fe_media = {
483 .supported_be = mm1_be,
484 .num_be = ARRAY_SIZE(mm1_be),
485 .fe_playback_channels = 2,
486 .fe_capture_channels = 8,
487 .trigger =
488 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
489};
490
491static const char *mm2_be[] = {
492 OMAP_ABE_BE_PDM_UL1,
493 OMAP_ABE_BE_BT_VX,
494 OMAP_ABE_BE_MM_EXT0,
495 OMAP_ABE_BE_DMIC0,
496 OMAP_ABE_BE_DMIC1,
497 OMAP_ABE_BE_DMIC2,
498};
499
500struct snd_soc_dsp_link fe_media_capture = {
501 .supported_be = mm2_be,
502 .num_be = ARRAY_SIZE(mm2_be),
503 .fe_capture_channels = 8,
504 .trigger =
505 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
506};
507
508static const char *tones_be[] = {
509 OMAP_ABE_BE_PDM_DL1,
510 OMAP_ABE_BE_PDM_DL2,
511 OMAP_ABE_BE_BT_VX,
512 OMAP_ABE_BE_MM_EXT0,
513};
514
515struct snd_soc_dsp_link fe_tones = {
516 .supported_be = tones_be,
517 .num_be = ARRAY_SIZE(tones_be),
518 .fe_playback_channels = 2,
519 .trigger =
520 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
521};
522
523static const char *vib_be[] = {
524 OMAP_ABE_BE_PDM_VIB,
525};
526
527struct snd_soc_dsp_link fe_vib = {
528 .supported_be = vib_be,
529 .num_be = ARRAY_SIZE(vib_be),
530 .fe_playback_channels = 2,
531 .trigger =
532 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
533};
534
535static const char *modem_be[] = {
536 OMAP_ABE_BE_PDM_DL1,
537 OMAP_ABE_BE_PDM_UL1,
538 OMAP_ABE_BE_PDM_DL2,
539 OMAP_ABE_BE_BT_VX,
540 OMAP_ABE_BE_DMIC0,
541 OMAP_ABE_BE_DMIC1,
542 OMAP_ABE_BE_DMIC2,
543};
544
545struct snd_soc_dsp_link fe_modem = {
546 .supported_be = modem_be,
547 .num_be = ARRAY_SIZE(modem_be),
548 .fe_playback_channels = 2,
549 .fe_capture_channels = 2,
550 .trigger =
551 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
552};
553
554static const char *mm_lp_be[] = {
555 OMAP_ABE_BE_PDM_DL1,
556 OMAP_ABE_BE_PDM_DL2,
557 OMAP_ABE_BE_BT_VX,
558 OMAP_ABE_BE_MM_EXT0,
559};
560
561struct snd_soc_dsp_link fe_lp_media = {
562 .supported_be = mm_lp_be,
563 .num_be = ARRAY_SIZE(mm_lp_be),
564 .fe_playback_channels = 2,
565 .trigger =
566 {SND_SOC_DSP_TRIGGER_BESPOKE, SND_SOC_DSP_TRIGGER_BESPOKE},
567};
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500568/* Digital audio interface glue - connects codec <--> CPU */
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000569static struct snd_soc_dai_link sdp4430_dai[] = {
570
571/*
572 * Frontend DAIs - i.e. userspace visible interfaces (ALSA PCMs)
573 */
574
575 {
576 .name = "SDP4430 Media",
577 .stream_name = "Multimedia",
578
579 /* ABE components - MM-UL & MM_DL */
580 .cpu_dai_name = "MultiMedia1",
581 .platform_name = "omap-pcm-audio",
582
583 .dynamic = 1, /* BE is dynamic */
584 .dsp_link = &fe_media,
585 },
586 {
587 .name = "SDP4430 Media Capture",
588 .stream_name = "Multimedia Capture",
589
590 /* ABE components - MM-UL2 */
591 .cpu_dai_name = "MultiMedia2",
592 .platform_name = "omap-pcm-audio",
593
594 .dynamic = 1, /* BE is dynamic */
595 .dsp_link = &fe_media_capture,
596 },
597 {
598 .name = "SDP4430 Voice",
599 .stream_name = "Voice",
600
601 /* ABE components - VX-UL & VX-DL */
602 .cpu_dai_name = "Voice",
603 .platform_name = "omap-pcm-audio",
604
605 .dynamic = 1, /* BE is dynamic */
606 .dsp_link = &fe_media,
607 .no_host_mode = SND_SOC_DAI_LINK_OPT_HOST,
608 },
609 {
610 .name = "SDP4430 Tones Playback",
611 .stream_name = "Tone Playback",
612
613 /* ABE components - TONES_DL */
614 .cpu_dai_name = "Tones",
615 .platform_name = "omap-pcm-audio",
616
617 .dynamic = 1, /* BE is dynamic */
618 .dsp_link = &fe_tones,
619 },
620 {
621 .name = "SDP4430 Vibra Playback",
622 .stream_name = "VIB-DL",
623
624 /* ABE components - DMIC UL 2 */
625 .cpu_dai_name = "Vibra",
626 .platform_name = "omap-pcm-audio",
627
628 .dynamic = 1, /* BE is dynamic */
629 .dsp_link = &fe_vib,
630 },
631 {
632 .name = "SDP4430 MODEM",
633 .stream_name = "MODEM",
634
635 /* ABE components - MODEM <-> McBSP2 */
636 .cpu_dai_name = "MODEM",
637 .platform_name = "aess",
638
639 .dynamic = 1, /* BE is dynamic */
640 .dsp_link = &fe_modem,
641 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
642 .ignore_suspend = 1,
643 },
644 {
645 .name = "SDP4430 Media LP",
646 .stream_name = "Multimedia",
647
648 /* ABE components - MM-DL (mmap) */
649 .cpu_dai_name = "MultiMedia1 LP",
650 .platform_name = "aess",
651
652 .dynamic = 1, /* BE is dynamic */
653 .dsp_link = &fe_lp_media,
654 },
655 {
656 .name = "Legacy McBSP",
657 .stream_name = "Multimedia",
658
659 /* ABE components - MCBSP2 - MM-EXT */
660 .cpu_dai_name = "omap-mcbsp-dai.1",
661 .platform_name = "omap-pcm-audio",
662
663 /* FM */
664 .codec_dai_name = "FM Digital",
665
666 .no_codec = 1, /* TODO: have a dummy CODEC */
667 .ops = &sdp4430_mcbsp_ops,
668 },
669 {
670 .name = "Legacy McPDM",
671 .stream_name = "Headset Playback",
672
673 /* ABE components - DL1 */
674 .cpu_dai_name = "mcpdm-dl",
675 .platform_name = "omap-pcm-audio",
676
677 /* Phoenix - DL1 DAC */
678 .codec_dai_name = "twl6040-dl1",
679 .codec_name = "twl6040-codec",
680
681 .ops = &sdp4430_mcpdm_ops,
682 },
683 {
684 .name = "Legacy DMIC",
685 .stream_name = "DMIC Capture",
686
687 /* ABE components - DMIC0 */
688 .cpu_dai_name = "omap-dmic-dai-0",
689 .platform_name = "omap-pcm-audio",
690
691 /* DMIC codec */
692 .codec_dai_name = "dmic-hifi",
693 .codec_name = "dmic-codec.0",
694
Misael Lopez Cruz47415f02011-04-27 23:56:32 -0500695 .init = sdp4430_dmic_init,
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000696 .ops = &sdp4430_dmic_ops,
697 },
698
699/*
700 * Backend DAIs - i.e. dynamically matched interfaces, invisible to userspace.
701 * Matched to above interfaces at runtime, based upon use case.
702 */
703
704 {
705 .name = OMAP_ABE_BE_PDM_DL1,
706 .stream_name = "HS Playback",
707
708 /* ABE components - DL1 */
709 .cpu_dai_name = "mcpdm-dl1",
710 .platform_name = "aess",
711
712 /* Phoenix - DL1 DAC */
713 .codec_dai_name = "twl6040-dl1",
714 .codec_name = "twl6040-codec",
715
716 .no_pcm = 1, /* don't create ALSA pcm for this */
717 .init = sdp4430_twl6040_init,
718 .ops = &sdp4430_mcpdm_ops,
719 .be_id = OMAP_ABE_DAI_PDM_DL1,
720 },
721 {
722 .name = OMAP_ABE_BE_PDM_UL1,
723 .stream_name = "Analog Capture",
724
725 /* ABE components - UL1 */
726 .cpu_dai_name = "mcpdm-ul1",
727 .platform_name = "aess",
728
729 /* Phoenix - UL ADC */
730 .codec_dai_name = "twl6040-ul",
731 .codec_name = "twl6040-codec",
732
733 .no_pcm = 1, /* don't create ALSA pcm for this */
734 .ops = &sdp4430_mcpdm_ops,
735 .be_id = OMAP_ABE_DAI_PDM_UL,
736 },
737 {
738 .name = OMAP_ABE_BE_PDM_DL2,
739 .stream_name = "HF Playback",
740
741 /* ABE components - DL2 */
742 .cpu_dai_name = "mcpdm-dl2",
743 .platform_name = "aess",
744
745 /* Phoenix - DL2 DAC */
746 .codec_dai_name = "twl6040-dl2",
747 .codec_name = "twl6040-codec",
748
749 .no_pcm = 1, /* don't create ALSA pcm for this */
750 .ops = &sdp4430_mcpdm_ops,
751 .be_id = OMAP_ABE_DAI_PDM_DL2,
752 },
753 {
754 .name = OMAP_ABE_BE_PDM_VIB,
755 .stream_name = "Vibra",
756
757 /* ABE components - VIB1 DL */
758 .cpu_dai_name = "mcpdm-vib",
759 .platform_name = "aess",
760
761 /* Phoenix - PDM to PWM */
762 .codec_dai_name = "twl6040-vib",
763 .codec_name = "twl6040-codec",
764
765 .no_pcm = 1, /* don't create ALSA pcm for this */
766 .ops = &sdp4430_mcpdm_ops,
767 .be_id = OMAP_ABE_DAI_PDM_VIB,
768 },
769 {
770 .name = OMAP_ABE_BE_BT_VX,
771 .stream_name = "BT",
772
773 /* ABE components - MCBSP1 - BT-VX */
774 .cpu_dai_name = "omap-mcbsp-dai.0",
775 .platform_name = "aess",
776
777 /* Bluetooth */
778 .codec_dai_name = "Bluetooth",
779
780 .no_pcm = 1, /* don't create ALSA pcm for this */
781 .no_codec = 1, /* TODO: have a dummy CODEC */
782 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
783 .ops = &sdp4430_mcbsp_ops,
784 .be_id = OMAP_ABE_DAI_BT_VX,
785 },
786 {
787 .name = OMAP_ABE_BE_MM_EXT0,
788 .stream_name = "FM",
789
790 /* ABE components - MCBSP2 - MM-EXT */
791 .cpu_dai_name = "omap-mcbsp-dai.1",
792 .platform_name = "aess",
793
794 /* FM */
795 .codec_dai_name = "FM Digital",
796
797 .no_pcm = 1, /* don't create ALSA pcm for this */
798 .no_codec = 1, /* TODO: have a dummy CODEC */
799 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
800 .ops = &sdp4430_mcbsp_ops,
801 .be_id = OMAP_ABE_DAI_MM_FM,
802 },
803 {
804 .name = OMAP_ABE_BE_MM_EXT1,
805 .stream_name = "MODEM",
806
807 /* ABE components - MCBSP2 - MM-EXT */
808 .cpu_dai_name = "omap-mcbsp-dai.1",
809 .platform_name = "aess",
810
811 /* MODEM */
812 .codec_dai_name = "MODEM",
813
814 .no_pcm = 1, /* don't create ALSA pcm for this */
815 .no_codec = 1, /* TODO: have a dummy CODEC */
816 .be_hw_params_fixup = mcbsp_be_hw_params_fixup,
817 .ops = &sdp4430_mcbsp_ops,
818 .be_id = OMAP_ABE_DAI_MODEM,
819 .ignore_suspend = 1,
820 },
821 {
822 .name = OMAP_ABE_BE_DMIC0,
823 .stream_name = "DMIC0",
824
825 /* ABE components - DMIC UL 1 */
826 .cpu_dai_name = "omap-dmic-abe-dai-0",
827 .platform_name = "aess",
828
829 /* DMIC 0 */
830 .codec_dai_name = "dmic-hifi",
831 .codec_name = "dmic-codec.0",
832 .ops = &sdp4430_dmic_ops,
833
834 .no_pcm = 1, /* don't create ALSA pcm for this */
835 .be_hw_params_fixup = dmic_be_hw_params_fixup,
836 .be_id = OMAP_ABE_DAI_DMIC0,
837 },
838 {
839 .name = OMAP_ABE_BE_DMIC1,
840 .stream_name = "DMIC1",
841
842 /* ABE components - DMIC UL 1 */
843 .cpu_dai_name = "omap-dmic-abe-dai-1",
844 .platform_name = "aess",
845
846 /* DMIC 1 */
847 .codec_dai_name = "dmic-hifi",
848 .codec_name = "dmic-codec.1",
849 .ops = &sdp4430_dmic_ops,
850
851 .no_pcm = 1, /* don't create ALSA pcm for this */
852 .be_hw_params_fixup = dmic_be_hw_params_fixup,
853 .be_id = OMAP_ABE_DAI_DMIC1,
854 },
855 {
856 .name = OMAP_ABE_BE_DMIC2,
857 .stream_name = "DMIC2",
858
859 /* ABE components - DMIC UL 2 */
860 .cpu_dai_name = "omap-dmic-abe-dai-2",
861 .platform_name = "aess",
862
863 /* DMIC 2 */
864 .codec_dai_name = "dmic-hifi",
865 .codec_name = "dmic-codec.2",
866 .ops = &sdp4430_dmic_ops,
867
868 .no_pcm = 1, /* don't create ALSA pcm for this */
869 .be_hw_params_fixup = dmic_be_hw_params_fixup,
870 .be_id = OMAP_ABE_DAI_DMIC2,
871 },
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500872};
873
874/* Audio machine driver */
875static struct snd_soc_card snd_soc_sdp4430 = {
Liam Girdwood62e16e82011-02-07 21:09:59 +0000876 .driver_name = "OMAP4",
877 .long_name = "TI OMAP4 Board",
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000878 .dai_link = sdp4430_dai,
879 .num_links = ARRAY_SIZE(sdp4430_dai),
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500880};
881
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500882static struct platform_device *sdp4430_snd_device;
Liam Girdwood8cc57052011-02-07 21:18:06 +0000883static struct i2c_adapter *adapter;
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500884
885static int __init sdp4430_soc_init(void)
886{
887 int ret;
888
Liam Girdwood62e16e82011-02-07 21:09:59 +0000889 if (!machine_is_omap_4430sdp() && !machine_is_omap4_panda()) {
890 pr_debug("Not SDP4430 or PandaBoard!\n");
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500891 return -ENODEV;
Liam Girdwood62e16e82011-02-07 21:09:59 +0000892 }
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500893 printk(KERN_INFO "SDP4430 SoC init\n");
Liam Girdwood62e16e82011-02-07 21:09:59 +0000894 if (machine_is_omap_4430sdp())
895 snd_soc_sdp4430.name = "SDP4430";
896 else if (machine_is_omap4_panda())
897 snd_soc_sdp4430.name = "Panda";
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500898
899 sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
900 if (!sdp4430_snd_device) {
901 printk(KERN_ERR "Platform device allocation failed\n");
902 return -ENOMEM;
903 }
904
Liam Girdwoodede6aa92011-02-07 21:07:48 +0000905 ret = snd_soc_register_dais(&sdp4430_snd_device->dev, dai, ARRAY_SIZE(dai));
906 if (ret < 0)
Liam Girdwood8cc57052011-02-07 21:18:06 +0000907 goto err_dai;
Liam Girdwoodf0fba2a2010-03-17 20:15:21 +0000908 platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500909
910 ret = platform_device_add(sdp4430_snd_device);
911 if (ret)
Liam Girdwood8cc57052011-02-07 21:18:06 +0000912 goto err_dev;
913
914 adapter = i2c_get_adapter(1);
915 if (!adapter) {
916 printk(KERN_ERR "can't get i2c adapter\n");
917 ret = -ENODEV;
918 goto err_adap;
919 }
920
921 tps6130x_client = i2c_new_device(adapter, &tps6130x_hwmon_info);
922 if (!tps6130x_client) {
923 printk(KERN_ERR "can't add i2c device\n");
924 ret = -ENODEV;
925 goto err_i2c;
926 }
927
928 /* Only configure the TPS6130x on SDP4430 */
929 if (machine_is_omap_4430sdp())
930 sdp4430_tps6130x_configure();
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500931
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500932 return 0;
933
Liam Girdwood8cc57052011-02-07 21:18:06 +0000934err_i2c:
935 i2c_put_adapter(adapter);
936err_adap:
937 platform_device_del(sdp4430_snd_device);
938err_dev:
939 snd_soc_unregister_dais(&sdp4430_snd_device->dev, ARRAY_SIZE(dai));
940err_dai:
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500941 platform_device_put(sdp4430_snd_device);
942 return ret;
943}
944module_init(sdp4430_soc_init);
945
946static void __exit sdp4430_soc_exit(void)
947{
948 platform_device_unregister(sdp4430_snd_device);
Liam Girdwood8cc57052011-02-07 21:18:06 +0000949 snd_soc_unregister_dais(&sdp4430_snd_device->dev, ARRAY_SIZE(dai));
950 i2c_unregister_device(tps6130x_client);
951 i2c_put_adapter(adapter);
Misael Lopez Cruz5e64d6a2010-05-17 19:53:10 -0500952}
953module_exit(sdp4430_soc_exit);
954
955MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
956MODULE_DESCRIPTION("ALSA SoC SDP4430");
957MODULE_LICENSE("GPL");
958