diff options
Diffstat (limited to 'sound/soc/codecs/wm8988.c')
-rw-r--r-- | sound/soc/codecs/wm8988.c | 180 |
1 files changed, 76 insertions, 104 deletions
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 8c0fdf84aac3..3f530f8a972a 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -57,50 +57,7 @@ struct wm8988_priv { | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | 59 | ||
60 | /* | 60 | #define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) |
61 | * read wm8988 register cache | ||
62 | */ | ||
63 | static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec, | ||
64 | unsigned int reg) | ||
65 | { | ||
66 | u16 *cache = codec->reg_cache; | ||
67 | if (reg > WM8988_NUM_REG) | ||
68 | return -1; | ||
69 | return cache[reg]; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * write wm8988 register cache | ||
74 | */ | ||
75 | static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec, | ||
76 | unsigned int reg, unsigned int value) | ||
77 | { | ||
78 | u16 *cache = codec->reg_cache; | ||
79 | if (reg > WM8988_NUM_REG) | ||
80 | return; | ||
81 | cache[reg] = value; | ||
82 | } | ||
83 | |||
84 | static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg, | ||
85 | unsigned int value) | ||
86 | { | ||
87 | u8 data[2]; | ||
88 | |||
89 | /* data is | ||
90 | * D15..D9 WM8753 register offset | ||
91 | * D8...D0 register data | ||
92 | */ | ||
93 | data[0] = (reg << 1) | ((value >> 8) & 0x0001); | ||
94 | data[1] = value & 0x00ff; | ||
95 | |||
96 | wm8988_write_reg_cache(codec, reg, value); | ||
97 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
98 | return 0; | ||
99 | else | ||
100 | return -EIO; | ||
101 | } | ||
102 | |||
103 | #define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0) | ||
104 | 61 | ||
105 | /* | 62 | /* |
106 | * WM8988 Controls | 63 | * WM8988 Controls |
@@ -226,15 +183,15 @@ static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, | |||
226 | struct snd_kcontrol *kcontrol, int event) | 183 | struct snd_kcontrol *kcontrol, int event) |
227 | { | 184 | { |
228 | struct snd_soc_codec *codec = w->codec; | 185 | struct snd_soc_codec *codec = w->codec; |
229 | u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); | 186 | u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2); |
230 | 187 | ||
231 | /* Use the DAC to gate LRC if active, otherwise use ADC */ | 188 | /* Use the DAC to gate LRC if active, otherwise use ADC */ |
232 | if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) | 189 | if (snd_soc_read(codec, WM8988_PWR2) & 0x180) |
233 | adctl2 &= ~0x4; | 190 | adctl2 &= ~0x4; |
234 | else | 191 | else |
235 | adctl2 |= 0x4; | 192 | adctl2 |= 0x4; |
236 | 193 | ||
237 | return wm8988_write(codec, WM8988_ADCTL2, adctl2); | 194 | return snd_soc_write(codec, WM8988_ADCTL2, adctl2); |
238 | } | 195 | } |
239 | 196 | ||
240 | static const char *wm8988_line_texts[] = { | 197 | static const char *wm8988_line_texts[] = { |
@@ -619,7 +576,7 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
619 | return -EINVAL; | 576 | return -EINVAL; |
620 | } | 577 | } |
621 | 578 | ||
622 | wm8988_write(codec, WM8988_IFACE, iface); | 579 | snd_soc_write(codec, WM8988_IFACE, iface); |
623 | return 0; | 580 | return 0; |
624 | } | 581 | } |
625 | 582 | ||
@@ -653,8 +610,8 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, | |||
653 | struct snd_soc_device *socdev = rtd->socdev; | 610 | struct snd_soc_device *socdev = rtd->socdev; |
654 | struct snd_soc_codec *codec = socdev->card->codec; | 611 | struct snd_soc_codec *codec = socdev->card->codec; |
655 | struct wm8988_priv *wm8988 = codec->private_data; | 612 | struct wm8988_priv *wm8988 = codec->private_data; |
656 | u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; | 613 | u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3; |
657 | u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; | 614 | u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180; |
658 | int coeff; | 615 | int coeff; |
659 | 616 | ||
660 | coeff = get_coeff(wm8988->sysclk, params_rate(params)); | 617 | coeff = get_coeff(wm8988->sysclk, params_rate(params)); |
@@ -685,9 +642,9 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, | |||
685 | } | 642 | } |
686 | 643 | ||
687 | /* set iface & srate */ | 644 | /* set iface & srate */ |
688 | wm8988_write(codec, WM8988_IFACE, iface); | 645 | snd_soc_write(codec, WM8988_IFACE, iface); |
689 | if (coeff >= 0) | 646 | if (coeff >= 0) |
690 | wm8988_write(codec, WM8988_SRATE, srate | | 647 | snd_soc_write(codec, WM8988_SRATE, srate | |
691 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); | 648 | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); |
692 | 649 | ||
693 | return 0; | 650 | return 0; |
@@ -696,19 +653,19 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, | |||
696 | static int wm8988_mute(struct snd_soc_dai *dai, int mute) | 653 | static int wm8988_mute(struct snd_soc_dai *dai, int mute) |
697 | { | 654 | { |
698 | struct snd_soc_codec *codec = dai->codec; | 655 | struct snd_soc_codec *codec = dai->codec; |
699 | u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; | 656 | u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7; |
700 | 657 | ||
701 | if (mute) | 658 | if (mute) |
702 | wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); | 659 | snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8); |
703 | else | 660 | else |
704 | wm8988_write(codec, WM8988_ADCDAC, mute_reg); | 661 | snd_soc_write(codec, WM8988_ADCDAC, mute_reg); |
705 | return 0; | 662 | return 0; |
706 | } | 663 | } |
707 | 664 | ||
708 | static int wm8988_set_bias_level(struct snd_soc_codec *codec, | 665 | static int wm8988_set_bias_level(struct snd_soc_codec *codec, |
709 | enum snd_soc_bias_level level) | 666 | enum snd_soc_bias_level level) |
710 | { | 667 | { |
711 | u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; | 668 | u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; |
712 | 669 | ||
713 | switch (level) { | 670 | switch (level) { |
714 | case SND_SOC_BIAS_ON: | 671 | case SND_SOC_BIAS_ON: |
@@ -716,24 +673,24 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, | |||
716 | 673 | ||
717 | case SND_SOC_BIAS_PREPARE: | 674 | case SND_SOC_BIAS_PREPARE: |
718 | /* VREF, VMID=2x50k, digital enabled */ | 675 | /* VREF, VMID=2x50k, digital enabled */ |
719 | wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); | 676 | snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); |
720 | break; | 677 | break; |
721 | 678 | ||
722 | case SND_SOC_BIAS_STANDBY: | 679 | case SND_SOC_BIAS_STANDBY: |
723 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 680 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
724 | /* VREF, VMID=2x5k */ | 681 | /* VREF, VMID=2x5k */ |
725 | wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); | 682 | snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); |
726 | 683 | ||
727 | /* Charge caps */ | 684 | /* Charge caps */ |
728 | msleep(100); | 685 | msleep(100); |
729 | } | 686 | } |
730 | 687 | ||
731 | /* VREF, VMID=2*500k, digital stopped */ | 688 | /* VREF, VMID=2*500k, digital stopped */ |
732 | wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); | 689 | snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141); |
733 | break; | 690 | break; |
734 | 691 | ||
735 | case SND_SOC_BIAS_OFF: | 692 | case SND_SOC_BIAS_OFF: |
736 | wm8988_write(codec, WM8988_PWR1, 0x0000); | 693 | snd_soc_write(codec, WM8988_PWR1, 0x0000); |
737 | break; | 694 | break; |
738 | } | 695 | } |
739 | codec->bias_level = level; | 696 | codec->bias_level = level; |
@@ -868,7 +825,8 @@ struct snd_soc_codec_device soc_codec_dev_wm8988 = { | |||
868 | }; | 825 | }; |
869 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); | 826 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); |
870 | 827 | ||
871 | static int wm8988_register(struct wm8988_priv *wm8988) | 828 | static int wm8988_register(struct wm8988_priv *wm8988, |
829 | enum snd_soc_control_type control) | ||
872 | { | 830 | { |
873 | struct snd_soc_codec *codec = &wm8988->codec; | 831 | struct snd_soc_codec *codec = &wm8988->codec; |
874 | int ret; | 832 | int ret; |
@@ -887,8 +845,6 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
887 | codec->private_data = wm8988; | 845 | codec->private_data = wm8988; |
888 | codec->name = "WM8988"; | 846 | codec->name = "WM8988"; |
889 | codec->owner = THIS_MODULE; | 847 | codec->owner = THIS_MODULE; |
890 | codec->read = wm8988_read_reg_cache; | ||
891 | codec->write = wm8988_write; | ||
892 | codec->dai = &wm8988_dai; | 848 | codec->dai = &wm8988_dai; |
893 | codec->num_dai = 1; | 849 | codec->num_dai = 1; |
894 | codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); | 850 | codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); |
@@ -899,23 +855,29 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
899 | memcpy(codec->reg_cache, wm8988_reg, | 855 | memcpy(codec->reg_cache, wm8988_reg, |
900 | sizeof(wm8988_reg)); | 856 | sizeof(wm8988_reg)); |
901 | 857 | ||
858 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
859 | if (ret < 0) { | ||
860 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
861 | goto err; | ||
862 | } | ||
863 | |||
902 | ret = wm8988_reset(codec); | 864 | ret = wm8988_reset(codec); |
903 | if (ret < 0) { | 865 | if (ret < 0) { |
904 | dev_err(codec->dev, "Failed to issue reset\n"); | 866 | dev_err(codec->dev, "Failed to issue reset\n"); |
905 | return ret; | 867 | goto err; |
906 | } | 868 | } |
907 | 869 | ||
908 | /* set the update bits (we always update left then right) */ | 870 | /* set the update bits (we always update left then right) */ |
909 | reg = wm8988_read_reg_cache(codec, WM8988_RADC); | 871 | reg = snd_soc_read(codec, WM8988_RADC); |
910 | wm8988_write(codec, WM8988_RADC, reg | 0x100); | 872 | snd_soc_write(codec, WM8988_RADC, reg | 0x100); |
911 | reg = wm8988_read_reg_cache(codec, WM8988_RDAC); | 873 | reg = snd_soc_read(codec, WM8988_RDAC); |
912 | wm8988_write(codec, WM8988_RDAC, reg | 0x0100); | 874 | snd_soc_write(codec, WM8988_RDAC, reg | 0x0100); |
913 | reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); | 875 | reg = snd_soc_read(codec, WM8988_ROUT1V); |
914 | wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); | 876 | snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100); |
915 | reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); | 877 | reg = snd_soc_read(codec, WM8988_ROUT2V); |
916 | wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); | 878 | snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100); |
917 | reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); | 879 | reg = snd_soc_read(codec, WM8988_RINVOL); |
918 | wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); | 880 | snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100); |
919 | 881 | ||
920 | wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); | 882 | wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); |
921 | 883 | ||
@@ -926,18 +888,20 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
926 | ret = snd_soc_register_codec(codec); | 888 | ret = snd_soc_register_codec(codec); |
927 | if (ret != 0) { | 889 | if (ret != 0) { |
928 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 890 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
929 | return ret; | 891 | goto err; |
930 | } | 892 | } |
931 | 893 | ||
932 | ret = snd_soc_register_dai(&wm8988_dai); | 894 | ret = snd_soc_register_dai(&wm8988_dai); |
933 | if (ret != 0) { | 895 | if (ret != 0) { |
934 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 896 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
935 | snd_soc_unregister_codec(codec); | 897 | snd_soc_unregister_codec(codec); |
936 | return ret; | 898 | goto err_codec; |
937 | } | 899 | } |
938 | 900 | ||
939 | return 0; | 901 | return 0; |
940 | 902 | ||
903 | err_codec: | ||
904 | snd_soc_unregister_codec(codec); | ||
941 | err: | 905 | err: |
942 | kfree(wm8988); | 906 | kfree(wm8988); |
943 | return ret; | 907 | return ret; |
@@ -964,14 +928,13 @@ static int wm8988_i2c_probe(struct i2c_client *i2c, | |||
964 | return -ENOMEM; | 928 | return -ENOMEM; |
965 | 929 | ||
966 | codec = &wm8988->codec; | 930 | codec = &wm8988->codec; |
967 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
968 | 931 | ||
969 | i2c_set_clientdata(i2c, wm8988); | 932 | i2c_set_clientdata(i2c, wm8988); |
970 | codec->control_data = i2c; | 933 | codec->control_data = i2c; |
971 | 934 | ||
972 | codec->dev = &i2c->dev; | 935 | codec->dev = &i2c->dev; |
973 | 936 | ||
974 | return wm8988_register(wm8988); | 937 | return wm8988_register(wm8988, SND_SOC_I2C); |
975 | } | 938 | } |
976 | 939 | ||
977 | static int wm8988_i2c_remove(struct i2c_client *client) | 940 | static int wm8988_i2c_remove(struct i2c_client *client) |
@@ -981,6 +944,21 @@ static int wm8988_i2c_remove(struct i2c_client *client) | |||
981 | return 0; | 944 | return 0; |
982 | } | 945 | } |
983 | 946 | ||
947 | #ifdef CONFIG_PM | ||
948 | static int wm8988_i2c_suspend(struct i2c_client *client, pm_message_t msg) | ||
949 | { | ||
950 | return snd_soc_suspend_device(&client->dev); | ||
951 | } | ||
952 | |||
953 | static int wm8988_i2c_resume(struct i2c_client *client) | ||
954 | { | ||
955 | return snd_soc_resume_device(&client->dev); | ||
956 | } | ||
957 | #else | ||
958 | #define wm8988_i2c_suspend NULL | ||
959 | #define wm8988_i2c_resume NULL | ||
960 | #endif | ||
961 | |||
984 | static const struct i2c_device_id wm8988_i2c_id[] = { | 962 | static const struct i2c_device_id wm8988_i2c_id[] = { |
985 | { "wm8988", 0 }, | 963 | { "wm8988", 0 }, |
986 | { } | 964 | { } |
@@ -994,35 +972,13 @@ static struct i2c_driver wm8988_i2c_driver = { | |||
994 | }, | 972 | }, |
995 | .probe = wm8988_i2c_probe, | 973 | .probe = wm8988_i2c_probe, |
996 | .remove = wm8988_i2c_remove, | 974 | .remove = wm8988_i2c_remove, |
975 | .suspend = wm8988_i2c_suspend, | ||
976 | .resume = wm8988_i2c_resume, | ||
997 | .id_table = wm8988_i2c_id, | 977 | .id_table = wm8988_i2c_id, |
998 | }; | 978 | }; |
999 | #endif | 979 | #endif |
1000 | 980 | ||
1001 | #if defined(CONFIG_SPI_MASTER) | 981 | #if defined(CONFIG_SPI_MASTER) |
1002 | static int wm8988_spi_write(struct spi_device *spi, const char *data, int len) | ||
1003 | { | ||
1004 | struct spi_transfer t; | ||
1005 | struct spi_message m; | ||
1006 | u8 msg[2]; | ||
1007 | |||
1008 | if (len <= 0) | ||
1009 | return 0; | ||
1010 | |||
1011 | msg[0] = data[0]; | ||
1012 | msg[1] = data[1]; | ||
1013 | |||
1014 | spi_message_init(&m); | ||
1015 | memset(&t, 0, (sizeof t)); | ||
1016 | |||
1017 | t.tx_buf = &msg[0]; | ||
1018 | t.len = len; | ||
1019 | |||
1020 | spi_message_add_tail(&t, &m); | ||
1021 | spi_sync(spi, &m); | ||
1022 | |||
1023 | return len; | ||
1024 | } | ||
1025 | |||
1026 | static int __devinit wm8988_spi_probe(struct spi_device *spi) | 982 | static int __devinit wm8988_spi_probe(struct spi_device *spi) |
1027 | { | 983 | { |
1028 | struct wm8988_priv *wm8988; | 984 | struct wm8988_priv *wm8988; |
@@ -1033,13 +989,12 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) | |||
1033 | return -ENOMEM; | 989 | return -ENOMEM; |
1034 | 990 | ||
1035 | codec = &wm8988->codec; | 991 | codec = &wm8988->codec; |
1036 | codec->hw_write = (hw_write_t)wm8988_spi_write; | ||
1037 | codec->control_data = spi; | 992 | codec->control_data = spi; |
1038 | codec->dev = &spi->dev; | 993 | codec->dev = &spi->dev; |
1039 | 994 | ||
1040 | dev_set_drvdata(&spi->dev, wm8988); | 995 | dev_set_drvdata(&spi->dev, wm8988); |
1041 | 996 | ||
1042 | return wm8988_register(wm8988); | 997 | return wm8988_register(wm8988, SND_SOC_SPI); |
1043 | } | 998 | } |
1044 | 999 | ||
1045 | static int __devexit wm8988_spi_remove(struct spi_device *spi) | 1000 | static int __devexit wm8988_spi_remove(struct spi_device *spi) |
@@ -1051,6 +1006,21 @@ static int __devexit wm8988_spi_remove(struct spi_device *spi) | |||
1051 | return 0; | 1006 | return 0; |
1052 | } | 1007 | } |
1053 | 1008 | ||
1009 | #ifdef CONFIG_PM | ||
1010 | static int wm8988_spi_suspend(struct spi_device *spi, pm_message_t msg) | ||
1011 | { | ||
1012 | return snd_soc_suspend_device(&spi->dev); | ||
1013 | } | ||
1014 | |||
1015 | static int wm8988_spi_resume(struct spi_device *spi) | ||
1016 | { | ||
1017 | return snd_soc_resume_device(&spi->dev); | ||
1018 | } | ||
1019 | #else | ||
1020 | #define wm8988_spi_suspend NULL | ||
1021 | #define wm8988_spi_resume NULL | ||
1022 | #endif | ||
1023 | |||
1054 | static struct spi_driver wm8988_spi_driver = { | 1024 | static struct spi_driver wm8988_spi_driver = { |
1055 | .driver = { | 1025 | .driver = { |
1056 | .name = "wm8988", | 1026 | .name = "wm8988", |
@@ -1059,6 +1029,8 @@ static struct spi_driver wm8988_spi_driver = { | |||
1059 | }, | 1029 | }, |
1060 | .probe = wm8988_spi_probe, | 1030 | .probe = wm8988_spi_probe, |
1061 | .remove = __devexit_p(wm8988_spi_remove), | 1031 | .remove = __devexit_p(wm8988_spi_remove), |
1032 | .suspend = wm8988_spi_suspend, | ||
1033 | .resume = wm8988_spi_resume, | ||
1062 | }; | 1034 | }; |
1063 | #endif | 1035 | #endif |
1064 | 1036 | ||