aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/s3c24xx/goni_wm8994.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2010-07-22 02:16:10 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:15 -0400
commitf51582fd8d9b1196d58cd94c2b4b759cc1baf57a (patch)
treefabe8ee5a0ae5f017bd54e8681ee53e86ca2a766 /sound/soc/s3c24xx/goni_wm8994.c
parent3782a528974c9607bde03ec265bbebd2dc300ea1 (diff)
ASoC: multi-component - Add Goni sound driver
This patch add sound support for the Goni board based on S5PV210. The Goni board is based on Samsung SoC(S5PV210) and include WM8994 codec over I2S to support sound. The kind of jack is below states : * SND_JACK_HEADPHONE * SND_JACK_HEADSET * SND_JACK_MECHANICAL : When TV-OUT cable is inserted on Goni board, the TV-OUT cable isn't connected to television. * SND_JACK_AVOUT : When TV-OUT cable is inserted on Goni board, the TV-OUT cable is connected to television. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/s3c24xx/goni_wm8994.c')
-rw-r--r--sound/soc/s3c24xx/goni_wm8994.c298
1 files changed, 298 insertions, 0 deletions
diff --git a/sound/soc/s3c24xx/goni_wm8994.c b/sound/soc/s3c24xx/goni_wm8994.c
new file mode 100644
index 000000000000..694f702cc8e2
--- /dev/null
+++ b/sound/soc/s3c24xx/goni_wm8994.c
@@ -0,0 +1,298 @@
1/*
2 * goni_wm8994.c
3 *
4 * Copyright (C) 2010 Samsung Electronics Co.Ltd
5 * Author: Chanwoo Choi <cw00.choi@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/io.h>
17#include <linux/platform_device.h>
18#include <sound/soc.h>
19#include <sound/soc-dapm.h>
20#include <sound/jack.h>
21#include <asm/mach-types.h>
22#include <mach/gpio.h>
23#include <mach/regs-clock.h>
24
25#include <linux/mfd/wm8994/core.h>
26#include <linux/mfd/wm8994/registers.h>
27#include "../codecs/wm8994.h"
28#include "s3c-dma.h"
29#include "s3c64xx-i2s.h"
30
31static struct snd_soc_card goni;
32static struct platform_device *goni_snd_device;
33
34/* 3.5 pie jack */
35static struct snd_soc_jack jack;
36
37/* 3.5 pie jack detection DAPM pins */
38static struct snd_soc_jack_pin jack_pins[] = {
39 {
40 .pin = "Headset Mic",
41 .mask = SND_JACK_MICROPHONE,
42 }, {
43 .pin = "Headset Stereophone",
44 .mask = SND_JACK_HEADPHONE | SND_JACK_MECHANICAL |
45 SND_JACK_AVOUT,
46 },
47};
48
49/* 3.5 pie jack detection gpios */
50static struct snd_soc_jack_gpio jack_gpios[] = {
51 {
52 .gpio = S5PV210_GPH0(6),
53 .name = "DET_3.5",
54 .report = SND_JACK_HEADSET | SND_JACK_MECHANICAL |
55 SND_JACK_AVOUT,
56 .debounce_time = 200,
57 },
58};
59
60static const struct snd_soc_dapm_widget goni_dapm_widgets[] = {
61 SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
62 SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
63 SND_SOC_DAPM_SPK("Ext Rcv", NULL),
64 SND_SOC_DAPM_HP("Headset Stereophone", NULL),
65 SND_SOC_DAPM_MIC("Headset Mic", NULL),
66 SND_SOC_DAPM_MIC("Main Mic", NULL),
67 SND_SOC_DAPM_MIC("2nd Mic", NULL),
68 SND_SOC_DAPM_LINE("Radio In", NULL),
69};
70
71static const struct snd_soc_dapm_route goni_dapm_routes[] = {
72 {"Ext Left Spk", NULL, "SPKOUTLP"},
73 {"Ext Left Spk", NULL, "SPKOUTLN"},
74
75 {"Ext Right Spk", NULL, "SPKOUTRP"},
76 {"Ext Right Spk", NULL, "SPKOUTRN"},
77
78 {"Ext Rcv", NULL, "HPOUT2N"},
79 {"Ext Rcv", NULL, "HPOUT2P"},
80
81 {"Headset Stereophone", NULL, "HPOUT1L"},
82 {"Headset Stereophone", NULL, "HPOUT1R"},
83
84 {"IN1RN", NULL, "Headset Mic"},
85 {"IN1RP", NULL, "Headset Mic"},
86
87 {"IN1RN", NULL, "2nd Mic"},
88 {"IN1RP", NULL, "2nd Mic"},
89
90 {"IN1LN", NULL, "Main Mic"},
91 {"IN1LP", NULL, "Main Mic"},
92
93 {"IN2LN", NULL, "Radio In"},
94 {"IN2RN", NULL, "Radio In"},
95};
96
97static int goni_wm8994_init(struct snd_soc_pcm_runtime *rtd)
98{
99 struct snd_soc_codec *codec = rtd->codec;
100 int ret;
101
102 /* add goni specific widgets */
103 snd_soc_dapm_new_controls(codec, goni_dapm_widgets,
104 ARRAY_SIZE(goni_dapm_widgets));
105
106 /* set up goni specific audio routes */
107 snd_soc_dapm_add_routes(codec, goni_dapm_routes,
108 ARRAY_SIZE(goni_dapm_routes));
109
110 /* set endpoints to not connected */
111 snd_soc_dapm_nc_pin(codec, "IN2LP:VXRN");
112 snd_soc_dapm_nc_pin(codec, "IN2RP:VXRP");
113 snd_soc_dapm_nc_pin(codec, "LINEOUT1N");
114 snd_soc_dapm_nc_pin(codec, "LINEOUT1P");
115 snd_soc_dapm_nc_pin(codec, "LINEOUT2N");
116 snd_soc_dapm_nc_pin(codec, "LINEOUT2P");
117
118 snd_soc_dapm_sync(codec);
119
120 /* Headset jack detection */
121 ret = snd_soc_jack_new(&goni, "Headset Jack",
122 SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
123 &jack);
124 if (ret)
125 return ret;
126
127 ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
128 if (ret)
129 return ret;
130
131 ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
132 if (ret)
133 return ret;
134
135 return 0;
136}
137
138static int goni_hifi_hw_params(struct snd_pcm_substream *substream,
139 struct snd_pcm_hw_params *params)
140{
141 struct snd_soc_pcm_runtime *rtd = substream->private_data;
142 struct snd_soc_dai *codec_dai = rtd->codec_dai;
143 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
144 unsigned int pll_out = 24000000;
145 int ret = 0;
146
147 /* set the cpu DAI configuration */
148 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
149 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
150 if (ret < 0)
151 return ret;
152
153 /* set the cpu system clock */
154 ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK,
155 0, SND_SOC_CLOCK_IN);
156 if (ret < 0)
157 return ret;
158
159 /* set codec DAI configuration */
160 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
161 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
162 if (ret < 0)
163 return ret;
164
165 /* set the codec FLL */
166 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 0, pll_out,
167 params_rate(params) * 256);
168 if (ret < 0)
169 return ret;
170
171 /* set the codec system clock */
172 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
173 params_rate(params) * 256, SND_SOC_CLOCK_IN);
174 if (ret < 0)
175 return ret;
176
177 return 0;
178}
179
180static struct snd_soc_ops goni_hifi_ops = {
181 .hw_params = goni_hifi_hw_params,
182};
183
184static int goni_voice_hw_params(struct snd_pcm_substream *substream,
185 struct snd_pcm_hw_params *params)
186{
187 struct snd_soc_pcm_runtime *rtd = substream->private_data;
188 struct snd_soc_dai *codec_dai = rtd->codec_dai;
189 unsigned int pll_out = 24000000;
190 int ret = 0;
191
192 if (params_rate(params) != 8000)
193 return -EINVAL;
194
195 /* set codec DAI configuration */
196 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_LEFT_J |
197 SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM);
198 if (ret < 0)
199 return ret;
200
201 /* set the codec FLL */
202 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, 0, pll_out,
203 params_rate(params) * 256);
204 if (ret < 0)
205 return ret;
206
207 /* set the codec system clock */
208 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
209 params_rate(params) * 256, SND_SOC_CLOCK_IN);
210 if (ret < 0)
211 return ret;
212
213 return 0;
214}
215
216static struct snd_soc_dai_driver voice_dai = {
217 .name = "goni-voice-dai",
218 .id = 0,
219 .playback = {
220 .channels_min = 1,
221 .channels_max = 2,
222 .rates = SNDRV_PCM_RATE_8000,
223 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
224 .capture = {
225 .channels_min = 1,
226 .channels_max = 2,
227 .rates = SNDRV_PCM_RATE_8000,
228 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
229};
230
231static struct snd_soc_ops goni_voice_ops = {
232 .hw_params = goni_voice_hw_params,
233};
234
235static struct snd_soc_dai_link goni_dai[] = {
236{
237 .name = "WM8994",
238 .stream_name = "WM8994 HiFi",
239 .cpu_dai_name = "s3c64xx-i2s-v4",
240 .codec_dai_name = "wm8994-hifi",
241 .platform_name = "s3c24xx-pcm-audio",
242 .codec_name = "wm8994-codec.0-0x1a",
243 .init = goni_wm8994_init,
244 .ops = &goni_hifi_ops,
245}, {
246 .name = "WM8994 Voice",
247 .stream_name = "Voice",
248 .cpu_dai_name = "goni-voice-dai",
249 .codec_dai_name = "wm8994-voice",
250 .platform_name = "s3c24xx-pcm-audio",
251 .codec_name = "wm8994-codec.0-0x1a",
252 .ops = &goni_voice_ops,
253},
254};
255
256static struct snd_soc_card goni = {
257 .name = "goni",
258 .dai_link = goni_dai,
259 .num_links = ARRAY_SIZE(goni_dai),
260};
261
262static int __init goni_init(void)
263{
264 int ret;
265
266 if (!machine_is_goni())
267 return -ENODEV;
268
269 goni_snd_device = platform_device_alloc("soc-audio", -1);
270 if (!goni_snd_device)
271 return -ENOMEM;
272
273 /* register voice DAI here */
274 ret = snd_soc_register_dai(&goni_snd_device->dev, &voice_dai);
275 if (ret)
276 return ret;
277
278 platform_set_drvdata(goni_snd_device, &goni);
279 ret = platform_device_add(goni_snd_device);
280
281 if (ret)
282 platform_device_put(goni_snd_device);
283
284 return ret;
285}
286
287static void __exit goni_exit(void)
288{
289 platform_device_unregister(goni_snd_device);
290}
291
292module_init(goni_init);
293module_exit(goni_exit);
294
295/* Module information */
296MODULE_DESCRIPTION("ALSA SoC WM8994 GONI(S5PV210)");
297MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
298MODULE_LICENSE("GPL");