diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic23.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic23.c | 182 |
1 files changed, 60 insertions, 122 deletions
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 0a4b0fef3355..e8652b1ae326 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -240,7 +240,8 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
240 | 240 | ||
241 | /* AIC23 driver data */ | 241 | /* AIC23 driver data */ |
242 | struct aic23 { | 242 | struct aic23 { |
243 | struct snd_soc_codec codec; | 243 | enum snd_soc_control_type control_type; |
244 | void *control_data; | ||
244 | int mclk; | 245 | int mclk; |
245 | int requested_adc; | 246 | int requested_adc; |
246 | int requested_dac; | 247 | int requested_dac; |
@@ -404,11 +405,10 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, | |||
404 | struct snd_soc_dai *dai) | 405 | struct snd_soc_dai *dai) |
405 | { | 406 | { |
406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 407 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
407 | struct snd_soc_device *socdev = rtd->socdev; | 408 | struct snd_soc_codec *codec = rtd->codec; |
408 | struct snd_soc_codec *codec = socdev->card->codec; | ||
409 | u16 iface_reg; | 409 | u16 iface_reg; |
410 | int ret; | 410 | int ret; |
411 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | 411 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
412 | u32 sample_rate_adc = aic23->requested_adc; | 412 | u32 sample_rate_adc = aic23->requested_adc; |
413 | u32 sample_rate_dac = aic23->requested_dac; | 413 | u32 sample_rate_dac = aic23->requested_dac; |
414 | u32 sample_rate = params_rate(params); | 414 | u32 sample_rate = params_rate(params); |
@@ -452,8 +452,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, | |||
452 | struct snd_soc_dai *dai) | 452 | struct snd_soc_dai *dai) |
453 | { | 453 | { |
454 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 454 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
455 | struct snd_soc_device *socdev = rtd->socdev; | 455 | struct snd_soc_codec *codec = rtd->codec; |
456 | struct snd_soc_codec *codec = socdev->card->codec; | ||
457 | 456 | ||
458 | /* set active */ | 457 | /* set active */ |
459 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); | 458 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); |
@@ -465,9 +464,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
465 | struct snd_soc_dai *dai) | 464 | struct snd_soc_dai *dai) |
466 | { | 465 | { |
467 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 466 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
468 | struct snd_soc_device *socdev = rtd->socdev; | 467 | struct snd_soc_codec *codec = rtd->codec; |
469 | struct snd_soc_codec *codec = socdev->card->codec; | 468 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
470 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | ||
471 | 469 | ||
472 | /* deactivate */ | 470 | /* deactivate */ |
473 | if (!codec->active) { | 471 | if (!codec->active) { |
@@ -546,8 +544,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
546 | static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 544 | static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
547 | int clk_id, unsigned int freq, int dir) | 545 | int clk_id, unsigned int freq, int dir) |
548 | { | 546 | { |
549 | struct snd_soc_codec *codec = codec_dai->codec; | 547 | struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai); |
550 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | ||
551 | aic23->mclk = freq; | 548 | aic23->mclk = freq; |
552 | return 0; | 549 | return 0; |
553 | } | 550 | } |
@@ -594,8 +591,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = { | |||
594 | .set_sysclk = tlv320aic23_set_dai_sysclk, | 591 | .set_sysclk = tlv320aic23_set_dai_sysclk, |
595 | }; | 592 | }; |
596 | 593 | ||
597 | struct snd_soc_dai tlv320aic23_dai = { | 594 | static struct snd_soc_dai_driver tlv320aic23_dai = { |
598 | .name = "tlv320aic23", | 595 | .name = "tlv320aic23-hifi", |
599 | .playback = { | 596 | .playback = { |
600 | .stream_name = "Playback", | 597 | .stream_name = "Playback", |
601 | .channels_min = 2, | 598 | .channels_min = 2, |
@@ -610,23 +607,17 @@ struct snd_soc_dai tlv320aic23_dai = { | |||
610 | .formats = AIC23_FORMATS,}, | 607 | .formats = AIC23_FORMATS,}, |
611 | .ops = &tlv320aic23_dai_ops, | 608 | .ops = &tlv320aic23_dai_ops, |
612 | }; | 609 | }; |
613 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); | ||
614 | 610 | ||
615 | static int tlv320aic23_suspend(struct platform_device *pdev, | 611 | static int tlv320aic23_suspend(struct snd_soc_codec *codec, |
616 | pm_message_t state) | 612 | pm_message_t state) |
617 | { | 613 | { |
618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
619 | struct snd_soc_codec *codec = socdev->card->codec; | ||
620 | |||
621 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | 614 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
622 | 615 | ||
623 | return 0; | 616 | return 0; |
624 | } | 617 | } |
625 | 618 | ||
626 | static int tlv320aic23_resume(struct platform_device *pdev) | 619 | static int tlv320aic23_resume(struct snd_soc_codec *codec) |
627 | { | 620 | { |
628 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
629 | struct snd_soc_codec *codec = socdev->card->codec; | ||
630 | u16 reg; | 621 | u16 reg; |
631 | 622 | ||
632 | /* Sync reg_cache with the hardware */ | 623 | /* Sync reg_cache with the hardware */ |
@@ -639,39 +630,19 @@ static int tlv320aic23_resume(struct platform_device *pdev) | |||
639 | return 0; | 630 | return 0; |
640 | } | 631 | } |
641 | 632 | ||
642 | /* | 633 | static int tlv320aic23_probe(struct snd_soc_codec *codec) |
643 | * initialise the AIC23 driver | ||
644 | * register the mixer and dsp interfaces with the kernel | ||
645 | */ | ||
646 | static int tlv320aic23_init(struct snd_soc_device *socdev) | ||
647 | { | 634 | { |
648 | struct snd_soc_codec *codec = socdev->card->codec; | 635 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
649 | int ret = 0; | 636 | int reg; |
650 | u16 reg; | ||
651 | 637 | ||
652 | codec->name = "tlv320aic23"; | 638 | printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); |
653 | codec->owner = THIS_MODULE; | 639 | codec->control_data = aic23->control_data; |
654 | codec->read = tlv320aic23_read_reg_cache; | 640 | codec->hw_write = (hw_write_t)i2c_master_send; |
655 | codec->write = tlv320aic23_write; | 641 | codec->hw_read = NULL; |
656 | codec->set_bias_level = tlv320aic23_set_bias_level; | ||
657 | codec->dai = &tlv320aic23_dai; | ||
658 | codec->num_dai = 1; | ||
659 | codec->reg_cache_size = ARRAY_SIZE(tlv320aic23_reg); | ||
660 | codec->reg_cache = | ||
661 | kmemdup(tlv320aic23_reg, sizeof(tlv320aic23_reg), GFP_KERNEL); | ||
662 | if (codec->reg_cache == NULL) | ||
663 | return -ENOMEM; | ||
664 | 642 | ||
665 | /* Reset codec */ | 643 | /* Reset codec */ |
666 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); | 644 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); |
667 | 645 | ||
668 | /* register pcms */ | ||
669 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
670 | if (ret < 0) { | ||
671 | printk(KERN_ERR "tlv320aic23: failed to create pcms\n"); | ||
672 | goto pcm_err; | ||
673 | } | ||
674 | |||
675 | /* power on device */ | 646 | /* power on device */ |
676 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 647 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
677 | 648 | ||
@@ -707,13 +678,27 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) | |||
707 | ARRAY_SIZE(tlv320aic23_snd_controls)); | 678 | ARRAY_SIZE(tlv320aic23_snd_controls)); |
708 | tlv320aic23_add_widgets(codec); | 679 | tlv320aic23_add_widgets(codec); |
709 | 680 | ||
710 | return ret; | 681 | return 0; |
682 | } | ||
711 | 683 | ||
712 | pcm_err: | 684 | static int tlv320aic23_remove(struct snd_soc_codec *codec) |
713 | kfree(codec->reg_cache); | 685 | { |
714 | return ret; | 686 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
687 | return 0; | ||
715 | } | 688 | } |
716 | static struct snd_soc_device *tlv320aic23_socdev; | 689 | |
690 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | ||
691 | .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg), | ||
692 | .reg_word_size = sizeof(u16), | ||
693 | .reg_cache_default = tlv320aic23_reg, | ||
694 | .probe = tlv320aic23_probe, | ||
695 | .remove = tlv320aic23_remove, | ||
696 | .suspend = tlv320aic23_suspend, | ||
697 | .resume = tlv320aic23_resume, | ||
698 | .read = tlv320aic23_read_reg_cache, | ||
699 | .write = tlv320aic23_write, | ||
700 | .set_bias_level = tlv320aic23_set_bias_level, | ||
701 | }; | ||
717 | 702 | ||
718 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 703 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
719 | /* | 704 | /* |
@@ -723,31 +708,30 @@ static struct snd_soc_device *tlv320aic23_socdev; | |||
723 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | 708 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, |
724 | const struct i2c_device_id *i2c_id) | 709 | const struct i2c_device_id *i2c_id) |
725 | { | 710 | { |
726 | struct snd_soc_device *socdev = tlv320aic23_socdev; | 711 | struct aic23 *aic23; |
727 | struct snd_soc_codec *codec = socdev->card->codec; | ||
728 | int ret; | 712 | int ret; |
729 | 713 | ||
730 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 714 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
731 | return -EINVAL; | 715 | return -EINVAL; |
732 | 716 | ||
733 | i2c_set_clientdata(i2c, codec); | 717 | aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); |
734 | codec->control_data = i2c; | 718 | if (aic23 == NULL) |
719 | return -ENOMEM; | ||
735 | 720 | ||
736 | ret = tlv320aic23_init(socdev); | 721 | i2c_set_clientdata(i2c, aic23); |
737 | if (ret < 0) { | 722 | aic23->control_data = i2c; |
738 | printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n"); | 723 | aic23->control_type = SND_SOC_I2C; |
739 | goto err; | ||
740 | } | ||
741 | return ret; | ||
742 | 724 | ||
743 | err: | 725 | ret = snd_soc_register_codec(&i2c->dev, |
744 | kfree(codec); | 726 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); |
745 | kfree(i2c); | 727 | if (ret < 0) |
728 | kfree(aic23); | ||
746 | return ret; | 729 | return ret; |
747 | } | 730 | } |
748 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | 731 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) |
749 | { | 732 | { |
750 | put_device(&i2c->dev); | 733 | snd_soc_unregister_codec(&i2c->dev); |
734 | kfree(i2c_get_clientdata(i2c)); | ||
751 | return 0; | 735 | return 0; |
752 | } | 736 | } |
753 | 737 | ||
@@ -760,7 +744,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | |||
760 | 744 | ||
761 | static struct i2c_driver tlv320aic23_i2c_driver = { | 745 | static struct i2c_driver tlv320aic23_i2c_driver = { |
762 | .driver = { | 746 | .driver = { |
763 | .name = "tlv320aic23", | 747 | .name = "tlv320aic23-codec", |
764 | }, | 748 | }, |
765 | .probe = tlv320aic23_codec_probe, | 749 | .probe = tlv320aic23_codec_probe, |
766 | .remove = __exit_p(tlv320aic23_i2c_remove), | 750 | .remove = __exit_p(tlv320aic23_i2c_remove), |
@@ -769,71 +753,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = { | |||
769 | 753 | ||
770 | #endif | 754 | #endif |
771 | 755 | ||
772 | static int tlv320aic23_probe(struct platform_device *pdev) | 756 | static int __init tlv320aic23_modinit(void) |
773 | { | 757 | { |
774 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 758 | int ret; |
775 | struct snd_soc_codec *codec; | ||
776 | struct aic23 *aic23; | ||
777 | int ret = 0; | ||
778 | |||
779 | printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); | ||
780 | |||
781 | aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); | ||
782 | if (aic23 == NULL) | ||
783 | return -ENOMEM; | ||
784 | codec = &aic23->codec; | ||
785 | socdev->card->codec = codec; | ||
786 | mutex_init(&codec->mutex); | ||
787 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
788 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
789 | |||
790 | tlv320aic23_socdev = socdev; | ||
791 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 759 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
792 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
793 | codec->hw_read = NULL; | ||
794 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); | 760 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); |
795 | if (ret != 0) | 761 | if (ret != 0) { |
796 | printk(KERN_ERR "can't add i2c driver"); | 762 | printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n", |
763 | ret); | ||
764 | } | ||
797 | #endif | 765 | #endif |
798 | return ret; | 766 | return ret; |
799 | } | 767 | } |
768 | module_init(tlv320aic23_modinit); | ||
800 | 769 | ||
801 | static int tlv320aic23_remove(struct platform_device *pdev) | 770 | static void __exit tlv320aic23_exit(void) |
802 | { | 771 | { |
803 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
804 | struct snd_soc_codec *codec = socdev->card->codec; | ||
805 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | ||
806 | |||
807 | if (codec->control_data) | ||
808 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
809 | |||
810 | snd_soc_free_pcms(socdev); | ||
811 | snd_soc_dapm_free(socdev); | ||
812 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 772 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
813 | i2c_del_driver(&tlv320aic23_i2c_driver); | 773 | i2c_del_driver(&tlv320aic23_i2c_driver); |
814 | #endif | 774 | #endif |
815 | kfree(codec->reg_cache); | ||
816 | kfree(aic23); | ||
817 | |||
818 | return 0; | ||
819 | } | ||
820 | struct snd_soc_codec_device soc_codec_dev_tlv320aic23 = { | ||
821 | .probe = tlv320aic23_probe, | ||
822 | .remove = tlv320aic23_remove, | ||
823 | .suspend = tlv320aic23_suspend, | ||
824 | .resume = tlv320aic23_resume, | ||
825 | }; | ||
826 | EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320aic23); | ||
827 | |||
828 | static int __init tlv320aic23_modinit(void) | ||
829 | { | ||
830 | return snd_soc_register_dai(&tlv320aic23_dai); | ||
831 | } | ||
832 | module_init(tlv320aic23_modinit); | ||
833 | |||
834 | static void __exit tlv320aic23_exit(void) | ||
835 | { | ||
836 | snd_soc_unregister_dai(&tlv320aic23_dai); | ||
837 | } | 775 | } |
838 | module_exit(tlv320aic23_exit); | 776 | module_exit(tlv320aic23_exit); |
839 | 777 | ||