aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8741.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/wm8741.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/wm8741.c')
-rw-r--r--sound/soc/codecs/wm8741.c204
1 files changed, 57 insertions, 147 deletions
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c
index b9ea8904ad4b..0c6d59e4d226 100644
--- a/sound/soc/codecs/wm8741.c
+++ b/sound/soc/codecs/wm8741.c
@@ -30,9 +30,6 @@
30 30
31#include "wm8741.h" 31#include "wm8741.h"
32 32
33static struct snd_soc_codec *wm8741_codec;
34struct snd_soc_codec_device soc_codec_dev_wm8741;
35
36#define WM8741_NUM_SUPPLIES 2 33#define WM8741_NUM_SUPPLIES 2
37static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { 34static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
38 "AVDD", 35 "AVDD",
@@ -43,7 +40,8 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = {
43 40
44/* codec private data */ 41/* codec private data */
45struct wm8741_priv { 42struct wm8741_priv {
46 struct snd_soc_codec codec; 43 enum snd_soc_control_type control_type;
44 void *control_data;
47 u16 reg_cache[WM8741_REGISTER_COUNT]; 45 u16 reg_cache[WM8741_REGISTER_COUNT];
48 struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; 46 struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES];
49 unsigned int sysclk; 47 unsigned int sysclk;
@@ -145,8 +143,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream,
145 struct snd_soc_dai *dai) 143 struct snd_soc_dai *dai)
146{ 144{
147 struct snd_soc_pcm_runtime *rtd = substream->private_data; 145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
148 struct snd_soc_device *socdev = rtd->socdev; 146 struct snd_soc_codec *codec = rtd->codec;
149 struct snd_soc_codec *codec = socdev->card->codec;
150 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); 147 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
151 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; 148 u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC;
152 int i; 149 int i;
@@ -314,7 +311,7 @@ static struct snd_soc_dai_ops wm8741_dai_ops = {
314 .set_fmt = wm8741_set_dai_fmt, 311 .set_fmt = wm8741_set_dai_fmt,
315}; 312};
316 313
317struct snd_soc_dai wm8741_dai = { 314static struct snd_soc_dai_driver wm8741_dai = {
318 .name = "WM8741", 315 .name = "WM8741",
319 .playback = { 316 .playback = {
320 .stream_name = "Playback", 317 .stream_name = "Playback",
@@ -325,13 +322,10 @@ struct snd_soc_dai wm8741_dai = {
325 }, 322 },
326 .ops = &wm8741_dai_ops, 323 .ops = &wm8741_dai_ops,
327}; 324};
328EXPORT_SYMBOL_GPL(wm8741_dai);
329 325
330#ifdef CONFIG_PM 326#ifdef CONFIG_PM
331static int wm8741_resume(struct platform_device *pdev) 327static int wm8741_resume(struct snd_soc_codec *codec)
332{ 328{
333 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
334 struct snd_soc_codec *codec = socdev->card->codec;
335 u16 *cache = codec->reg_cache; 329 u16 *cache = codec->reg_cache;
336 int i; 330 int i;
337 331
@@ -348,189 +342,105 @@ static int wm8741_resume(struct platform_device *pdev)
348#define wm8741_resume NULL 342#define wm8741_resume NULL
349#endif 343#endif
350 344
351static int wm8741_probe(struct platform_device *pdev) 345static int wm8741_probe(struct snd_soc_codec *codec)
352{ 346{
353 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 347 struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
354 struct snd_soc_codec *codec;
355 int ret = 0; 348 int ret = 0;
356 349
357 if (wm8741_codec == NULL) { 350 codec->control_data = wm8741->control_data;
358 dev_err(&pdev->dev, "Codec device not registered\n"); 351 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
359 return -ENODEV; 352 if (ret != 0) {
353 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
354 return ret;
360 } 355 }
361 356
362 socdev->card->codec = wm8741_codec; 357 ret = wm8741_reset(codec);
363 codec = wm8741_codec;
364
365 /* register pcms */
366 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
367 if (ret < 0) { 358 if (ret < 0) {
368 dev_err(codec->dev, "failed to create pcms: %d\n", ret); 359 dev_err(codec->dev, "Failed to issue reset\n");
369 goto pcm_err; 360 return ret;
370 } 361 }
371 362
363 /* Change some default settings - latch VU */
364 wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
365 wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
366 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
367 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
368
372 snd_soc_add_controls(codec, wm8741_snd_controls, 369 snd_soc_add_controls(codec, wm8741_snd_controls,
373 ARRAY_SIZE(wm8741_snd_controls)); 370 ARRAY_SIZE(wm8741_snd_controls));
374 wm8741_add_widgets(codec); 371 wm8741_add_widgets(codec);
375 372
373 dev_dbg(codec->dev, "Successful registration\n");
376 return ret; 374 return ret;
377
378pcm_err:
379 return ret;
380}
381
382static int wm8741_remove(struct platform_device *pdev)
383{
384 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
385
386 snd_soc_free_pcms(socdev);
387 snd_soc_dapm_free(socdev);
388
389 return 0;
390} 375}
391 376
392struct snd_soc_codec_device soc_codec_dev_wm8741 = { 377static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
393 .probe = wm8741_probe, 378 .probe = wm8741_probe,
394 .remove = wm8741_remove,
395 .resume = wm8741_resume, 379 .resume = wm8741_resume,
380 .reg_cache_size = sizeof(wm8741_reg_defaults),
381 .reg_word_size = sizeof(u16),
382 .reg_cache_default = &wm8741_reg_defaults,
396}; 383};
397EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741);
398 384
399static int wm8741_register(struct wm8741_priv *wm8741, 385#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
400 enum snd_soc_control_type control) 386static int wm8741_i2c_probe(struct i2c_client *i2c,
387 const struct i2c_device_id *id)
401{ 388{
402 int ret; 389 struct wm8741_priv *wm8741;
403 struct snd_soc_codec *codec = &wm8741->codec; 390 int ret, i;
404 int i;
405
406 if (wm8741_codec) {
407 dev_err(codec->dev, "Another WM8741 is registered\n");
408 return -EINVAL;
409 }
410
411 mutex_init(&codec->mutex);
412 INIT_LIST_HEAD(&codec->dapm_widgets);
413 INIT_LIST_HEAD(&codec->dapm_paths);
414 391
415 snd_soc_codec_set_drvdata(codec, wm8741); 392 wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
416 codec->name = "WM8741"; 393 if (wm8741 == NULL)
417 codec->owner = THIS_MODULE; 394 return -ENOMEM;
418 codec->bias_level = SND_SOC_BIAS_OFF;
419 codec->set_bias_level = NULL;
420 codec->dai = &wm8741_dai;
421 codec->num_dai = 1;
422 codec->reg_cache_size = WM8741_REGISTER_COUNT;
423 codec->reg_cache = &wm8741->reg_cache;
424 395
425 wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; 396 wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0];
426 wm8741->rate_constraint.count = 397 wm8741->rate_constraint.count =
427 ARRAY_SIZE(wm8741->rate_constraint_list); 398 ARRAY_SIZE(wm8741->rate_constraint_list);
428 399
429 memcpy(codec->reg_cache, wm8741_reg_defaults,
430 sizeof(wm8741->reg_cache));
431
432 ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
433 if (ret != 0) {
434 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
435 goto err;
436 }
437
438 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) 400 for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
439 wm8741->supplies[i].supply = wm8741_supply_names[i]; 401 wm8741->supplies[i].supply = wm8741_supply_names[i];
440 402
441 ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), 403 ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
442 wm8741->supplies); 404 wm8741->supplies);
443 if (ret != 0) { 405 if (ret != 0) {
444 dev_err(codec->dev, "Failed to request supplies: %d\n", ret); 406 dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
445 goto err; 407 goto err;
446 } 408 }
447 409
448 ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), 410 ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
449 wm8741->supplies); 411 wm8741->supplies);
450 if (ret != 0) { 412 if (ret != 0) {
451 dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); 413 dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
452 goto err_get; 414 goto err_get;
453 } 415 }
454 416
455 ret = wm8741_reset(codec); 417 i2c_set_clientdata(i2c, wm8741);
456 if (ret < 0) { 418 wm8741->control_data = i2c;
457 dev_err(codec->dev, "Failed to issue reset\n"); 419 wm8741->control_type = SND_SOC_I2C;
458 goto err_enable;
459 }
460
461 wm8741_dai.dev = codec->dev;
462
463 /* Change some default settings - latch VU */
464 wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL;
465 wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM;
466 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL;
467 wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM;
468
469 wm8741_codec = codec;
470
471 ret = snd_soc_register_codec(codec);
472 if (ret != 0) {
473 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
474 return ret;
475 }
476
477 ret = snd_soc_register_dai(&wm8741_dai);
478 if (ret != 0) {
479 dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
480 snd_soc_unregister_codec(codec);
481 return ret;
482 }
483 420
484 dev_dbg(codec->dev, "Successful registration\n"); 421 ret = snd_soc_register_codec(&i2c->dev,
485 return 0; 422 &soc_codec_dev_wm8741, &wm8741_dai, 1);
423 if (ret < 0)
424 goto err_enable;
425 return ret;
486 426
487err_enable: 427err_enable:
488 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 428 regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
489 429
490err_get: 430err_get:
491 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); 431 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
492
493err: 432err:
494 kfree(wm8741); 433 kfree(wm8741);
495 return ret; 434 return ret;
496} 435}
497 436
498static void wm8741_unregister(struct wm8741_priv *wm8741) 437static int wm8741_i2c_remove(struct i2c_client *client)
499{
500 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
501
502 snd_soc_unregister_dai(&wm8741_dai);
503 snd_soc_unregister_codec(&wm8741->codec);
504 kfree(wm8741);
505 wm8741_codec = NULL;
506}
507
508#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
509static __devinit int wm8741_i2c_probe(struct i2c_client *i2c,
510 const struct i2c_device_id *id)
511{
512 struct wm8741_priv *wm8741;
513 struct snd_soc_codec *codec;
514
515 wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
516 if (wm8741 == NULL)
517 return -ENOMEM;
518
519 codec = &wm8741->codec;
520 codec->hw_write = (hw_write_t)i2c_master_send;
521
522 i2c_set_clientdata(i2c, wm8741);
523 codec->control_data = i2c;
524
525 codec->dev = &i2c->dev;
526
527 return wm8741_register(wm8741, SND_SOC_I2C);
528}
529
530static __devexit int wm8741_i2c_remove(struct i2c_client *client)
531{ 438{
532 struct wm8741_priv *wm8741 = i2c_get_clientdata(client); 439 struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
533 wm8741_unregister(wm8741); 440
441 snd_soc_unregister_codec(&client->dev);
442 regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
443 kfree(i2c_get_clientdata(client));
534 return 0; 444 return 0;
535} 445}
536 446
@@ -540,29 +450,29 @@ static const struct i2c_device_id wm8741_i2c_id[] = {
540}; 450};
541MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); 451MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
542 452
543
544static struct i2c_driver wm8741_i2c_driver = { 453static struct i2c_driver wm8741_i2c_driver = {
545 .driver = { 454 .driver = {
546 .name = "WM8741", 455 .name = "wm8741-codec",
547 .owner = THIS_MODULE, 456 .owner = THIS_MODULE,
548 }, 457 },
549 .probe = wm8741_i2c_probe, 458 .probe = wm8741_i2c_probe,
550 .remove = __devexit_p(wm8741_i2c_remove), 459 .remove = wm8741_i2c_remove,
551 .id_table = wm8741_i2c_id, 460 .id_table = wm8741_i2c_id,
552}; 461};
553#endif 462#endif
554 463
555static int __init wm8741_modinit(void) 464static int __init wm8741_modinit(void)
556{ 465{
557 int ret; 466 int ret = 0;
467
558#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 468#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
559 ret = i2c_add_driver(&wm8741_i2c_driver); 469 ret = i2c_add_driver(&wm8741_i2c_driver);
560 if (ret != 0) { 470 if (ret != 0) {
561 printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", 471 pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
562 ret);
563 } 472 }
564#endif 473#endif
565 return 0; 474
475 return ret;
566} 476}
567module_init(wm8741_modinit); 477module_init(wm8741_modinit);
568 478