diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-05 12:24:50 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-07-05 12:24:50 -0400 |
commit | 17a52fd60a0a0e617ed94aadb1b19751a8fa219e (patch) | |
tree | 2c2fd4526ae219ec9435a0a4b0fc281a5ca62b7c /sound/soc/codecs/wm8988.c | |
parent | 5420f30723122012c7bb868a55ff21c7d383b68e (diff) |
ASoC: Begin to factor out register cache I/O functions
A lot of CODECs share the same register data formats and therefore
replicate the code to manage access to and caching of the register
map. In order to reduce code duplication centralised versions of
this code will be introduced with drivers able to configure the use
of the common code by calling the new snd_soc_codec_set_cache_io()
API call during startup.
As an initial user the 7 bit address/9 bit data format used by many
Wolfson devices is supported for write only CODECs and the drivers
with straightforward register cache implementations are converted to
use it.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8988.c')
-rw-r--r-- | sound/soc/codecs/wm8988.c | 105 |
1 files changed, 33 insertions, 72 deletions
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index 6f15acd10489..7d5b807bdb48 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; |
@@ -887,8 +844,6 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
887 | codec->private_data = wm8988; | 844 | codec->private_data = wm8988; |
888 | codec->name = "WM8988"; | 845 | codec->name = "WM8988"; |
889 | codec->owner = THIS_MODULE; | 846 | codec->owner = THIS_MODULE; |
890 | codec->read = wm8988_read_reg_cache; | ||
891 | codec->write = wm8988_write; | ||
892 | codec->dai = &wm8988_dai; | 847 | codec->dai = &wm8988_dai; |
893 | codec->num_dai = 1; | 848 | codec->num_dai = 1; |
894 | codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); | 849 | codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); |
@@ -899,6 +854,12 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
899 | memcpy(codec->reg_cache, wm8988_reg, | 854 | memcpy(codec->reg_cache, wm8988_reg, |
900 | sizeof(wm8988_reg)); | 855 | sizeof(wm8988_reg)); |
901 | 856 | ||
857 | ret = snd_soc_codec_set_cache_io(codec, 7, 9); | ||
858 | if (ret < 0) { | ||
859 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
860 | goto err; | ||
861 | } | ||
862 | |||
902 | ret = wm8988_reset(codec); | 863 | ret = wm8988_reset(codec); |
903 | if (ret < 0) { | 864 | if (ret < 0) { |
904 | dev_err(codec->dev, "Failed to issue reset\n"); | 865 | dev_err(codec->dev, "Failed to issue reset\n"); |
@@ -906,16 +867,16 @@ static int wm8988_register(struct wm8988_priv *wm8988) | |||
906 | } | 867 | } |
907 | 868 | ||
908 | /* set the update bits (we always update left then right) */ | 869 | /* set the update bits (we always update left then right) */ |
909 | reg = wm8988_read_reg_cache(codec, WM8988_RADC); | 870 | reg = snd_soc_read(codec, WM8988_RADC); |
910 | wm8988_write(codec, WM8988_RADC, reg | 0x100); | 871 | snd_soc_write(codec, WM8988_RADC, reg | 0x100); |
911 | reg = wm8988_read_reg_cache(codec, WM8988_RDAC); | 872 | reg = snd_soc_read(codec, WM8988_RDAC); |
912 | wm8988_write(codec, WM8988_RDAC, reg | 0x0100); | 873 | snd_soc_write(codec, WM8988_RDAC, reg | 0x0100); |
913 | reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); | 874 | reg = snd_soc_read(codec, WM8988_ROUT1V); |
914 | wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); | 875 | snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100); |
915 | reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); | 876 | reg = snd_soc_read(codec, WM8988_ROUT2V); |
916 | wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); | 877 | snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100); |
917 | reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); | 878 | reg = snd_soc_read(codec, WM8988_RINVOL); |
918 | wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); | 879 | snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100); |
919 | 880 | ||
920 | wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); | 881 | wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); |
921 | 882 | ||