aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8711.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/wm8711.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- 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> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8711.c')
-rw-r--r--sound/soc/codecs/wm8711.c206
1 files changed, 59 insertions, 147 deletions
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index e2dba07f0260..8d942b3b111f 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -31,11 +31,10 @@
31 31
32#include "wm8711.h" 32#include "wm8711.h"
33 33
34static struct snd_soc_codec *wm8711_codec;
35
36/* codec private data */ 34/* codec private data */
37struct wm8711_priv { 35struct wm8711_priv {
38 struct snd_soc_codec codec; 36 enum snd_soc_control_type bus_type;
37 void *control_data;
39 u16 reg_cache[WM8711_CACHEREGNUM]; 38 u16 reg_cache[WM8711_CACHEREGNUM];
40 unsigned int sysclk; 39 unsigned int sysclk;
41}; 40};
@@ -163,7 +162,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
163 struct snd_soc_dai *dai) 162 struct snd_soc_dai *dai)
164{ 163{
165 struct snd_soc_codec *codec = dai->codec; 164 struct snd_soc_codec *codec = dai->codec;
166 struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); 165 struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
167 u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; 166 u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
168 int i = get_coeff(wm8711->sysclk, params_rate(params)); 167 int i = get_coeff(wm8711->sysclk, params_rate(params));
169 u16 srate = (coeff_div[i].sr << 2) | 168 u16 srate = (coeff_div[i].sr << 2) |
@@ -227,7 +226,7 @@ static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai,
227 int clk_id, unsigned int freq, int dir) 226 int clk_id, unsigned int freq, int dir)
228{ 227{
229 struct snd_soc_codec *codec = codec_dai->codec; 228 struct snd_soc_codec *codec = codec_dai->codec;
230 struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); 229 struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
231 230
232 switch (freq) { 231 switch (freq) {
233 case 11289600: 232 case 11289600:
@@ -338,8 +337,8 @@ static struct snd_soc_dai_ops wm8711_ops = {
338 .set_fmt = wm8711_set_dai_fmt, 337 .set_fmt = wm8711_set_dai_fmt,
339}; 338};
340 339
341struct snd_soc_dai wm8711_dai = { 340static struct snd_soc_dai_driver wm8711_dai = {
342 .name = "WM8711", 341 .name = "wm8711-hifi",
343 .playback = { 342 .playback = {
344 .stream_name = "Playback", 343 .stream_name = "Playback",
345 .channels_min = 1, 344 .channels_min = 1,
@@ -349,22 +348,16 @@ struct snd_soc_dai wm8711_dai = {
349 }, 348 },
350 .ops = &wm8711_ops, 349 .ops = &wm8711_ops,
351}; 350};
352EXPORT_SYMBOL_GPL(wm8711_dai);
353 351
354static int wm8711_suspend(struct platform_device *pdev, pm_message_t state) 352static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
355{ 353{
356 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
357 struct snd_soc_codec *codec = socdev->card->codec;
358
359 snd_soc_write(codec, WM8711_ACTIVE, 0x0); 354 snd_soc_write(codec, WM8711_ACTIVE, 0x0);
360 wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); 355 wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
361 return 0; 356 return 0;
362} 357}
363 358
364static int wm8711_resume(struct platform_device *pdev) 359static int wm8711_resume(struct snd_soc_codec *codec)
365{ 360{
366 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
367 struct snd_soc_codec *codec = socdev->card->codec;
368 int i; 361 int i;
369 u8 data[2]; 362 u8 data[2];
370 u16 *cache = codec->reg_cache; 363 u16 *cache = codec->reg_cache;
@@ -380,99 +373,24 @@ static int wm8711_resume(struct platform_device *pdev)
380 return 0; 373 return 0;
381} 374}
382 375
383static int wm8711_probe(struct platform_device *pdev) 376static int wm8711_probe(struct snd_soc_codec *codec)
384{ 377{
385 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 378 struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
386 struct snd_soc_codec *codec; 379 int ret, reg;
387 int ret = 0;
388
389 if (wm8711_codec == NULL) {
390 dev_err(&pdev->dev, "Codec device not registered\n");
391 return -ENODEV;
392 }
393
394 socdev->card->codec = wm8711_codec;
395 codec = wm8711_codec;
396
397 /* register pcms */
398 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
399 if (ret < 0) {
400 dev_err(codec->dev, "failed to create pcms: %d\n", ret);
401 goto pcm_err;
402 }
403
404 snd_soc_add_controls(codec, wm8711_snd_controls,
405 ARRAY_SIZE(wm8711_snd_controls));
406 wm8711_add_widgets(codec);
407
408 return ret;
409
410pcm_err:
411 return ret;
412}
413
414/* power down chip */
415static int wm8711_remove(struct platform_device *pdev)
416{
417 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
418
419 snd_soc_free_pcms(socdev);
420 snd_soc_dapm_free(socdev);
421
422 return 0;
423}
424
425struct snd_soc_codec_device soc_codec_dev_wm8711 = {
426 .probe = wm8711_probe,
427 .remove = wm8711_remove,
428 .suspend = wm8711_suspend,
429 .resume = wm8711_resume,
430};
431EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711);
432
433static int wm8711_register(struct wm8711_priv *wm8711,
434 enum snd_soc_control_type control)
435{
436 int ret;
437 struct snd_soc_codec *codec = &wm8711->codec;
438 u16 reg;
439
440 if (wm8711_codec) {
441 dev_err(codec->dev, "Another WM8711 is registered\n");
442 ret = -EINVAL;
443 goto err;
444 }
445
446 mutex_init(&codec->mutex);
447 INIT_LIST_HEAD(&codec->dapm_widgets);
448 INIT_LIST_HEAD(&codec->dapm_paths);
449
450 snd_soc_codec_set_drvdata(codec, wm8711);
451 codec->name = "WM8711";
452 codec->owner = THIS_MODULE;
453 codec->bias_level = SND_SOC_BIAS_OFF;
454 codec->set_bias_level = wm8711_set_bias_level;
455 codec->dai = &wm8711_dai;
456 codec->num_dai = 1;
457 codec->reg_cache_size = WM8711_CACHEREGNUM;
458 codec->reg_cache = &wm8711->reg_cache;
459
460 memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg));
461 380
462 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); 381 codec->control_data = wm8711->control_data;
382 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
463 if (ret < 0) { 383 if (ret < 0) {
464 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); 384 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
465 goto err; 385 return ret;
466 } 386 }
467 387
468 ret = wm8711_reset(codec); 388 ret = wm8711_reset(codec);
469 if (ret < 0) { 389 if (ret < 0) {
470 dev_err(codec->dev, "Failed to issue reset\n"); 390 dev_err(codec->dev, "Failed to issue reset\n");
471 goto err; 391 return ret;
472 } 392 }
473 393
474 wm8711_dai.dev = codec->dev;
475
476 wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 394 wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
477 395
478 /* Latch the update bits */ 396 /* Latch the update bits */
@@ -481,69 +399,63 @@ static int wm8711_register(struct wm8711_priv *wm8711,
481 reg = snd_soc_read(codec, WM8711_ROUT1V); 399 reg = snd_soc_read(codec, WM8711_ROUT1V);
482 snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100); 400 snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
483 401
484 wm8711_codec = codec; 402 snd_soc_add_controls(codec, wm8711_snd_controls,
485 403 ARRAY_SIZE(wm8711_snd_controls));
486 ret = snd_soc_register_codec(codec); 404 wm8711_add_widgets(codec);
487 if (ret != 0) {
488 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
489 goto err;
490 }
491
492 ret = snd_soc_register_dai(&wm8711_dai);
493 if (ret != 0) {
494 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
495 goto err_codec;
496 }
497
498 return 0;
499 405
500err_codec:
501 snd_soc_unregister_codec(codec);
502err:
503 kfree(wm8711);
504 return ret; 406 return ret;
407
505} 408}
506 409
507static void wm8711_unregister(struct wm8711_priv *wm8711) 410/* power down chip */
411static int wm8711_remove(struct snd_soc_codec *codec)
508{ 412{
509 wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF); 413 wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
510 snd_soc_unregister_dai(&wm8711_dai); 414 return 0;
511 snd_soc_unregister_codec(&wm8711->codec);
512 kfree(wm8711);
513 wm8711_codec = NULL;
514} 415}
515 416
417static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
418 .probe = wm8711_probe,
419 .remove = wm8711_remove,
420 .suspend = wm8711_suspend,
421 .resume = wm8711_resume,
422 .set_bias_level = wm8711_set_bias_level,
423 .reg_cache_size = sizeof(wm8711_reg),
424 .reg_word_size = sizeof(u16),
425 .reg_cache_default = wm8711_reg,
426};
427
516#if defined(CONFIG_SPI_MASTER) 428#if defined(CONFIG_SPI_MASTER)
517static int __devinit wm8711_spi_probe(struct spi_device *spi) 429static int __devinit wm8711_spi_probe(struct spi_device *spi)
518{ 430{
519 struct snd_soc_codec *codec;
520 struct wm8711_priv *wm8711; 431 struct wm8711_priv *wm8711;
432 int ret;
521 433
522 wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); 434 wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
523 if (wm8711 == NULL) 435 if (wm8711 == NULL)
524 return -ENOMEM; 436 return -ENOMEM;
525 437
526 codec = &wm8711->codec; 438 spi_set_drvdata(spi, wm8711);
527 codec->control_data = spi; 439 wm8711->control_data = spi;
528 codec->dev = &spi->dev; 440 wm8711->bus_type = SND_SOC_SPI;
529 441
530 dev_set_drvdata(&spi->dev, wm8711); 442 ret = snd_soc_register_codec(&spi->dev,
531 443 &soc_codec_dev_wm8711, &wm8711_dai, 1);
532 return wm8711_register(wm8711, SND_SOC_SPI); 444 if (ret < 0)
445 kfree(wm8711);
446 return ret;
533} 447}
534 448
535static int __devexit wm8711_spi_remove(struct spi_device *spi) 449static int __devexit wm8711_spi_remove(struct spi_device *spi)
536{ 450{
537 struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev); 451 snd_soc_unregister_codec(&spi->dev);
538 452 kfree(spi_get_drvdata(spi));
539 wm8711_unregister(wm8711);
540
541 return 0; 453 return 0;
542} 454}
543 455
544static struct spi_driver wm8711_spi_driver = { 456static struct spi_driver wm8711_spi_driver = {
545 .driver = { 457 .driver = {
546 .name = "wm8711", 458 .name = "wm8711-codec",
547 .bus = &spi_bus_type, 459 .bus = &spi_bus_type,
548 .owner = THIS_MODULE, 460 .owner = THIS_MODULE,
549 }, 461 },
@@ -553,31 +465,31 @@ static struct spi_driver wm8711_spi_driver = {
553#endif /* CONFIG_SPI_MASTER */ 465#endif /* CONFIG_SPI_MASTER */
554 466
555#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 467#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
556static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, 468static __devinit int wm8711_i2c_probe(struct i2c_client *client,
557 const struct i2c_device_id *id) 469 const struct i2c_device_id *id)
558{ 470{
559 struct wm8711_priv *wm8711; 471 struct wm8711_priv *wm8711;
560 struct snd_soc_codec *codec; 472 int ret;
561 473
562 wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); 474 wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL);
563 if (wm8711 == NULL) 475 if (wm8711 == NULL)
564 return -ENOMEM; 476 return -ENOMEM;
565 477
566 codec = &wm8711->codec; 478 i2c_set_clientdata(client, wm8711);
567 codec->hw_write = (hw_write_t)i2c_master_send; 479 wm8711->control_data = client;
568 480 wm8711->bus_type = SND_SOC_I2C;
569 i2c_set_clientdata(i2c, wm8711);
570 codec->control_data = i2c;
571 481
572 codec->dev = &i2c->dev; 482 ret = snd_soc_register_codec(&client->dev,
573 483 &soc_codec_dev_wm8711, &wm8711_dai, 1);
574 return wm8711_register(wm8711, SND_SOC_I2C); 484 if (ret < 0)
485 kfree(wm8711);
486 return ret;
575} 487}
576 488
577static __devexit int wm8711_i2c_remove(struct i2c_client *client) 489static __devexit int wm8711_i2c_remove(struct i2c_client *client)
578{ 490{
579 struct wm8711_priv *wm8711 = i2c_get_clientdata(client); 491 snd_soc_unregister_codec(&client->dev);
580 wm8711_unregister(wm8711); 492 kfree(i2c_get_clientdata(client));
581 return 0; 493 return 0;
582} 494}
583 495
@@ -589,7 +501,7 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
589 501
590static struct i2c_driver wm8711_i2c_driver = { 502static struct i2c_driver wm8711_i2c_driver = {
591 .driver = { 503 .driver = {
592 .name = "WM8711 I2C Codec", 504 .name = "wm8711-codec",
593 .owner = THIS_MODULE, 505 .owner = THIS_MODULE,
594 }, 506 },
595 .probe = wm8711_i2c_probe, 507 .probe = wm8711_i2c_probe,