diff options
Diffstat (limited to 'sound/soc/codecs/wm8510.c')
-rw-r--r-- | sound/soc/codecs/wm8510.c | 290 |
1 files changed, 98 insertions, 192 deletions
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 0f7bcb61071a..dbfa05d2cb92 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -31,8 +31,6 @@ | |||
31 | 31 | ||
32 | #define WM8510_VERSION "0.6" | 32 | #define WM8510_VERSION "0.6" |
33 | 33 | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8510; | ||
35 | |||
36 | /* | 34 | /* |
37 | * wm8510 register cache | 35 | * wm8510 register cache |
38 | * We can't read the WM8510 register space when we are | 36 | * We can't read the WM8510 register space when we are |
@@ -61,6 +59,12 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { | |||
61 | 59 | ||
62 | #define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) | 60 | #define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) |
63 | 61 | ||
62 | /* codec private data */ | ||
63 | struct wm8510_priv { | ||
64 | enum snd_soc_control_type control_type; | ||
65 | void *control_data; | ||
66 | }; | ||
67 | |||
64 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; | 68 | static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; |
65 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; | 69 | static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; |
66 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; | 70 | static const char *wm8510_alc[] = { "ALC", "Limiter" }; |
@@ -403,8 +407,7 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, | |||
403 | struct snd_soc_dai *dai) | 407 | struct snd_soc_dai *dai) |
404 | { | 408 | { |
405 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 409 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
406 | struct snd_soc_device *socdev = rtd->socdev; | 410 | struct snd_soc_codec *codec = rtd->codec; |
407 | struct snd_soc_codec *codec = socdev->card->codec; | ||
408 | u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; | 411 | u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; |
409 | u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; | 412 | u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; |
410 | 413 | ||
@@ -514,8 +517,8 @@ static struct snd_soc_dai_ops wm8510_dai_ops = { | |||
514 | .set_pll = wm8510_set_dai_pll, | 517 | .set_pll = wm8510_set_dai_pll, |
515 | }; | 518 | }; |
516 | 519 | ||
517 | struct snd_soc_dai wm8510_dai = { | 520 | static struct snd_soc_dai_driver wm8510_dai = { |
518 | .name = "WM8510 HiFi", | 521 | .name = "wm8510-hifi", |
519 | .playback = { | 522 | .playback = { |
520 | .stream_name = "Playback", | 523 | .stream_name = "Playback", |
521 | .channels_min = 2, | 524 | .channels_min = 2, |
@@ -531,21 +534,15 @@ struct snd_soc_dai wm8510_dai = { | |||
531 | .ops = &wm8510_dai_ops, | 534 | .ops = &wm8510_dai_ops, |
532 | .symmetric_rates = 1, | 535 | .symmetric_rates = 1, |
533 | }; | 536 | }; |
534 | EXPORT_SYMBOL_GPL(wm8510_dai); | ||
535 | 537 | ||
536 | static int wm8510_suspend(struct platform_device *pdev, pm_message_t state) | 538 | static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state) |
537 | { | 539 | { |
538 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
539 | struct snd_soc_codec *codec = socdev->card->codec; | ||
540 | |||
541 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | 540 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
542 | return 0; | 541 | return 0; |
543 | } | 542 | } |
544 | 543 | ||
545 | static int wm8510_resume(struct platform_device *pdev) | 544 | static int wm8510_resume(struct snd_soc_codec *codec) |
546 | { | 545 | { |
547 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
548 | struct snd_soc_codec *codec = socdev->card->codec; | ||
549 | int i; | 546 | int i; |
550 | u8 data[2]; | 547 | u8 data[2]; |
551 | u16 *cache = codec->reg_cache; | 548 | u16 *cache = codec->reg_cache; |
@@ -561,43 +558,22 @@ static int wm8510_resume(struct platform_device *pdev) | |||
561 | return 0; | 558 | return 0; |
562 | } | 559 | } |
563 | 560 | ||
564 | /* | 561 | static int wm8510_probe(struct snd_soc_codec *codec) |
565 | * initialise the WM8510 driver | ||
566 | * register the mixer and dsp interfaces with the kernel | ||
567 | */ | ||
568 | static int wm8510_init(struct snd_soc_device *socdev, | ||
569 | enum snd_soc_control_type control) | ||
570 | { | 562 | { |
571 | struct snd_soc_codec *codec = socdev->card->codec; | 563 | struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec); |
572 | int ret = 0; | 564 | int ret; |
573 | |||
574 | codec->name = "WM8510"; | ||
575 | codec->owner = THIS_MODULE; | ||
576 | codec->set_bias_level = wm8510_set_bias_level; | ||
577 | codec->dai = &wm8510_dai; | ||
578 | codec->num_dai = 1; | ||
579 | codec->reg_cache_size = ARRAY_SIZE(wm8510_reg); | ||
580 | codec->reg_cache = kmemdup(wm8510_reg, sizeof(wm8510_reg), GFP_KERNEL); | ||
581 | 565 | ||
582 | if (codec->reg_cache == NULL) | 566 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); |
583 | return -ENOMEM; | ||
584 | 567 | ||
585 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 568 | codec->control_data = wm8510->control_data; |
569 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8510->control_type); | ||
586 | if (ret < 0) { | 570 | if (ret < 0) { |
587 | printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", | 571 | printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", ret); |
588 | ret); | 572 | return ret; |
589 | goto err; | ||
590 | } | 573 | } |
591 | 574 | ||
592 | wm8510_reset(codec); | 575 | wm8510_reset(codec); |
593 | 576 | ||
594 | /* register pcms */ | ||
595 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
596 | if (ret < 0) { | ||
597 | printk(KERN_ERR "wm8510: failed to create pcms\n"); | ||
598 | goto err; | ||
599 | } | ||
600 | |||
601 | /* power on device */ | 577 | /* power on device */ |
602 | codec->bias_level = SND_SOC_BIAS_OFF; | 578 | codec->bias_level = SND_SOC_BIAS_OFF; |
603 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 579 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -606,119 +582,53 @@ static int wm8510_init(struct snd_soc_device *socdev, | |||
606 | wm8510_add_widgets(codec); | 582 | wm8510_add_widgets(codec); |
607 | 583 | ||
608 | return ret; | 584 | return ret; |
609 | |||
610 | err: | ||
611 | kfree(codec->reg_cache); | ||
612 | return ret; | ||
613 | } | 585 | } |
614 | 586 | ||
615 | static struct snd_soc_device *wm8510_socdev; | 587 | /* power down chip */ |
616 | 588 | static int wm8510_remove(struct snd_soc_codec *codec) | |
617 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
618 | |||
619 | /* | ||
620 | * WM8510 2 wire address is 0x1a | ||
621 | */ | ||
622 | |||
623 | static int wm8510_i2c_probe(struct i2c_client *i2c, | ||
624 | const struct i2c_device_id *id) | ||
625 | { | 589 | { |
626 | struct snd_soc_device *socdev = wm8510_socdev; | 590 | struct wm8510_priv *wm8510 = snd_soc_codec_get_drvdata(codec); |
627 | struct snd_soc_codec *codec = socdev->card->codec; | ||
628 | int ret; | ||
629 | |||
630 | i2c_set_clientdata(i2c, codec); | ||
631 | codec->control_data = i2c; | ||
632 | |||
633 | ret = wm8510_init(socdev, SND_SOC_I2C); | ||
634 | if (ret < 0) | ||
635 | pr_err("failed to initialise WM8510\n"); | ||
636 | |||
637 | return ret; | ||
638 | } | ||
639 | 591 | ||
640 | static int wm8510_i2c_remove(struct i2c_client *client) | 592 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); |
641 | { | 593 | kfree(wm8510); |
642 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | ||
643 | kfree(codec->reg_cache); | ||
644 | return 0; | 594 | return 0; |
645 | } | 595 | } |
646 | 596 | ||
647 | static const struct i2c_device_id wm8510_i2c_id[] = { | 597 | static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { |
648 | { "wm8510", 0 }, | 598 | .probe = wm8510_probe, |
649 | { } | 599 | .remove = wm8510_remove, |
650 | }; | 600 | .suspend = wm8510_suspend, |
651 | MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); | 601 | .resume = wm8510_resume, |
652 | 602 | .set_bias_level = wm8510_set_bias_level, | |
653 | static struct i2c_driver wm8510_i2c_driver = { | 603 | .reg_cache_size = ARRAY_SIZE(wm8510_reg), |
654 | .driver = { | 604 | .reg_word_size = sizeof(u16), |
655 | .name = "WM8510 I2C Codec", | 605 | .reg_cache_default =wm8510_reg, |
656 | .owner = THIS_MODULE, | ||
657 | }, | ||
658 | .probe = wm8510_i2c_probe, | ||
659 | .remove = wm8510_i2c_remove, | ||
660 | .id_table = wm8510_i2c_id, | ||
661 | }; | 606 | }; |
662 | 607 | ||
663 | static int wm8510_add_i2c_device(struct platform_device *pdev, | ||
664 | const struct wm8510_setup_data *setup) | ||
665 | { | ||
666 | struct i2c_board_info info; | ||
667 | struct i2c_adapter *adapter; | ||
668 | struct i2c_client *client; | ||
669 | int ret; | ||
670 | |||
671 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
672 | if (ret != 0) { | ||
673 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
674 | return ret; | ||
675 | } | ||
676 | |||
677 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
678 | info.addr = setup->i2c_address; | ||
679 | strlcpy(info.type, "wm8510", I2C_NAME_SIZE); | ||
680 | |||
681 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
682 | if (!adapter) { | ||
683 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
684 | setup->i2c_bus); | ||
685 | goto err_driver; | ||
686 | } | ||
687 | |||
688 | client = i2c_new_device(adapter, &info); | ||
689 | i2c_put_adapter(adapter); | ||
690 | if (!client) { | ||
691 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
692 | (unsigned int)info.addr); | ||
693 | goto err_driver; | ||
694 | } | ||
695 | |||
696 | return 0; | ||
697 | |||
698 | err_driver: | ||
699 | i2c_del_driver(&wm8510_i2c_driver); | ||
700 | return -ENODEV; | ||
701 | } | ||
702 | #endif | ||
703 | |||
704 | #if defined(CONFIG_SPI_MASTER) | 608 | #if defined(CONFIG_SPI_MASTER) |
705 | static int __devinit wm8510_spi_probe(struct spi_device *spi) | 609 | static int __devinit wm8510_spi_probe(struct spi_device *spi) |
706 | { | 610 | { |
707 | struct snd_soc_device *socdev = wm8510_socdev; | 611 | struct wm8510_priv *wm8510; |
708 | struct snd_soc_codec *codec = socdev->card->codec; | ||
709 | int ret; | 612 | int ret; |
710 | 613 | ||
711 | codec->control_data = spi; | 614 | wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL); |
615 | if (wm8510 == NULL) | ||
616 | return -ENOMEM; | ||
617 | |||
618 | wm8510->control_data = spi; | ||
619 | wm8510->control_type = SND_SOC_SPI; | ||
620 | spi_set_drvdata(spi, wm8510); | ||
712 | 621 | ||
713 | ret = wm8510_init(socdev, SND_SOC_SPI); | 622 | ret = snd_soc_register_codec(&spi->dev, |
623 | &soc_codec_dev_wm8510, &wm8510_dai, 1); | ||
714 | if (ret < 0) | 624 | if (ret < 0) |
715 | dev_err(&spi->dev, "failed to initialise WM8510\n"); | 625 | kfree(wm8510); |
716 | |||
717 | return ret; | 626 | return ret; |
718 | } | 627 | } |
719 | 628 | ||
720 | static int __devexit wm8510_spi_remove(struct spi_device *spi) | 629 | static int __devexit wm8510_spi_remove(struct spi_device *spi) |
721 | { | 630 | { |
631 | snd_soc_unregister_codec(&spi->dev); | ||
722 | return 0; | 632 | return 0; |
723 | } | 633 | } |
724 | 634 | ||
@@ -733,84 +643,80 @@ static struct spi_driver wm8510_spi_driver = { | |||
733 | }; | 643 | }; |
734 | #endif /* CONFIG_SPI_MASTER */ | 644 | #endif /* CONFIG_SPI_MASTER */ |
735 | 645 | ||
736 | static int wm8510_probe(struct platform_device *pdev) | 646 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
647 | static __devinit int wm8510_i2c_probe(struct i2c_client *i2c, | ||
648 | const struct i2c_device_id *id) | ||
737 | { | 649 | { |
738 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 650 | struct wm8510_priv *wm8510; |
739 | struct wm8510_setup_data *setup; | 651 | int ret; |
740 | struct snd_soc_codec *codec; | ||
741 | int ret = 0; | ||
742 | |||
743 | pr_info("WM8510 Audio Codec %s", WM8510_VERSION); | ||
744 | 652 | ||
745 | setup = socdev->codec_data; | 653 | wm8510 = kzalloc(sizeof(struct wm8510_priv), GFP_KERNEL); |
746 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 654 | if (wm8510 == NULL) |
747 | if (codec == NULL) | ||
748 | return -ENOMEM; | 655 | return -ENOMEM; |
749 | 656 | ||
750 | socdev->card->codec = codec; | 657 | i2c_set_clientdata(i2c, wm8510); |
751 | mutex_init(&codec->mutex); | 658 | wm8510->control_data = i2c; |
752 | INIT_LIST_HEAD(&codec->dapm_widgets); | 659 | wm8510->control_type = SND_SOC_I2C; |
753 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
754 | 660 | ||
755 | wm8510_socdev = socdev; | 661 | ret = snd_soc_register_codec(&i2c->dev, |
756 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 662 | &soc_codec_dev_wm8510, &wm8510_dai, 1); |
757 | if (setup->i2c_address) { | 663 | if (ret < 0) |
758 | ret = wm8510_add_i2c_device(pdev, setup); | 664 | kfree(wm8510); |
759 | } | ||
760 | #endif | ||
761 | #if defined(CONFIG_SPI_MASTER) | ||
762 | if (setup->spi) { | ||
763 | ret = spi_register_driver(&wm8510_spi_driver); | ||
764 | if (ret != 0) | ||
765 | printk(KERN_ERR "can't add spi driver"); | ||
766 | } | ||
767 | #endif | ||
768 | |||
769 | if (ret != 0) | ||
770 | kfree(codec); | ||
771 | return ret; | 665 | return ret; |
772 | } | 666 | } |
773 | 667 | ||
774 | /* power down chip */ | 668 | static __devexit int wm8510_i2c_remove(struct i2c_client *client) |
775 | static int wm8510_remove(struct platform_device *pdev) | ||
776 | { | 669 | { |
777 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 670 | snd_soc_unregister_codec(&client->dev); |
778 | struct snd_soc_codec *codec = socdev->card->codec; | ||
779 | |||
780 | if (codec->control_data) | ||
781 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
782 | |||
783 | snd_soc_free_pcms(socdev); | ||
784 | snd_soc_dapm_free(socdev); | ||
785 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
786 | i2c_unregister_device(codec->control_data); | ||
787 | i2c_del_driver(&wm8510_i2c_driver); | ||
788 | #endif | ||
789 | #if defined(CONFIG_SPI_MASTER) | ||
790 | spi_unregister_driver(&wm8510_spi_driver); | ||
791 | #endif | ||
792 | kfree(codec); | ||
793 | |||
794 | return 0; | 671 | return 0; |
795 | } | 672 | } |
796 | 673 | ||
797 | struct snd_soc_codec_device soc_codec_dev_wm8510 = { | 674 | static const struct i2c_device_id wm8510_i2c_id[] = { |
798 | .probe = wm8510_probe, | 675 | { "wm8510", 0 }, |
799 | .remove = wm8510_remove, | 676 | { } |
800 | .suspend = wm8510_suspend, | 677 | }; |
801 | .resume = wm8510_resume, | 678 | MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); |
679 | |||
680 | static struct i2c_driver wm8510_i2c_driver = { | ||
681 | .driver = { | ||
682 | .name = "wm8510-codec", | ||
683 | .owner = THIS_MODULE, | ||
684 | }, | ||
685 | .probe = wm8510_i2c_probe, | ||
686 | .remove = __devexit_p(wm8510_i2c_remove), | ||
687 | .id_table = wm8510_i2c_id, | ||
802 | }; | 688 | }; |
803 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8510); | 689 | #endif |
804 | 690 | ||
805 | static int __init wm8510_modinit(void) | 691 | static int __init wm8510_modinit(void) |
806 | { | 692 | { |
807 | return snd_soc_register_dai(&wm8510_dai); | 693 | int ret = 0; |
694 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
695 | ret = i2c_add_driver(&wm8510_i2c_driver); | ||
696 | if (ret != 0) { | ||
697 | printk(KERN_ERR "Failed to register WM8510 I2C driver: %d\n", | ||
698 | ret); | ||
699 | } | ||
700 | #endif | ||
701 | #if defined(CONFIG_SPI_MASTER) | ||
702 | ret = spi_register_driver(&wm8510_spi_driver); | ||
703 | if (ret != 0) { | ||
704 | printk(KERN_ERR "Failed to register WM8510 SPI driver: %d\n", | ||
705 | ret); | ||
706 | } | ||
707 | #endif | ||
708 | return ret; | ||
808 | } | 709 | } |
809 | module_init(wm8510_modinit); | 710 | module_init(wm8510_modinit); |
810 | 711 | ||
811 | static void __exit wm8510_exit(void) | 712 | static void __exit wm8510_exit(void) |
812 | { | 713 | { |
813 | snd_soc_unregister_dai(&wm8510_dai); | 714 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
715 | i2c_del_driver(&wm8510_i2c_driver); | ||
716 | #endif | ||
717 | #if defined(CONFIG_SPI_MASTER) | ||
718 | spi_unregister_driver(&wm8510_spi_driver); | ||
719 | #endif | ||
814 | } | 720 | } |
815 | module_exit(wm8510_exit); | 721 | module_exit(wm8510_exit); |
816 | 722 | ||