diff options
Diffstat (limited to 'sound/soc/codecs/wm8750.c')
-rw-r--r-- | sound/soc/codecs/wm8750.c | 154 |
1 files changed, 47 insertions, 107 deletions
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index b64509b01a49..4ba1e7e93fb4 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -55,50 +55,7 @@ static const u16 wm8750_reg[] = { | |||
55 | 0x0079, 0x0079, 0x0079, /* 40 */ | 55 | 0x0079, 0x0079, 0x0079, /* 40 */ |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | #define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) |
59 | * read wm8750 register cache | ||
60 | */ | ||
61 | static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, | ||
62 | unsigned int reg) | ||
63 | { | ||
64 | u16 *cache = codec->reg_cache; | ||
65 | if (reg > WM8750_CACHE_REGNUM) | ||
66 | return -1; | ||
67 | return cache[reg]; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * write wm8750 register cache | ||
72 | */ | ||
73 | static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, | ||
74 | unsigned int reg, unsigned int value) | ||
75 | { | ||
76 | u16 *cache = codec->reg_cache; | ||
77 | if (reg > WM8750_CACHE_REGNUM) | ||
78 | return; | ||
79 | cache[reg] = value; | ||
80 | } | ||
81 | |||
82 | static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, | ||
83 | unsigned int value) | ||
84 | { | ||
85 | u8 data[2]; | ||
86 | |||
87 | /* data is | ||
88 | * D15..D9 WM8753 register offset | ||
89 | * D8...D0 register data | ||
90 | */ | ||
91 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
92 | data[1] = value & 0x00ff; | ||
93 | |||
94 | wm8750_write_reg_cache(codec, reg, value); | ||
95 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
96 | return 0; | ||
97 | else | ||
98 | return -EIO; | ||
99 | } | ||
100 | |||
101 | #define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) | ||
102 | 59 | ||
103 | /* | 60 | /* |
104 | * WM8750 Controls | 61 | * WM8750 Controls |
@@ -594,7 +551,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
594 | return -EINVAL; | 551 | return -EINVAL; |
595 | } | 552 | } |
596 | 553 | ||
597 | wm8750_write(codec, WM8750_IFACE, iface); | 554 | snd_soc_write(codec, WM8750_IFACE, iface); |
598 | return 0; | 555 | return 0; |
599 | } | 556 | } |
600 | 557 | ||
@@ -606,8 +563,8 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
606 | struct snd_soc_device *socdev = rtd->socdev; | 563 | struct snd_soc_device *socdev = rtd->socdev; |
607 | struct snd_soc_codec *codec = socdev->card->codec; | 564 | struct snd_soc_codec *codec = socdev->card->codec; |
608 | struct wm8750_priv *wm8750 = codec->private_data; | 565 | struct wm8750_priv *wm8750 = codec->private_data; |
609 | u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; | 566 | u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; |
610 | u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; | 567 | u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; |
611 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); | 568 | int coeff = get_coeff(wm8750->sysclk, params_rate(params)); |
612 | 569 | ||
613 | /* bit size */ | 570 | /* bit size */ |
@@ -626,9 +583,9 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
626 | } | 583 | } |
627 | 584 | ||
628 | /* set iface & srate */ | 585 | /* set iface & srate */ |
629 | wm8750_write(codec, WM8750_IFACE, iface); | 586 | snd_soc_write(codec, WM8750_IFACE, iface); |
630 | if (coeff >= 0) | 587 | if (coeff >= 0) |
631 | wm8750_write(codec, WM8750_SRATE, srate | | 588 | snd_soc_write(codec, WM8750_SRATE, srate | |
632 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | 589 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); |
633 | 590 | ||
634 | return 0; | 591 | return 0; |
@@ -637,35 +594,35 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, | |||
637 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) | 594 | static int wm8750_mute(struct snd_soc_dai *dai, int mute) |
638 | { | 595 | { |
639 | struct snd_soc_codec *codec = dai->codec; | 596 | struct snd_soc_codec *codec = dai->codec; |
640 | u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; | 597 | u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7; |
641 | 598 | ||
642 | if (mute) | 599 | if (mute) |
643 | wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); | 600 | snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8); |
644 | else | 601 | else |
645 | wm8750_write(codec, WM8750_ADCDAC, mute_reg); | 602 | snd_soc_write(codec, WM8750_ADCDAC, mute_reg); |
646 | return 0; | 603 | return 0; |
647 | } | 604 | } |
648 | 605 | ||
649 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, | 606 | static int wm8750_set_bias_level(struct snd_soc_codec *codec, |
650 | enum snd_soc_bias_level level) | 607 | enum snd_soc_bias_level level) |
651 | { | 608 | { |
652 | u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; | 609 | u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e; |
653 | 610 | ||
654 | switch (level) { | 611 | switch (level) { |
655 | case SND_SOC_BIAS_ON: | 612 | case SND_SOC_BIAS_ON: |
656 | /* set vmid to 50k and unmute dac */ | 613 | /* set vmid to 50k and unmute dac */ |
657 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); | 614 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); |
658 | break; | 615 | break; |
659 | case SND_SOC_BIAS_PREPARE: | 616 | case SND_SOC_BIAS_PREPARE: |
660 | /* set vmid to 5k for quick power up */ | 617 | /* set vmid to 5k for quick power up */ |
661 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); | 618 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); |
662 | break; | 619 | break; |
663 | case SND_SOC_BIAS_STANDBY: | 620 | case SND_SOC_BIAS_STANDBY: |
664 | /* mute dac and set vmid to 500k, enable VREF */ | 621 | /* mute dac and set vmid to 500k, enable VREF */ |
665 | wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); | 622 | snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141); |
666 | break; | 623 | break; |
667 | case SND_SOC_BIAS_OFF: | 624 | case SND_SOC_BIAS_OFF: |
668 | wm8750_write(codec, WM8750_PWR1, 0x0001); | 625 | snd_soc_write(codec, WM8750_PWR1, 0x0001); |
669 | break; | 626 | break; |
670 | } | 627 | } |
671 | codec->bias_level = level; | 628 | codec->bias_level = level; |
@@ -754,15 +711,14 @@ static int wm8750_resume(struct platform_device *pdev) | |||
754 | * initialise the WM8750 driver | 711 | * initialise the WM8750 driver |
755 | * register the mixer and dsp interfaces with the kernel | 712 | * register the mixer and dsp interfaces with the kernel |
756 | */ | 713 | */ |
757 | static int wm8750_init(struct snd_soc_device *socdev) | 714 | static int wm8750_init(struct snd_soc_device *socdev, |
715 | enum snd_soc_control_type control) | ||
758 | { | 716 | { |
759 | struct snd_soc_codec *codec = socdev->card->codec; | 717 | struct snd_soc_codec *codec = socdev->card->codec; |
760 | int reg, ret = 0; | 718 | int reg, ret = 0; |
761 | 719 | ||
762 | codec->name = "WM8750"; | 720 | codec->name = "WM8750"; |
763 | codec->owner = THIS_MODULE; | 721 | codec->owner = THIS_MODULE; |
764 | codec->read = wm8750_read_reg_cache; | ||
765 | codec->write = wm8750_write; | ||
766 | codec->set_bias_level = wm8750_set_bias_level; | 722 | codec->set_bias_level = wm8750_set_bias_level; |
767 | codec->dai = &wm8750_dai; | 723 | codec->dai = &wm8750_dai; |
768 | codec->num_dai = 1; | 724 | codec->num_dai = 1; |
@@ -771,13 +727,23 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
771 | if (codec->reg_cache == NULL) | 727 | if (codec->reg_cache == NULL) |
772 | return -ENOMEM; | 728 | return -ENOMEM; |
773 | 729 | ||
774 | wm8750_reset(codec); | 730 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); |
731 | if (ret < 0) { | ||
732 | printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); | ||
733 | goto err; | ||
734 | } | ||
735 | |||
736 | ret = wm8750_reset(codec); | ||
737 | if (ret < 0) { | ||
738 | printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); | ||
739 | goto err; | ||
740 | } | ||
775 | 741 | ||
776 | /* register pcms */ | 742 | /* register pcms */ |
777 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 743 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
778 | if (ret < 0) { | 744 | if (ret < 0) { |
779 | printk(KERN_ERR "wm8750: failed to create pcms\n"); | 745 | printk(KERN_ERR "wm8750: failed to create pcms\n"); |
780 | goto pcm_err; | 746 | goto err; |
781 | } | 747 | } |
782 | 748 | ||
783 | /* charge output caps */ | 749 | /* charge output caps */ |
@@ -786,22 +752,22 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
786 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); | 752 | schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); |
787 | 753 | ||
788 | /* set the update bits */ | 754 | /* set the update bits */ |
789 | reg = wm8750_read_reg_cache(codec, WM8750_LDAC); | 755 | reg = snd_soc_read(codec, WM8750_LDAC); |
790 | wm8750_write(codec, WM8750_LDAC, reg | 0x0100); | 756 | snd_soc_write(codec, WM8750_LDAC, reg | 0x0100); |
791 | reg = wm8750_read_reg_cache(codec, WM8750_RDAC); | 757 | reg = snd_soc_read(codec, WM8750_RDAC); |
792 | wm8750_write(codec, WM8750_RDAC, reg | 0x0100); | 758 | snd_soc_write(codec, WM8750_RDAC, reg | 0x0100); |
793 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); | 759 | reg = snd_soc_read(codec, WM8750_LOUT1V); |
794 | wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); | 760 | snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100); |
795 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); | 761 | reg = snd_soc_read(codec, WM8750_ROUT1V); |
796 | wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); | 762 | snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100); |
797 | reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); | 763 | reg = snd_soc_read(codec, WM8750_LOUT2V); |
798 | wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); | 764 | snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100); |
799 | reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); | 765 | reg = snd_soc_read(codec, WM8750_ROUT2V); |
800 | wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); | 766 | snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100); |
801 | reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); | 767 | reg = snd_soc_read(codec, WM8750_LINVOL); |
802 | wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); | 768 | snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100); |
803 | reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); | 769 | reg = snd_soc_read(codec, WM8750_RINVOL); |
804 | wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); | 770 | snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100); |
805 | 771 | ||
806 | snd_soc_add_controls(codec, wm8750_snd_controls, | 772 | snd_soc_add_controls(codec, wm8750_snd_controls, |
807 | ARRAY_SIZE(wm8750_snd_controls)); | 773 | ARRAY_SIZE(wm8750_snd_controls)); |
@@ -816,7 +782,7 @@ static int wm8750_init(struct snd_soc_device *socdev) | |||
816 | card_err: | 782 | card_err: |
817 | snd_soc_free_pcms(socdev); | 783 | snd_soc_free_pcms(socdev); |
818 | snd_soc_dapm_free(socdev); | 784 | snd_soc_dapm_free(socdev); |
819 | pcm_err: | 785 | err: |
820 | kfree(codec->reg_cache); | 786 | kfree(codec->reg_cache); |
821 | return ret; | 787 | return ret; |
822 | } | 788 | } |
@@ -844,7 +810,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c, | |||
844 | i2c_set_clientdata(i2c, codec); | 810 | i2c_set_clientdata(i2c, codec); |
845 | codec->control_data = i2c; | 811 | codec->control_data = i2c; |
846 | 812 | ||
847 | ret = wm8750_init(socdev); | 813 | ret = wm8750_init(socdev, SND_SOC_I2C); |
848 | if (ret < 0) | 814 | if (ret < 0) |
849 | pr_err("failed to initialise WM8750\n"); | 815 | pr_err("failed to initialise WM8750\n"); |
850 | 816 | ||
@@ -924,7 +890,7 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) | |||
924 | 890 | ||
925 | codec->control_data = spi; | 891 | codec->control_data = spi; |
926 | 892 | ||
927 | ret = wm8750_init(socdev); | 893 | ret = wm8750_init(socdev, SND_SOC_SPI); |
928 | if (ret < 0) | 894 | if (ret < 0) |
929 | dev_err(&spi->dev, "failed to initialise WM8750\n"); | 895 | dev_err(&spi->dev, "failed to initialise WM8750\n"); |
930 | 896 | ||
@@ -945,30 +911,6 @@ static struct spi_driver wm8750_spi_driver = { | |||
945 | .probe = wm8750_spi_probe, | 911 | .probe = wm8750_spi_probe, |
946 | .remove = __devexit_p(wm8750_spi_remove), | 912 | .remove = __devexit_p(wm8750_spi_remove), |
947 | }; | 913 | }; |
948 | |||
949 | static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) | ||
950 | { | ||
951 | struct spi_transfer t; | ||
952 | struct spi_message m; | ||
953 | u8 msg[2]; | ||
954 | |||
955 | if (len <= 0) | ||
956 | return 0; | ||
957 | |||
958 | msg[0] = data[0]; | ||
959 | msg[1] = data[1]; | ||
960 | |||
961 | spi_message_init(&m); | ||
962 | memset(&t, 0, (sizeof t)); | ||
963 | |||
964 | t.tx_buf = &msg[0]; | ||
965 | t.len = len; | ||
966 | |||
967 | spi_message_add_tail(&t, &m); | ||
968 | spi_sync(spi, &m); | ||
969 | |||
970 | return len; | ||
971 | } | ||
972 | #endif | 914 | #endif |
973 | 915 | ||
974 | static int wm8750_probe(struct platform_device *pdev) | 916 | static int wm8750_probe(struct platform_device *pdev) |
@@ -1002,13 +944,11 @@ static int wm8750_probe(struct platform_device *pdev) | |||
1002 | 944 | ||
1003 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 945 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1004 | if (setup->i2c_address) { | 946 | if (setup->i2c_address) { |
1005 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1006 | ret = wm8750_add_i2c_device(pdev, setup); | 947 | ret = wm8750_add_i2c_device(pdev, setup); |
1007 | } | 948 | } |
1008 | #endif | 949 | #endif |
1009 | #if defined(CONFIG_SPI_MASTER) | 950 | #if defined(CONFIG_SPI_MASTER) |
1010 | if (setup->spi) { | 951 | if (setup->spi) { |
1011 | codec->hw_write = (hw_write_t)wm8750_spi_write; | ||
1012 | ret = spi_register_driver(&wm8750_spi_driver); | 952 | ret = spi_register_driver(&wm8750_spi_driver); |
1013 | if (ret != 0) | 953 | if (ret != 0) |
1014 | printk(KERN_ERR "can't add spi driver"); | 954 | printk(KERN_ERR "can't add spi driver"); |