aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/ak4535.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/ak4535.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/ak4535.c')
-rw-r--r--sound/soc/codecs/ak4535.c236
1 files changed, 61 insertions, 175 deletions
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index d4253675b2d3..cd88c8f32a38 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -31,11 +31,11 @@
31 31
32#define AK4535_VERSION "0.3" 32#define AK4535_VERSION "0.3"
33 33
34struct snd_soc_codec_device soc_codec_dev_ak4535;
35
36/* codec private data */ 34/* codec private data */
37struct ak4535_priv { 35struct ak4535_priv {
38 unsigned int sysclk; 36 unsigned int sysclk;
37 enum snd_soc_control_type control_type;
38 void *control_data;
39}; 39};
40 40
41/* 41/*
@@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
313 struct snd_soc_dai *dai) 313 struct snd_soc_dai *dai)
314{ 314{
315 struct snd_soc_pcm_runtime *rtd = substream->private_data; 315 struct snd_soc_pcm_runtime *rtd = substream->private_data;
316 struct snd_soc_device *socdev = rtd->socdev; 316 struct snd_soc_codec *codec = rtd->codec;
317 struct snd_soc_codec *codec = socdev->card->codec;
318 struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec); 317 struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
319 u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); 318 u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
320 int rate = params_rate(params), fs = 256; 319 int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
378static int ak4535_set_bias_level(struct snd_soc_codec *codec, 377static int ak4535_set_bias_level(struct snd_soc_codec *codec,
379 enum snd_soc_bias_level level) 378 enum snd_soc_bias_level level)
380{ 379{
381 u16 i; 380 u16 i, mute_reg;
382 381
383 switch (level) { 382 switch (level) {
384 case SND_SOC_BIAS_ON: 383 case SND_SOC_BIAS_ON:
385 ak4535_mute(codec->dai, 0); 384 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
385 ak4535_write(codec, AK4535_DAC, mute_reg);
386 break; 386 break;
387 case SND_SOC_BIAS_PREPARE: 387 case SND_SOC_BIAS_PREPARE:
388 ak4535_mute(codec->dai, 1); 388 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
389 ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
389 break; 390 break;
390 case SND_SOC_BIAS_STANDBY: 391 case SND_SOC_BIAS_STANDBY:
391 i = ak4535_read_reg_cache(codec, AK4535_PM1); 392 i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
413 .set_sysclk = ak4535_set_dai_sysclk, 414 .set_sysclk = ak4535_set_dai_sysclk,
414}; 415};
415 416
416struct snd_soc_dai ak4535_dai = { 417static struct snd_soc_dai_driver ak4535_dai = {
417 .name = "AK4535", 418 .name = "ak4535-hifi",
418 .playback = { 419 .playback = {
419 .stream_name = "Playback", 420 .stream_name = "Playback",
420 .channels_min = 1, 421 .channels_min = 1,
@@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
429 .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 430 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
430 .ops = &ak4535_dai_ops, 431 .ops = &ak4535_dai_ops,
431}; 432};
432EXPORT_SYMBOL_GPL(ak4535_dai);
433 433
434static int ak4535_suspend(struct platform_device *pdev, pm_message_t state) 434static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
435{ 435{
436 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
437 struct snd_soc_codec *codec = socdev->card->codec;
438
439 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); 436 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
440 return 0; 437 return 0;
441} 438}
442 439
443static int ak4535_resume(struct platform_device *pdev) 440static int ak4535_resume(struct snd_soc_codec *codec)
444{ 441{
445 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
446 struct snd_soc_codec *codec = socdev->card->codec;
447 ak4535_sync(codec); 442 ak4535_sync(codec);
448 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 443 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
449 return 0; 444 return 0;
450} 445}
451 446
452/* 447static int ak4535_probe(struct snd_soc_codec *codec)
453 * initialise the AK4535 driver
454 * register the mixer and dsp interfaces with the kernel
455 */
456static int ak4535_init(struct snd_soc_device *socdev)
457{ 448{
458 struct snd_soc_codec *codec = socdev->card->codec; 449 struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
459 int ret = 0;
460 450
461 codec->name = "AK4535"; 451 printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
462 codec->owner = THIS_MODULE;
463 codec->read = ak4535_read_reg_cache;
464 codec->write = ak4535_write;
465 codec->set_bias_level = ak4535_set_bias_level;
466 codec->dai = &ak4535_dai;
467 codec->num_dai = 1;
468 codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
469 codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
470
471 if (codec->reg_cache == NULL)
472 return -ENOMEM;
473 452
474 /* register pcms */ 453 codec->control_data = ak4535->control_data;
475 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
476 if (ret < 0) {
477 printk(KERN_ERR "ak4535: failed to create pcms\n");
478 goto pcm_err;
479 }
480 454
481 /* power on device */ 455 /* power on device */
482 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 456 ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
485 ARRAY_SIZE(ak4535_snd_controls)); 459 ARRAY_SIZE(ak4535_snd_controls));
486 ak4535_add_widgets(codec); 460 ak4535_add_widgets(codec);
487 461
488 return ret; 462 return 0;
489 463}
490pcm_err:
491 kfree(codec->reg_cache);
492 464
493 return ret; 465/* power down chip */
466static int ak4535_remove(struct snd_soc_codec *codec)
467{
468 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
469 return 0;
494} 470}
495 471
496static struct snd_soc_device *ak4535_socdev; 472static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
473 .probe = ak4535_probe,
474 .remove = ak4535_remove,
475 .suspend = ak4535_suspend,
476 .resume = ak4535_resume,
477 .read = ak4535_read_reg_cache,
478 .write = ak4535_write,
479 .set_bias_level = ak4535_set_bias_level,
480 .reg_cache_size = ARRAY_SIZE(ak4535_reg),
481 .reg_word_size = sizeof(u8),
482 .reg_cache_default = ak4535_reg,
483};
497 484
498#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 485#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
499 486static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
500static int ak4535_i2c_probe(struct i2c_client *i2c, 487 const struct i2c_device_id *id)
501 const struct i2c_device_id *id)
502{ 488{
503 struct snd_soc_device *socdev = ak4535_socdev; 489 struct ak4535_priv *ak4535;
504 struct snd_soc_codec *codec = socdev->card->codec;
505 int ret; 490 int ret;
506 491
507 i2c_set_clientdata(i2c, codec); 492 ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
508 codec->control_data = i2c; 493 if (ak4535 == NULL)
494 return -ENOMEM;
509 495
510 ret = ak4535_init(socdev); 496 i2c_set_clientdata(i2c, ak4535);
511 if (ret < 0) 497 ak4535->control_data = i2c;
512 printk(KERN_ERR "failed to initialise AK4535\n"); 498 ak4535->control_type = SND_SOC_I2C;
513 499
500 ret = snd_soc_register_codec(&i2c->dev,
501 &soc_codec_dev_ak4535, &ak4535_dai, 1);
502 if (ret < 0)
503 kfree(ak4535);
514 return ret; 504 return ret;
515} 505}
516 506
517static int ak4535_i2c_remove(struct i2c_client *client) 507static __devexit int ak4535_i2c_remove(struct i2c_client *client)
518{ 508{
519 struct snd_soc_codec *codec = i2c_get_clientdata(client); 509 snd_soc_unregister_codec(&client->dev);
520 kfree(codec->reg_cache); 510 kfree(i2c_get_clientdata(client));
521 return 0; 511 return 0;
522} 512}
523 513
@@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
529 519
530static struct i2c_driver ak4535_i2c_driver = { 520static struct i2c_driver ak4535_i2c_driver = {
531 .driver = { 521 .driver = {
532 .name = "AK4535 I2C Codec", 522 .name = "ak4535-codec",
533 .owner = THIS_MODULE, 523 .owner = THIS_MODULE,
534 }, 524 },
535 .probe = ak4535_i2c_probe, 525 .probe = ak4535_i2c_probe,
536 .remove = ak4535_i2c_remove, 526 .remove = __devexit_p(ak4535_i2c_remove),
537 .id_table = ak4535_i2c_id, 527 .id_table = ak4535_i2c_id,
538}; 528};
539
540static int ak4535_add_i2c_device(struct platform_device *pdev,
541 const struct ak4535_setup_data *setup)
542{
543 struct i2c_board_info info;
544 struct i2c_adapter *adapter;
545 struct i2c_client *client;
546 int ret;
547
548 ret = i2c_add_driver(&ak4535_i2c_driver);
549 if (ret != 0) {
550 dev_err(&pdev->dev, "can't add i2c driver\n");
551 return ret;
552 }
553
554 memset(&info, 0, sizeof(struct i2c_board_info));
555 info.addr = setup->i2c_address;
556 strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
557
558 adapter = i2c_get_adapter(setup->i2c_bus);
559 if (!adapter) {
560 dev_err(&pdev->dev, "can't get i2c adapter %d\n",
561 setup->i2c_bus);
562 goto err_driver;
563 }
564
565 client = i2c_new_device(adapter, &info);
566 i2c_put_adapter(adapter);
567 if (!client) {
568 dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
569 (unsigned int)info.addr);
570 goto err_driver;
571 }
572
573 return 0;
574
575err_driver:
576 i2c_del_driver(&ak4535_i2c_driver);
577 return -ENODEV;
578}
579#endif 529#endif
580 530
581static int ak4535_probe(struct platform_device *pdev) 531static int __init ak4535_modinit(void)
582{ 532{
583 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 533 int ret = 0;
584 struct ak4535_setup_data *setup;
585 struct snd_soc_codec *codec;
586 struct ak4535_priv *ak4535;
587 int ret;
588
589 printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
590
591 setup = socdev->codec_data;
592 codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
593 if (codec == NULL)
594 return -ENOMEM;
595
596 ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
597 if (ak4535 == NULL) {
598 kfree(codec);
599 return -ENOMEM;
600 }
601
602 snd_soc_codec_set_drvdata(codec, ak4535);
603 socdev->card->codec = codec;
604 mutex_init(&codec->mutex);
605 INIT_LIST_HEAD(&codec->dapm_widgets);
606 INIT_LIST_HEAD(&codec->dapm_paths);
607
608 ak4535_socdev = socdev;
609 ret = -ENODEV;
610
611#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 534#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
612 if (setup->i2c_address) { 535 ret = i2c_add_driver(&ak4535_i2c_driver);
613 codec->hw_write = (hw_write_t)i2c_master_send;
614 ret = ak4535_add_i2c_device(pdev, setup);
615 }
616#endif
617
618 if (ret != 0) { 536 if (ret != 0) {
619 kfree(snd_soc_codec_get_drvdata(codec)); 537 printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
620 kfree(codec); 538 ret);
621 } 539 }
540#endif
622 return ret; 541 return ret;
623} 542}
543module_init(ak4535_modinit);
624 544
625/* power down chip */ 545static void __exit ak4535_exit(void)
626static int ak4535_remove(struct platform_device *pdev)
627{ 546{
628 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
629 struct snd_soc_codec *codec = socdev->card->codec;
630
631 if (codec->control_data)
632 ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
633
634 snd_soc_free_pcms(socdev);
635 snd_soc_dapm_free(socdev);
636#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 547#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
637 if (codec->control_data)
638 i2c_unregister_device(codec->control_data);
639 i2c_del_driver(&ak4535_i2c_driver); 548 i2c_del_driver(&ak4535_i2c_driver);
640#endif 549#endif
641 kfree(snd_soc_codec_get_drvdata(codec));
642 kfree(codec);
643
644 return 0;
645}
646
647struct snd_soc_codec_device soc_codec_dev_ak4535 = {
648 .probe = ak4535_probe,
649 .remove = ak4535_remove,
650 .suspend = ak4535_suspend,
651 .resume = ak4535_resume,
652};
653EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
654
655static int __init ak4535_modinit(void)
656{
657 return snd_soc_register_dai(&ak4535_dai);
658}
659module_init(ak4535_modinit);
660
661static void __exit ak4535_exit(void)
662{
663 snd_soc_unregister_dai(&ak4535_dai);
664} 550}
665module_exit(ak4535_exit); 551module_exit(ak4535_exit);
666 552