2 * sound/soc/imx/3ds-sgtl5000.c -- SoC audio for i.MX 3ds boards with
5 * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
6 * Copyright (C) 2011 Freescale Semiconductor, Inc.
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
14 #include <linux/module.h>
15 #include <linux/moduleparam.h>
16 #include <linux/device.h>
17 #include <linux/i2c.h>
18 #include <linux/fsl_devices.h>
19 #include <linux/gpio.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/soc.h>
23 #include <sound/jack.h>
24 #include <sound/soc-dapm.h>
25 #include <asm/mach-types.h>
26 #include <mach/audmux.h>
28 #include "../codecs/sgtl5000.h"
31 static struct imx_sgtl5000_priv {
34 struct platform_device *pdev;
37 static struct snd_soc_jack hs_jack;
38 static struct snd_soc_card imx_sgtl5000;
40 /* Headphones jack detection DAPM pins */
41 static struct snd_soc_jack_pin hs_jack_pins[] = {
43 .pin = "Headphone Jack",
44 .mask = SND_JACK_HEADPHONE,
48 /* Headphones jack detection gpios */
49 static struct snd_soc_jack_gpio hs_jack_gpios[] = {
51 /* gpio is set on per-platform basis */
53 .report = SND_JACK_HEADPHONE,
58 static int sgtl5000_params(struct snd_pcm_substream *substream,
59 struct snd_pcm_hw_params *params)
61 struct snd_soc_pcm_runtime *rtd = substream->private_data;
62 struct snd_soc_dai *codec_dai = rtd->codec_dai;
63 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
66 unsigned int channels = params_channels(params);
68 snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, card_priv.sysclk, 0);
70 snd_soc_dai_set_sysclk(codec_dai, SGTL5000_LRCLK, params_rate(params), 0);
72 dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
73 SND_SOC_DAIFMT_CBM_CFM;
75 /* set codec DAI configuration */
76 ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
81 /* TODO: The SSI driver should figure this out for us */
84 snd_soc_dai_set_tdm_slot(cpu_dai, 0xfffffffc, 0xfffffffc, 2, 0);
87 snd_soc_dai_set_tdm_slot(cpu_dai, 0xfffffffe, 0xfffffffe, 1, 0);
93 /* set cpu DAI configuration */
94 dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
95 SND_SOC_DAIFMT_CBM_CFM;
96 ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
103 static struct snd_soc_ops imx_sgtl5000_hifi_ops = {
104 .hw_params = sgtl5000_params,
107 static int sgtl5000_jack_func;
108 static int sgtl5000_spk_func;
109 static int sgtl5000_line_in_func;
111 static const char *jack_function[] = { "off", "on"};
113 static const char *spk_function[] = { "off", "on" };
115 static const char *line_in_function[] = { "off", "on" };
117 static const struct soc_enum sgtl5000_enum[] = {
118 SOC_ENUM_SINGLE_EXT(2, jack_function),
119 SOC_ENUM_SINGLE_EXT(2, spk_function),
120 SOC_ENUM_SINGLE_EXT(2, line_in_function),
123 static int sgtl5000_get_jack(struct snd_kcontrol *kcontrol,
124 struct snd_ctl_elem_value *ucontrol)
126 ucontrol->value.enumerated.item[0] = sgtl5000_jack_func;
130 static int sgtl5000_set_jack(struct snd_kcontrol *kcontrol,
131 struct snd_ctl_elem_value *ucontrol)
133 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
135 if (sgtl5000_jack_func == ucontrol->value.enumerated.item[0])
138 sgtl5000_jack_func = ucontrol->value.enumerated.item[0];
139 if (sgtl5000_jack_func)
140 snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
142 snd_soc_dapm_disable_pin(&codec->dapm, "Headphone Jack");
144 snd_soc_dapm_sync(&codec->dapm);
148 static int sgtl5000_get_spk(struct snd_kcontrol *kcontrol,
149 struct snd_ctl_elem_value *ucontrol)
151 ucontrol->value.enumerated.item[0] = sgtl5000_spk_func;
155 static int sgtl5000_set_spk(struct snd_kcontrol *kcontrol,
156 struct snd_ctl_elem_value *ucontrol)
158 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
160 if (sgtl5000_spk_func == ucontrol->value.enumerated.item[0])
163 sgtl5000_spk_func = ucontrol->value.enumerated.item[0];
164 if (sgtl5000_spk_func)
165 snd_soc_dapm_enable_pin(&codec->dapm, "Ext Spk");
167 snd_soc_dapm_disable_pin(&codec->dapm, "Ext Spk");
169 snd_soc_dapm_sync(&codec->dapm);
173 static int sgtl5000_get_line_in(struct snd_kcontrol *kcontrol,
174 struct snd_ctl_elem_value *ucontrol)
176 ucontrol->value.enumerated.item[0] = sgtl5000_line_in_func;
180 static int sgtl5000_set_line_in(struct snd_kcontrol *kcontrol,
181 struct snd_ctl_elem_value *ucontrol)
183 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
185 if (sgtl5000_line_in_func == ucontrol->value.enumerated.item[0])
188 sgtl5000_line_in_func = ucontrol->value.enumerated.item[0];
189 if (sgtl5000_line_in_func)
190 snd_soc_dapm_enable_pin(&codec->dapm, "Line In Jack");
192 snd_soc_dapm_disable_pin(&codec->dapm, "Line In Jack");
194 snd_soc_dapm_sync(&codec->dapm);
198 /* imx_3stack card dapm widgets */
199 static const struct snd_soc_dapm_widget imx_3stack_dapm_widgets[] = {
200 SND_SOC_DAPM_MIC("Mic Jack", NULL),
201 SND_SOC_DAPM_LINE("Line In Jack", NULL),
202 SND_SOC_DAPM_SPK("Ext Spk", NULL),
203 SND_SOC_DAPM_HP("Headphone Jack", NULL),
206 static const struct snd_kcontrol_new sgtl5000_machine_controls[] = {
207 SOC_ENUM_EXT("Jack Function", sgtl5000_enum[0], sgtl5000_get_jack,
209 SOC_ENUM_EXT("Speaker Function", sgtl5000_enum[1], sgtl5000_get_spk,
211 SOC_ENUM_EXT("Line In Function", sgtl5000_enum[1], sgtl5000_get_line_in,
212 sgtl5000_set_line_in),
215 /* imx_3stack machine connections to the codec pins */
216 static const struct snd_soc_dapm_route audio_map[] = {
218 /* Mic Jack --> MIC_IN (with automatic bias) */
219 {"MIC_IN", NULL, "Mic Jack"},
221 /* Line in Jack --> LINE_IN */
222 {"LINE_IN", NULL, "Line In Jack"},
224 /* HP_OUT --> Headphone Jack */
225 {"Headphone Jack", NULL, "HP_OUT"},
227 /* LINE_OUT --> Ext Speaker */
228 {"Ext Spk", NULL, "LINE_OUT"},
231 static int imx_3stack_sgtl5000_init(struct snd_soc_pcm_runtime *rtd)
233 struct snd_soc_codec *codec = rtd->codec;
236 ret = snd_soc_add_controls(codec, sgtl5000_machine_controls,
237 ARRAY_SIZE(sgtl5000_machine_controls));
241 /* Add imx_3stack specific widgets */
242 snd_soc_dapm_new_controls(&codec->dapm, imx_3stack_dapm_widgets,
243 ARRAY_SIZE(imx_3stack_dapm_widgets));
245 /* Set up imx_3stack specific audio path audio_map */
246 snd_soc_dapm_add_routes(&codec->dapm, audio_map, ARRAY_SIZE(audio_map));
248 snd_soc_dapm_disable_pin(&codec->dapm, "Line In Jack");
249 snd_soc_dapm_enable_pin(&codec->dapm, "Headphone Jack");
250 snd_soc_dapm_sync(&codec->dapm);
252 if (hs_jack_gpios[0].gpio != -1) {
253 /* Jack detection API stuff */
254 ret = snd_soc_jack_new(codec, "Headphone Jack",
255 SND_JACK_HEADPHONE, &hs_jack);
259 ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
262 printk(KERN_ERR "failed to call snd_soc_jack_add_pins\n");
266 ret = snd_soc_jack_add_gpios(&hs_jack,
267 ARRAY_SIZE(hs_jack_gpios), hs_jack_gpios);
269 printk(KERN_WARNING "failed to call snd_soc_jack_add_gpios\n");
275 static struct snd_soc_dai_link imx_sgtl5000_dai[] = {
278 .stream_name = "HiFi",
279 .codec_dai_name = "sgtl5000",
280 .codec_name = "sgtl5000.1-000a",
281 .cpu_dai_name = "imx-ssi.1",
282 .platform_name = "imx-pcm-audio.1",
283 .init = imx_3stack_sgtl5000_init,
284 .ops = &imx_sgtl5000_hifi_ops,
288 static struct snd_soc_card imx_sgtl5000 = {
289 .name = "sgtl5000-audio",
290 .dai_link = imx_sgtl5000_dai,
291 .num_links = ARRAY_SIZE(imx_sgtl5000_dai),
294 static struct platform_device *imx_sgtl5000_snd_device;
296 static int imx_audmux_config(int slave, int master)
298 unsigned int ptcr, pdcr;
302 /* SSI0 mastered by port 5 */
303 ptcr = MXC_AUDMUX_V2_PTCR_SYN |
304 MXC_AUDMUX_V2_PTCR_TFSDIR |
305 MXC_AUDMUX_V2_PTCR_TFSEL(master) |
306 MXC_AUDMUX_V2_PTCR_TCLKDIR |
307 MXC_AUDMUX_V2_PTCR_TCSEL(master);
308 pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(master);
309 mxc_audmux_v2_configure_port(slave, ptcr, pdcr);
311 ptcr = MXC_AUDMUX_V2_PTCR_SYN;
312 pdcr = MXC_AUDMUX_V2_PDCR_RXDSEL(slave);
313 mxc_audmux_v2_configure_port(master, ptcr, pdcr);
318 static int __devinit imx_sgtl5000_probe(struct platform_device *pdev)
320 struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
324 card_priv.pdev = pdev;
326 imx_audmux_config(plat->src_port, plat->ext_port);
329 if (plat->init && plat->init())
332 card_priv.sysclk = plat->sysclk;
334 hs_jack_gpios[0].gpio = plat->hp_gpio;
335 hs_jack_gpios[0].invert = plat->hp_active_low;
340 static int imx_sgtl5000_remove(struct platform_device *pdev)
342 struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
350 static struct platform_driver imx_sgtl5000_audio_driver = {
351 .probe = imx_sgtl5000_probe,
352 .remove = imx_sgtl5000_remove,
354 .name = "imx-sgtl5000",
358 static int __init imx_sgtl5000_init(void)
362 ret = platform_driver_register(&imx_sgtl5000_audio_driver);
366 if (machine_is_mx35_3ds())
367 imx_sgtl5000_dai[0].codec_name = "sgtl5000.0-000a";
369 imx_sgtl5000_dai[0].codec_name = "sgtl5000.1-000a";
371 imx_sgtl5000_snd_device = platform_device_alloc("soc-audio", 1);
372 if (!imx_sgtl5000_snd_device)
375 platform_set_drvdata(imx_sgtl5000_snd_device, &imx_sgtl5000);
377 ret = platform_device_add(imx_sgtl5000_snd_device);
380 printk(KERN_ERR "ASoC: Platform device allocation failed\n");
381 platform_device_put(imx_sgtl5000_snd_device);
387 static void __exit imx_sgtl5000_exit(void)
389 platform_driver_unregister(&imx_sgtl5000_audio_driver);
390 platform_device_unregister(imx_sgtl5000_snd_device);
393 module_init(imx_sgtl5000_init);
394 module_exit(imx_sgtl5000_exit);
396 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
397 MODULE_DESCRIPTION("PhyCORE ALSA SoC driver");
398 MODULE_LICENSE("GPL");