diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic23.c')
-rw-r--r-- | sound/soc/codecs/tlv320aic23.c | 203 |
1 files changed, 66 insertions, 137 deletions
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 0a4b0fef3355..33bb52f3f683 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
31 | #include <sound/pcm_params.h> | 31 | #include <sound/pcm_params.h> |
32 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
33 | #include <sound/soc-dapm.h> | ||
34 | #include <sound/tlv.h> | 33 | #include <sound/tlv.h> |
35 | #include <sound/initval.h> | 34 | #include <sound/initval.h> |
36 | 35 | ||
@@ -213,7 +212,7 @@ static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | |||
213 | SND_SOC_DAPM_INPUT("MICIN"), | 212 | SND_SOC_DAPM_INPUT("MICIN"), |
214 | }; | 213 | }; |
215 | 214 | ||
216 | static const struct snd_soc_dapm_route intercon[] = { | 215 | static const struct snd_soc_dapm_route tlv320aic23_intercon[] = { |
217 | /* Output Mixer */ | 216 | /* Output Mixer */ |
218 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, | 217 | {"Output Mixer", "Line Bypass Switch", "Line Input"}, |
219 | {"Output Mixer", "Playback Switch", "DAC"}, | 218 | {"Output Mixer", "Playback Switch", "DAC"}, |
@@ -240,7 +239,8 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
240 | 239 | ||
241 | /* AIC23 driver data */ | 240 | /* AIC23 driver data */ |
242 | struct aic23 { | 241 | struct aic23 { |
243 | struct snd_soc_codec codec; | 242 | enum snd_soc_control_type control_type; |
243 | void *control_data; | ||
244 | int mclk; | 244 | int mclk; |
245 | int requested_adc; | 245 | int requested_adc; |
246 | int requested_dac; | 246 | int requested_dac; |
@@ -388,27 +388,15 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk, | |||
388 | return 0; | 388 | return 0; |
389 | } | 389 | } |
390 | 390 | ||
391 | static int tlv320aic23_add_widgets(struct snd_soc_codec *codec) | ||
392 | { | ||
393 | snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets, | ||
394 | ARRAY_SIZE(tlv320aic23_dapm_widgets)); | ||
395 | |||
396 | /* set up audio path interconnects */ | ||
397 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, | 391 | static int tlv320aic23_hw_params(struct snd_pcm_substream *substream, |
403 | struct snd_pcm_hw_params *params, | 392 | struct snd_pcm_hw_params *params, |
404 | struct snd_soc_dai *dai) | 393 | struct snd_soc_dai *dai) |
405 | { | 394 | { |
406 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 395 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
407 | struct snd_soc_device *socdev = rtd->socdev; | 396 | struct snd_soc_codec *codec = rtd->codec; |
408 | struct snd_soc_codec *codec = socdev->card->codec; | ||
409 | u16 iface_reg; | 397 | u16 iface_reg; |
410 | int ret; | 398 | int ret; |
411 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | 399 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
412 | u32 sample_rate_adc = aic23->requested_adc; | 400 | u32 sample_rate_adc = aic23->requested_adc; |
413 | u32 sample_rate_dac = aic23->requested_dac; | 401 | u32 sample_rate_dac = aic23->requested_dac; |
414 | u32 sample_rate = params_rate(params); | 402 | u32 sample_rate = params_rate(params); |
@@ -452,8 +440,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream, | |||
452 | struct snd_soc_dai *dai) | 440 | struct snd_soc_dai *dai) |
453 | { | 441 | { |
454 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 442 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
455 | struct snd_soc_device *socdev = rtd->socdev; | 443 | struct snd_soc_codec *codec = rtd->codec; |
456 | struct snd_soc_codec *codec = socdev->card->codec; | ||
457 | 444 | ||
458 | /* set active */ | 445 | /* set active */ |
459 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); | 446 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); |
@@ -465,9 +452,8 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
465 | struct snd_soc_dai *dai) | 452 | struct snd_soc_dai *dai) |
466 | { | 453 | { |
467 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 454 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
468 | struct snd_soc_device *socdev = rtd->socdev; | 455 | struct snd_soc_codec *codec = rtd->codec; |
469 | struct snd_soc_codec *codec = socdev->card->codec; | 456 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
470 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | ||
471 | 457 | ||
472 | /* deactivate */ | 458 | /* deactivate */ |
473 | if (!codec->active) { | 459 | if (!codec->active) { |
@@ -546,8 +532,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, | 532 | static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
547 | int clk_id, unsigned int freq, int dir) | 533 | int clk_id, unsigned int freq, int dir) |
548 | { | 534 | { |
549 | struct snd_soc_codec *codec = codec_dai->codec; | 535 | struct aic23 *aic23 = snd_soc_dai_get_drvdata(codec_dai); |
550 | struct aic23 *aic23 = container_of(codec, struct aic23, codec); | ||
551 | aic23->mclk = freq; | 536 | aic23->mclk = freq; |
552 | return 0; | 537 | return 0; |
553 | } | 538 | } |
@@ -577,7 +562,7 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | |||
577 | tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff); | 562 | tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff); |
578 | break; | 563 | break; |
579 | } | 564 | } |
580 | codec->bias_level = level; | 565 | codec->dapm.bias_level = level; |
581 | return 0; | 566 | return 0; |
582 | } | 567 | } |
583 | 568 | ||
@@ -594,8 +579,8 @@ static struct snd_soc_dai_ops tlv320aic23_dai_ops = { | |||
594 | .set_sysclk = tlv320aic23_set_dai_sysclk, | 579 | .set_sysclk = tlv320aic23_set_dai_sysclk, |
595 | }; | 580 | }; |
596 | 581 | ||
597 | struct snd_soc_dai tlv320aic23_dai = { | 582 | static struct snd_soc_dai_driver tlv320aic23_dai = { |
598 | .name = "tlv320aic23", | 583 | .name = "tlv320aic23-hifi", |
599 | .playback = { | 584 | .playback = { |
600 | .stream_name = "Playback", | 585 | .stream_name = "Playback", |
601 | .channels_min = 2, | 586 | .channels_min = 2, |
@@ -610,23 +595,17 @@ struct snd_soc_dai tlv320aic23_dai = { | |||
610 | .formats = AIC23_FORMATS,}, | 595 | .formats = AIC23_FORMATS,}, |
611 | .ops = &tlv320aic23_dai_ops, | 596 | .ops = &tlv320aic23_dai_ops, |
612 | }; | 597 | }; |
613 | EXPORT_SYMBOL_GPL(tlv320aic23_dai); | ||
614 | 598 | ||
615 | static int tlv320aic23_suspend(struct platform_device *pdev, | 599 | static int tlv320aic23_suspend(struct snd_soc_codec *codec, |
616 | pm_message_t state) | 600 | pm_message_t state) |
617 | { | 601 | { |
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); | 602 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
622 | 603 | ||
623 | return 0; | 604 | return 0; |
624 | } | 605 | } |
625 | 606 | ||
626 | static int tlv320aic23_resume(struct platform_device *pdev) | 607 | static int tlv320aic23_resume(struct snd_soc_codec *codec) |
627 | { | 608 | { |
628 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
629 | struct snd_soc_codec *codec = socdev->card->codec; | ||
630 | u16 reg; | 609 | u16 reg; |
631 | 610 | ||
632 | /* Sync reg_cache with the hardware */ | 611 | /* Sync reg_cache with the hardware */ |
@@ -639,39 +618,19 @@ static int tlv320aic23_resume(struct platform_device *pdev) | |||
639 | return 0; | 618 | return 0; |
640 | } | 619 | } |
641 | 620 | ||
642 | /* | 621 | 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 | { | 622 | { |
648 | struct snd_soc_codec *codec = socdev->card->codec; | 623 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
649 | int ret = 0; | 624 | int reg; |
650 | u16 reg; | ||
651 | 625 | ||
652 | codec->name = "tlv320aic23"; | 626 | printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); |
653 | codec->owner = THIS_MODULE; | 627 | codec->control_data = aic23->control_data; |
654 | codec->read = tlv320aic23_read_reg_cache; | 628 | codec->hw_write = (hw_write_t)i2c_master_send; |
655 | codec->write = tlv320aic23_write; | 629 | 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 | 630 | ||
665 | /* Reset codec */ | 631 | /* Reset codec */ |
666 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); | 632 | tlv320aic23_write(codec, TLV320AIC23_RESET, 0); |
667 | 633 | ||
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 */ | 634 | /* power on device */ |
676 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 635 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
677 | 636 | ||
@@ -705,15 +664,32 @@ static int tlv320aic23_init(struct snd_soc_device *socdev) | |||
705 | 664 | ||
706 | snd_soc_add_controls(codec, tlv320aic23_snd_controls, | 665 | snd_soc_add_controls(codec, tlv320aic23_snd_controls, |
707 | ARRAY_SIZE(tlv320aic23_snd_controls)); | 666 | ARRAY_SIZE(tlv320aic23_snd_controls)); |
708 | tlv320aic23_add_widgets(codec); | ||
709 | 667 | ||
710 | return ret; | 668 | return 0; |
669 | } | ||
711 | 670 | ||
712 | pcm_err: | 671 | static int tlv320aic23_remove(struct snd_soc_codec *codec) |
713 | kfree(codec->reg_cache); | 672 | { |
714 | return ret; | 673 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
674 | return 0; | ||
715 | } | 675 | } |
716 | static struct snd_soc_device *tlv320aic23_socdev; | 676 | |
677 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | ||
678 | .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg), | ||
679 | .reg_word_size = sizeof(u16), | ||
680 | .reg_cache_default = tlv320aic23_reg, | ||
681 | .probe = tlv320aic23_probe, | ||
682 | .remove = tlv320aic23_remove, | ||
683 | .suspend = tlv320aic23_suspend, | ||
684 | .resume = tlv320aic23_resume, | ||
685 | .read = tlv320aic23_read_reg_cache, | ||
686 | .write = tlv320aic23_write, | ||
687 | .set_bias_level = tlv320aic23_set_bias_level, | ||
688 | .dapm_widgets = tlv320aic23_dapm_widgets, | ||
689 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), | ||
690 | .dapm_routes = tlv320aic23_intercon, | ||
691 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), | ||
692 | }; | ||
717 | 693 | ||
718 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 694 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
719 | /* | 695 | /* |
@@ -723,31 +699,30 @@ static struct snd_soc_device *tlv320aic23_socdev; | |||
723 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | 699 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, |
724 | const struct i2c_device_id *i2c_id) | 700 | const struct i2c_device_id *i2c_id) |
725 | { | 701 | { |
726 | struct snd_soc_device *socdev = tlv320aic23_socdev; | 702 | struct aic23 *aic23; |
727 | struct snd_soc_codec *codec = socdev->card->codec; | ||
728 | int ret; | 703 | int ret; |
729 | 704 | ||
730 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 705 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
731 | return -EINVAL; | 706 | return -EINVAL; |
732 | 707 | ||
733 | i2c_set_clientdata(i2c, codec); | 708 | aic23 = kzalloc(sizeof(struct aic23), GFP_KERNEL); |
734 | codec->control_data = i2c; | 709 | if (aic23 == NULL) |
710 | return -ENOMEM; | ||
735 | 711 | ||
736 | ret = tlv320aic23_init(socdev); | 712 | i2c_set_clientdata(i2c, aic23); |
737 | if (ret < 0) { | 713 | aic23->control_data = i2c; |
738 | printk(KERN_ERR "tlv320aic23: failed to initialise AIC23\n"); | 714 | aic23->control_type = SND_SOC_I2C; |
739 | goto err; | ||
740 | } | ||
741 | return ret; | ||
742 | 715 | ||
743 | err: | 716 | ret = snd_soc_register_codec(&i2c->dev, |
744 | kfree(codec); | 717 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); |
745 | kfree(i2c); | 718 | if (ret < 0) |
719 | kfree(aic23); | ||
746 | return ret; | 720 | return ret; |
747 | } | 721 | } |
748 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | 722 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) |
749 | { | 723 | { |
750 | put_device(&i2c->dev); | 724 | snd_soc_unregister_codec(&i2c->dev); |
725 | kfree(i2c_get_clientdata(i2c)); | ||
751 | return 0; | 726 | return 0; |
752 | } | 727 | } |
753 | 728 | ||
@@ -760,7 +735,7 @@ MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | |||
760 | 735 | ||
761 | static struct i2c_driver tlv320aic23_i2c_driver = { | 736 | static struct i2c_driver tlv320aic23_i2c_driver = { |
762 | .driver = { | 737 | .driver = { |
763 | .name = "tlv320aic23", | 738 | .name = "tlv320aic23-codec", |
764 | }, | 739 | }, |
765 | .probe = tlv320aic23_codec_probe, | 740 | .probe = tlv320aic23_codec_probe, |
766 | .remove = __exit_p(tlv320aic23_i2c_remove), | 741 | .remove = __exit_p(tlv320aic23_i2c_remove), |
@@ -769,71 +744,25 @@ static struct i2c_driver tlv320aic23_i2c_driver = { | |||
769 | 744 | ||
770 | #endif | 745 | #endif |
771 | 746 | ||
772 | static int tlv320aic23_probe(struct platform_device *pdev) | 747 | static int __init tlv320aic23_modinit(void) |
773 | { | 748 | { |
774 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 749 | 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) | 750 | #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); | 751 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); |
795 | if (ret != 0) | 752 | if (ret != 0) { |
796 | printk(KERN_ERR "can't add i2c driver"); | 753 | printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n", |
754 | ret); | ||
755 | } | ||
797 | #endif | 756 | #endif |
798 | return ret; | 757 | return ret; |
799 | } | 758 | } |
759 | module_init(tlv320aic23_modinit); | ||
800 | 760 | ||
801 | static int tlv320aic23_remove(struct platform_device *pdev) | 761 | static void __exit tlv320aic23_exit(void) |
802 | { | 762 | { |
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) | 763 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
813 | i2c_del_driver(&tlv320aic23_i2c_driver); | 764 | i2c_del_driver(&tlv320aic23_i2c_driver); |
814 | #endif | 765 | #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 | } | 766 | } |
838 | module_exit(tlv320aic23_exit); | 767 | module_exit(tlv320aic23_exit); |
839 | 768 | ||