diff options
Diffstat (limited to 'sound/soc/atmel/sam9g20_wm8731.c')
-rw-r--r-- | sound/soc/atmel/sam9g20_wm8731.c | 116 |
1 files changed, 88 insertions, 28 deletions
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index c88351488f45..da976291da9e 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -38,6 +38,8 @@ | |||
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | 40 | ||
41 | #include <linux/pinctrl/consumer.h> | ||
42 | |||
41 | #include <linux/atmel-ssc.h> | 43 | #include <linux/atmel-ssc.h> |
42 | 44 | ||
43 | #include <sound/core.h> | 45 | #include <sound/core.h> |
@@ -179,10 +181,10 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | |||
179 | static struct snd_soc_dai_link at91sam9g20ek_dai = { | 181 | static struct snd_soc_dai_link at91sam9g20ek_dai = { |
180 | .name = "WM8731", | 182 | .name = "WM8731", |
181 | .stream_name = "WM8731 PCM", | 183 | .stream_name = "WM8731 PCM", |
182 | .cpu_dai_name = "atmel-ssc-dai.0", | 184 | .cpu_dai_name = "at91rm9200_ssc.0", |
183 | .codec_dai_name = "wm8731-hifi", | 185 | .codec_dai_name = "wm8731-hifi", |
184 | .init = at91sam9g20ek_wm8731_init, | 186 | .init = at91sam9g20ek_wm8731_init, |
185 | .platform_name = "atmel-pcm-audio", | 187 | .platform_name = "at91rm9200_ssc.0", |
186 | .codec_name = "wm8731.0-001b", | 188 | .codec_name = "wm8731.0-001b", |
187 | .ops = &at91sam9g20ek_ops, | 189 | .ops = &at91sam9g20ek_ops, |
188 | }; | 190 | }; |
@@ -195,20 +197,31 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { | |||
195 | .set_bias_level = at91sam9g20ek_set_bias_level, | 197 | .set_bias_level = at91sam9g20ek_set_bias_level, |
196 | }; | 198 | }; |
197 | 199 | ||
198 | static struct platform_device *at91sam9g20ek_snd_device; | 200 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) |
199 | |||
200 | static int __init at91sam9g20ek_init(void) | ||
201 | { | 201 | { |
202 | struct device_node *np = pdev->dev.of_node; | ||
203 | struct device_node *codec_np, *cpu_np; | ||
202 | struct clk *pllb; | 204 | struct clk *pllb; |
205 | struct snd_soc_card *card = &snd_soc_at91sam9g20ek; | ||
206 | struct pinctrl *pinctrl; | ||
203 | int ret; | 207 | int ret; |
204 | 208 | ||
205 | if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) | 209 | pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
206 | return -ENODEV; | 210 | if (IS_ERR(pinctrl)) { |
211 | dev_err(&pdev->dev, "Failed to request pinctrl for mck\n"); | ||
212 | return PTR_ERR(pinctrl); | ||
213 | } | ||
214 | |||
215 | if (!np) { | ||
216 | if (!(machine_is_at91sam9g20ek() || | ||
217 | machine_is_at91sam9g20ek_2mmc())) | ||
218 | return -ENODEV; | ||
219 | } | ||
207 | 220 | ||
208 | ret = atmel_ssc_set_audio(0); | 221 | ret = atmel_ssc_set_audio(0); |
209 | if (ret != 0) { | 222 | if (ret) { |
210 | pr_err("Failed to set SSC 0 for audio: %d\n", ret); | 223 | dev_err(&pdev->dev, "ssc channel is not valid\n"); |
211 | return ret; | 224 | return -EINVAL; |
212 | } | 225 | } |
213 | 226 | ||
214 | /* | 227 | /* |
@@ -236,45 +249,92 @@ static int __init at91sam9g20ek_init(void) | |||
236 | 249 | ||
237 | clk_set_rate(mclk, MCLK_RATE); | 250 | clk_set_rate(mclk, MCLK_RATE); |
238 | 251 | ||
239 | at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1); | 252 | card->dev = &pdev->dev; |
240 | if (!at91sam9g20ek_snd_device) { | 253 | |
241 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | 254 | /* Parse device node info */ |
242 | ret = -ENOMEM; | 255 | if (np) { |
243 | goto err_mclk; | 256 | ret = snd_soc_of_parse_card_name(card, "atmel,model"); |
257 | if (ret) | ||
258 | goto err; | ||
259 | |||
260 | ret = snd_soc_of_parse_audio_routing(card, | ||
261 | "atmel,audio-routing"); | ||
262 | if (ret) | ||
263 | goto err; | ||
264 | |||
265 | /* Parse codec info */ | ||
266 | at91sam9g20ek_dai.codec_name = NULL; | ||
267 | codec_np = of_parse_phandle(np, "atmel,audio-codec", 0); | ||
268 | if (!codec_np) { | ||
269 | dev_err(&pdev->dev, "codec info missing\n"); | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | at91sam9g20ek_dai.codec_of_node = codec_np; | ||
273 | |||
274 | /* Parse dai and platform info */ | ||
275 | at91sam9g20ek_dai.cpu_dai_name = NULL; | ||
276 | at91sam9g20ek_dai.platform_name = NULL; | ||
277 | cpu_np = of_parse_phandle(np, "atmel,ssc-controller", 0); | ||
278 | if (!cpu_np) { | ||
279 | dev_err(&pdev->dev, "dai and pcm info missing\n"); | ||
280 | return -EINVAL; | ||
281 | } | ||
282 | at91sam9g20ek_dai.cpu_of_node = cpu_np; | ||
283 | at91sam9g20ek_dai.platform_of_node = cpu_np; | ||
284 | |||
285 | of_node_put(codec_np); | ||
286 | of_node_put(cpu_np); | ||
244 | } | 287 | } |
245 | 288 | ||
246 | platform_set_drvdata(at91sam9g20ek_snd_device, | 289 | ret = snd_soc_register_card(card); |
247 | &snd_soc_at91sam9g20ek); | ||
248 | |||
249 | ret = platform_device_add(at91sam9g20ek_snd_device); | ||
250 | if (ret) { | 290 | if (ret) { |
251 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | 291 | printk(KERN_ERR "ASoC: snd_soc_register_card() failed\n"); |
252 | goto err_device_add; | ||
253 | } | 292 | } |
254 | 293 | ||
255 | return ret; | 294 | return ret; |
256 | 295 | ||
257 | err_device_add: | ||
258 | platform_device_put(at91sam9g20ek_snd_device); | ||
259 | err_mclk: | 296 | err_mclk: |
260 | clk_put(mclk); | 297 | clk_put(mclk); |
261 | mclk = NULL; | 298 | mclk = NULL; |
262 | err: | 299 | err: |
300 | atmel_ssc_put_audio(0); | ||
263 | return ret; | 301 | return ret; |
264 | } | 302 | } |
265 | 303 | ||
266 | static void __exit at91sam9g20ek_exit(void) | 304 | static int at91sam9g20ek_audio_remove(struct platform_device *pdev) |
267 | { | 305 | { |
268 | platform_device_unregister(at91sam9g20ek_snd_device); | 306 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
269 | at91sam9g20ek_snd_device = NULL; | 307 | |
308 | atmel_ssc_put_audio(0); | ||
309 | snd_soc_unregister_card(card); | ||
270 | clk_put(mclk); | 310 | clk_put(mclk); |
271 | mclk = NULL; | 311 | mclk = NULL; |
312 | |||
313 | return 0; | ||
272 | } | 314 | } |
273 | 315 | ||
274 | module_init(at91sam9g20ek_init); | 316 | #ifdef CONFIG_OF |
275 | module_exit(at91sam9g20ek_exit); | 317 | static const struct of_device_id at91sam9g20ek_wm8731_dt_ids[] = { |
318 | { .compatible = "atmel,at91sam9g20ek-wm8731-audio", }, | ||
319 | { } | ||
320 | }; | ||
321 | MODULE_DEVICE_TABLE(of, at91sam9g20ek_wm8731_dt_ids); | ||
322 | #endif | ||
323 | |||
324 | static struct platform_driver at91sam9g20ek_audio_driver = { | ||
325 | .driver = { | ||
326 | .name = "at91sam9g20ek-audio", | ||
327 | .owner = THIS_MODULE, | ||
328 | .of_match_table = of_match_ptr(at91sam9g20ek_wm8731_dt_ids), | ||
329 | }, | ||
330 | .probe = at91sam9g20ek_audio_probe, | ||
331 | .remove = at91sam9g20ek_audio_remove, | ||
332 | }; | ||
333 | |||
334 | module_platform_driver(at91sam9g20ek_audio_driver); | ||
276 | 335 | ||
277 | /* Module information */ | 336 | /* Module information */ |
278 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); | 337 | MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>"); |
279 | MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); | 338 | MODULE_DESCRIPTION("ALSA SoC AT91SAM9G20EK_WM8731"); |
339 | MODULE_ALIAS("platform:at91sam9g20ek-audio"); | ||
280 | MODULE_LICENSE("GPL"); | 340 | MODULE_LICENSE("GPL"); |