aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/samsung/littlemill.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-11-28 17:05:41 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-11-28 17:10:29 -0500
commit0a590b1de28813c81effa2c291f24ef1f47444e9 (patch)
treecb26c478d64221cb161cf7c13dfe71ef3069628c /sound/soc/samsung/littlemill.c
parent34cbe16833a1840d6cde592123335fb3ad75b5d4 (diff)
ASoC: Add basic 1277-EV1 Littlemill audio driver
The Littlemill audio card supports a number of pluggable miniboards, normally for the WM8994 family of devices. As all these devices look mostly the same from an external configuration point of view and are runtime enumerable we can write a standard machine driver which will work out of the box with any of them. Start doing that with the bare bones of a driver, only supporting AIF1. Future patches will flesh this out to be more fully featured. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/samsung/littlemill.c')
-rw-r--r--sound/soc/samsung/littlemill.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c
new file mode 100644
index 000000000000..d2a44ab3c207
--- /dev/null
+++ b/sound/soc/samsung/littlemill.c
@@ -0,0 +1,227 @@
1/*
2 * Littlemill audio support
3 *
4 * Copyright 2011 Wolfson Microelectronics
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12#include <sound/soc.h>
13#include <sound/soc-dapm.h>
14#include <sound/jack.h>
15#include <linux/gpio.h>
16#include <linux/module.h>
17
18#include "../codecs/wm8994.h"
19
20static int sample_rate = 44100;
21
22static int littlemill_set_bias_level(struct snd_soc_card *card,
23 struct snd_soc_dapm_context *dapm,
24 enum snd_soc_bias_level level)
25{
26 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
27 int ret;
28
29 if (dapm->dev != codec_dai->dev)
30 return 0;
31
32 switch (level) {
33 case SND_SOC_BIAS_PREPARE:
34 /*
35 * If we've not already clocked things via hw_params()
36 * then do so now, otherwise these are noops.
37 */
38 if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
39 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
40 WM8994_FLL_SRC_MCLK2, 32768,
41 sample_rate * 512);
42 if (ret < 0) {
43 pr_err("Failed to start FLL: %d\n", ret);
44 return ret;
45 }
46
47 ret = snd_soc_dai_set_sysclk(codec_dai,
48 WM8994_SYSCLK_FLL1,
49 sample_rate * 512,
50 SND_SOC_CLOCK_IN);
51 if (ret < 0) {
52 pr_err("Failed to set SYSCLK: %d\n", ret);
53 return ret;
54 }
55 }
56 break;
57
58 default:
59 break;
60 }
61
62 return 0;
63}
64
65static int littlemill_set_bias_level_post(struct snd_soc_card *card,
66 struct snd_soc_dapm_context *dapm,
67 enum snd_soc_bias_level level)
68{
69 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
70 int ret;
71
72 if (dapm->dev != codec_dai->dev)
73 return 0;
74
75 switch (level) {
76 case SND_SOC_BIAS_STANDBY:
77 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
78 32768, SND_SOC_CLOCK_IN);
79 if (ret < 0) {
80 pr_err("Failed to switch away from FLL: %d\n", ret);
81 return ret;
82 }
83
84 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
85 0, 0, 0);
86 if (ret < 0) {
87 pr_err("Failed to stop FLL: %d\n", ret);
88 return ret;
89 }
90 break;
91
92 default:
93 break;
94 }
95
96 dapm->bias_level = level;
97
98 return 0;
99}
100
101static int littlemill_hw_params(struct snd_pcm_substream *substream,
102 struct snd_pcm_hw_params *params)
103{
104 struct snd_soc_pcm_runtime *rtd = substream->private_data;
105 struct snd_soc_dai *codec_dai = rtd->codec_dai;
106 int ret;
107
108 sample_rate = params_rate(params);
109
110 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1,
111 WM8994_FLL_SRC_MCLK2, 32768,
112 sample_rate * 512);
113 if (ret < 0) {
114 pr_err("Failed to start FLL: %d\n", ret);
115 return ret;
116 }
117
118 ret = snd_soc_dai_set_sysclk(codec_dai,
119 WM8994_SYSCLK_FLL1,
120 sample_rate * 512,
121 SND_SOC_CLOCK_IN);
122 if (ret < 0) {
123 pr_err("Failed to set SYSCLK: %d\n", ret);
124 return ret;
125 }
126
127 return 0;
128}
129
130static struct snd_soc_ops littlemill_ops = {
131 .hw_params = littlemill_hw_params,
132};
133
134static struct snd_soc_dai_link littlemill_dai[] = {
135 {
136 .name = "CPU",
137 .stream_name = "CPU",
138 .cpu_dai_name = "samsung-i2s.0",
139 .codec_dai_name = "wm8994-aif1",
140 .platform_name = "samsung-audio",
141 .codec_name = "wm8994-codec",
142 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
143 | SND_SOC_DAIFMT_CBM_CFM,
144 .ops = &littlemill_ops,
145 },
146};
147
148static struct snd_soc_dapm_widget widgets[] = {
149 SND_SOC_DAPM_HP("Headphone", NULL),
150};
151
152static struct snd_soc_dapm_route audio_paths[] = {
153 { "Headphone", NULL, "HPOUT1L" },
154 { "Headphone", NULL, "HPOUT1R" },
155};
156
157static int littlemill_late_probe(struct snd_soc_card *card)
158{
159 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
160 int ret;
161
162 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK2,
163 32768, SND_SOC_CLOCK_IN);
164 if (ret < 0)
165 return ret;
166
167 return 0;
168}
169
170static struct snd_soc_card littlemill = {
171 .name = "Littlemill",
172 .dai_link = littlemill_dai,
173 .num_links = ARRAY_SIZE(littlemill_dai),
174
175 .set_bias_level = littlemill_set_bias_level,
176 .set_bias_level_post = littlemill_set_bias_level_post,
177
178 .dapm_widgets = widgets,
179 .num_dapm_widgets = ARRAY_SIZE(widgets),
180 .dapm_routes = audio_paths,
181 .num_dapm_routes = ARRAY_SIZE(audio_paths),
182
183 .late_probe = littlemill_late_probe,
184};
185
186static __devinit int littlemill_probe(struct platform_device *pdev)
187{
188 struct snd_soc_card *card = &littlemill;
189 int ret;
190
191 card->dev = &pdev->dev;
192
193 ret = snd_soc_register_card(card);
194 if (ret) {
195 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
196 ret);
197 return ret;
198 }
199
200 return 0;
201}
202
203static int __devexit littlemill_remove(struct platform_device *pdev)
204{
205 struct snd_soc_card *card = platform_get_drvdata(pdev);
206
207 snd_soc_unregister_card(card);
208
209 return 0;
210}
211
212static struct platform_driver littlemill_driver = {
213 .driver = {
214 .name = "littlemill",
215 .owner = THIS_MODULE,
216 .pm = &snd_soc_pm_ops,
217 },
218 .probe = littlemill_probe,
219 .remove = __devexit_p(littlemill_remove),
220};
221
222module_platform_driver(littlemill_driver);
223
224MODULE_DESCRIPTION("Littlemill audio support");
225MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
226MODULE_LICENSE("GPL");
227MODULE_ALIAS("platform:littlemill");