]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/omap/sdp4430.c
Merge branch 'for-3.2' into for-3.3
[karo-tx-linux.git] / sound / soc / omap / sdp4430.c
1 /*
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>
24 #include <linux/mfd/twl6040.h>
25 #include <linux/module.h>
26
27 #include <sound/core.h>
28 #include <sound/pcm.h>
29 #include <sound/soc.h>
30 #include <sound/jack.h>
31
32 #include <asm/mach-types.h>
33 #include <plat/hardware.h>
34 #include <plat/mux.h>
35
36 #include "omap-dmic.h"
37 #include "omap-mcpdm.h"
38 #include "omap-pcm.h"
39 #include "../codecs/twl6040.h"
40
41 static int sdp4430_hw_params(struct snd_pcm_substream *substream,
42         struct snd_pcm_hw_params *params)
43 {
44         struct snd_soc_pcm_runtime *rtd = substream->private_data;
45         struct snd_soc_dai *codec_dai = rtd->codec_dai;
46         int clk_id, freq;
47         int ret;
48
49         clk_id = twl6040_get_clk_id(rtd->codec);
50         if (clk_id == TWL6040_SYSCLK_SEL_HPPLL)
51                 freq = 38400000;
52         else if (clk_id == TWL6040_SYSCLK_SEL_LPPLL)
53                 freq = 32768;
54         else
55                 return -EINVAL;
56
57         /* set the codec mclk */
58         ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, freq,
59                                 SND_SOC_CLOCK_IN);
60         if (ret) {
61                 printk(KERN_ERR "can't set codec system clock\n");
62                 return ret;
63         }
64         return ret;
65 }
66
67 static struct snd_soc_ops sdp4430_ops = {
68         .hw_params = sdp4430_hw_params,
69 };
70
71 static int sdp4430_dmic_hw_params(struct snd_pcm_substream *substream,
72         struct snd_pcm_hw_params *params)
73 {
74         struct snd_soc_pcm_runtime *rtd = substream->private_data;
75         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
76         int ret = 0;
77
78         ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_SYSCLK_PAD_CLKS,
79                                      19200000, SND_SOC_CLOCK_IN);
80         if (ret < 0) {
81                 printk(KERN_ERR "can't set DMIC cpu system clock\n");
82                 return ret;
83         }
84         ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_DMIC_ABE_DMIC_CLK, 2400000,
85                                      SND_SOC_CLOCK_OUT);
86         if (ret < 0) {
87                 printk(KERN_ERR "can't set DMIC output clock\n");
88                 return ret;
89         }
90         return 0;
91 }
92
93 static struct snd_soc_ops sdp4430_dmic_ops = {
94         .hw_params = sdp4430_dmic_hw_params,
95 };
96
97 /* Headset jack */
98 static struct snd_soc_jack hs_jack;
99
100 /*Headset jack detection DAPM pins */
101 static struct snd_soc_jack_pin hs_jack_pins[] = {
102         {
103                 .pin = "Headset Mic",
104                 .mask = SND_JACK_MICROPHONE,
105         },
106         {
107                 .pin = "Headset Stereophone",
108                 .mask = SND_JACK_HEADPHONE,
109         },
110 };
111
112 /* SDP4430 machine DAPM */
113 static const struct snd_soc_dapm_widget sdp4430_twl6040_dapm_widgets[] = {
114         SND_SOC_DAPM_MIC("Ext Mic", NULL),
115         SND_SOC_DAPM_SPK("Ext Spk", NULL),
116         SND_SOC_DAPM_MIC("Headset Mic", NULL),
117         SND_SOC_DAPM_HP("Headset Stereophone", NULL),
118         SND_SOC_DAPM_SPK("Earphone Spk", NULL),
119         SND_SOC_DAPM_INPUT("FM Stereo In"),
120 };
121
122 static const struct snd_soc_dapm_route audio_map[] = {
123         /* External Mics: MAINMIC, SUBMIC with bias*/
124         {"MAINMIC", NULL, "Main Mic Bias"},
125         {"SUBMIC", NULL, "Main Mic Bias"},
126         {"Main Mic Bias", NULL, "Ext Mic"},
127
128         /* External Speakers: HFL, HFR */
129         {"Ext Spk", NULL, "HFL"},
130         {"Ext Spk", NULL, "HFR"},
131
132         /* Headset Mic: HSMIC with bias */
133         {"HSMIC", NULL, "Headset Mic Bias"},
134         {"Headset Mic Bias", NULL, "Headset Mic"},
135
136         /* Headset Stereophone (Headphone): HSOL, HSOR */
137         {"Headset Stereophone", NULL, "HSOL"},
138         {"Headset Stereophone", NULL, "HSOR"},
139
140         /* Earphone speaker */
141         {"Earphone Spk", NULL, "EP"},
142
143         /* Aux/FM Stereo In: AFML, AFMR */
144         {"AFML", NULL, "FM Stereo In"},
145         {"AFMR", NULL, "FM Stereo In"},
146 };
147
148 static int sdp4430_twl6040_init(struct snd_soc_pcm_runtime *rtd)
149 {
150         struct snd_soc_codec *codec = rtd->codec;
151         int ret, hs_trim;
152
153         /*
154          * Configure McPDM offset cancellation based on the HSOTRIM value from
155          * twl6040.
156          */
157         hs_trim = twl6040_get_trim_value(codec, TWL6040_TRIM_HSOTRIM);
158         omap_mcpdm_configure_dn_offsets(rtd, TWL6040_HSF_TRIM_LEFT(hs_trim),
159                                         TWL6040_HSF_TRIM_RIGHT(hs_trim));
160
161         /* Headset jack detection */
162         ret = snd_soc_jack_new(codec, "Headset Jack",
163                                 SND_JACK_HEADSET, &hs_jack);
164         if (ret)
165                 return ret;
166
167         ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
168                                 hs_jack_pins);
169
170         if (machine_is_omap_4430sdp())
171                 twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
172         else
173                 snd_soc_jack_report(&hs_jack, SND_JACK_HEADSET, SND_JACK_HEADSET);
174
175         return ret;
176 }
177
178 static const struct snd_soc_dapm_widget sdp4430_dmic_dapm_widgets[] = {
179         SND_SOC_DAPM_MIC("Digital Mic", NULL),
180 };
181
182 static const struct snd_soc_dapm_route dmic_audio_map[] = {
183         {"DMic", NULL, "Digital Mic1 Bias"},
184         {"Digital Mic1 Bias", NULL, "Digital Mic"},
185 };
186
187 static int sdp4430_dmic_init(struct snd_soc_pcm_runtime *rtd)
188 {
189         struct snd_soc_codec *codec = rtd->codec;
190         struct snd_soc_dapm_context *dapm = &codec->dapm;
191         int ret;
192
193         ret = snd_soc_dapm_new_controls(dapm, sdp4430_dmic_dapm_widgets,
194                                 ARRAY_SIZE(sdp4430_dmic_dapm_widgets));
195         if (ret)
196                 return ret;
197
198         return snd_soc_dapm_add_routes(dapm, dmic_audio_map,
199                                 ARRAY_SIZE(dmic_audio_map));
200 }
201
202 /* Digital audio interface glue - connects codec <--> CPU */
203 static struct snd_soc_dai_link sdp4430_dai[] = {
204         {
205                 .name = "TWL6040",
206                 .stream_name = "TWL6040",
207                 .cpu_dai_name = "omap-mcpdm",
208                 .codec_dai_name = "twl6040-legacy",
209                 .platform_name = "omap-pcm-audio",
210                 .codec_name = "twl6040-codec",
211                 .init = sdp4430_twl6040_init,
212                 .ops = &sdp4430_ops,
213         },
214         {
215                 .name = "DMIC",
216                 .stream_name = "DMIC Capture",
217                 .cpu_dai_name = "omap-dmic",
218                 .codec_dai_name = "dmic-hifi",
219                 .platform_name = "omap-pcm-audio",
220                 .codec_name = "dmic-codec",
221                 .init = sdp4430_dmic_init,
222                 .ops = &sdp4430_dmic_ops,
223         },
224 };
225
226 /* Audio machine driver */
227 static struct snd_soc_card snd_soc_sdp4430 = {
228         .name = "SDP4430",
229         .dai_link = sdp4430_dai,
230         .num_links = ARRAY_SIZE(sdp4430_dai),
231
232         .dapm_widgets = sdp4430_twl6040_dapm_widgets,
233         .num_dapm_widgets = ARRAY_SIZE(sdp4430_twl6040_dapm_widgets),
234         .dapm_routes = audio_map,
235         .num_dapm_routes = ARRAY_SIZE(audio_map),
236 };
237
238 static struct platform_device *sdp4430_snd_device;
239
240 static int __init sdp4430_soc_init(void)
241 {
242         int ret;
243
244         if (!machine_is_omap_4430sdp())
245                 return -ENODEV;
246         printk(KERN_INFO "SDP4430 SoC init\n");
247
248         sdp4430_snd_device = platform_device_alloc("soc-audio", -1);
249         if (!sdp4430_snd_device) {
250                 printk(KERN_ERR "Platform device allocation failed\n");
251                 return -ENOMEM;
252         }
253
254         platform_set_drvdata(sdp4430_snd_device, &snd_soc_sdp4430);
255
256         ret = platform_device_add(sdp4430_snd_device);
257         if (ret)
258                 goto err;
259
260         return 0;
261
262 err:
263         printk(KERN_ERR "Unable to add platform device\n");
264         platform_device_put(sdp4430_snd_device);
265         return ret;
266 }
267 module_init(sdp4430_soc_init);
268
269 static void __exit sdp4430_soc_exit(void)
270 {
271         platform_device_unregister(sdp4430_snd_device);
272 }
273 module_exit(sdp4430_soc_exit);
274
275 MODULE_AUTHOR("Misael Lopez Cruz <x0052729@ti.com>");
276 MODULE_DESCRIPTION("ALSA SoC SDP4430");
277 MODULE_LICENSE("GPL");
278