aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8728.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-07-05 12:24:50 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2009-07-05 12:24:50 -0400
commit17a52fd60a0a0e617ed94aadb1b19751a8fa219e (patch)
tree2c2fd4526ae219ec9435a0a4b0fc281a5ca62b7c /sound/soc/codecs/wm8728.c
parent5420f30723122012c7bb868a55ff21c7d383b68e (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/wm8728.c')
-rw-r--r--sound/soc/codecs/wm8728.c78
1 files changed, 22 insertions, 56 deletions
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index e7ff2121ede9..66da44b08d35 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -43,45 +43,6 @@ static const u16 wm8728_reg_defaults[] = {
43 0x100, 43 0x100,
44}; 44};
45 45
46static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec,
47 unsigned int reg)
48{
49 u16 *cache = codec->reg_cache;
50 BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
51 return cache[reg];
52}
53
54static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec,
55 u16 reg, unsigned int value)
56{
57 u16 *cache = codec->reg_cache;
58 BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults));
59 cache[reg] = value;
60}
61
62/*
63 * write to the WM8728 register space
64 */
65static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg,
66 unsigned int value)
67{
68 u8 data[2];
69
70 /* data is
71 * D15..D9 WM8728 register offset
72 * D8...D0 register data
73 */
74 data[0] = (reg << 1) | ((value >> 8) & 0x0001);
75 data[1] = value & 0x00ff;
76
77 wm8728_write_reg_cache(codec, reg, value);
78
79 if (codec->hw_write(codec->control_data, data, 2) == 2)
80 return 0;
81 else
82 return -EIO;
83}
84
85static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); 46static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1);
86 47
87static const struct snd_kcontrol_new wm8728_snd_controls[] = { 48static const struct snd_kcontrol_new wm8728_snd_controls[] = {
@@ -121,12 +82,12 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec)
121static int wm8728_mute(struct snd_soc_dai *dai, int mute) 82static int wm8728_mute(struct snd_soc_dai *dai, int mute)
122{ 83{
123 struct snd_soc_codec *codec = dai->codec; 84 struct snd_soc_codec *codec = dai->codec;
124 u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 85 u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL);
125 86
126 if (mute) 87 if (mute)
127 wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); 88 snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1);
128 else 89 else
129 wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); 90 snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1);
130 91
131 return 0; 92 return 0;
132} 93}
@@ -138,7 +99,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
138 struct snd_soc_pcm_runtime *rtd = substream->private_data; 99 struct snd_soc_pcm_runtime *rtd = substream->private_data;
139 struct snd_soc_device *socdev = rtd->socdev; 100 struct snd_soc_device *socdev = rtd->socdev;
140 struct snd_soc_codec *codec = socdev->card->codec; 101 struct snd_soc_codec *codec = socdev->card->codec;
141 u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); 102 u16 dac = snd_soc_read(codec, WM8728_DACCTL);
142 103
143 dac &= ~0x18; 104 dac &= ~0x18;
144 105
@@ -155,7 +116,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream,
155 return -EINVAL; 116 return -EINVAL;
156 } 117 }
157 118
158 wm8728_write(codec, WM8728_DACCTL, dac); 119 snd_soc_write(codec, WM8728_DACCTL, dac);
159 120
160 return 0; 121 return 0;
161} 122}
@@ -164,7 +125,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
164 unsigned int fmt) 125 unsigned int fmt)
165{ 126{
166 struct snd_soc_codec *codec = codec_dai->codec; 127 struct snd_soc_codec *codec = codec_dai->codec;
167 u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); 128 u16 iface = snd_soc_read(codec, WM8728_IFCTL);
168 129
169 /* Currently only I2S is supported by the driver, though the 130 /* Currently only I2S is supported by the driver, though the
170 * hardware is more flexible. 131 * hardware is more flexible.
@@ -204,7 +165,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai,
204 return -EINVAL; 165 return -EINVAL;
205 } 166 }
206 167
207 wm8728_write(codec, WM8728_IFCTL, iface); 168 snd_soc_write(codec, WM8728_IFCTL, iface);
208 return 0; 169 return 0;
209} 170}
210 171
@@ -220,19 +181,19 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
220 case SND_SOC_BIAS_STANDBY: 181 case SND_SOC_BIAS_STANDBY:
221 if (codec->bias_level == SND_SOC_BIAS_OFF) { 182 if (codec->bias_level == SND_SOC_BIAS_OFF) {
222 /* Power everything up... */ 183 /* Power everything up... */
223 reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 184 reg = snd_soc_read(codec, WM8728_DACCTL);
224 wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); 185 snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
225 186
226 /* ..then sync in the register cache. */ 187 /* ..then sync in the register cache. */
227 for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) 188 for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++)
228 wm8728_write(codec, i, 189 snd_soc_write(codec, i,
229 wm8728_read_reg_cache(codec, i)); 190 snd_soc_read(codec, i));
230 } 191 }
231 break; 192 break;
232 193
233 case SND_SOC_BIAS_OFF: 194 case SND_SOC_BIAS_OFF:
234 reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); 195 reg = snd_soc_read(codec, WM8728_DACCTL);
235 wm8728_write(codec, WM8728_DACCTL, reg | 0x4); 196 snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
236 break; 197 break;
237 } 198 }
238 codec->bias_level = level; 199 codec->bias_level = level;
@@ -294,8 +255,6 @@ static int wm8728_init(struct snd_soc_device *socdev)
294 255
295 codec->name = "WM8728"; 256 codec->name = "WM8728";
296 codec->owner = THIS_MODULE; 257 codec->owner = THIS_MODULE;
297 codec->read = wm8728_read_reg_cache;
298 codec->write = wm8728_write;
299 codec->set_bias_level = wm8728_set_bias_level; 258 codec->set_bias_level = wm8728_set_bias_level;
300 codec->dai = &wm8728_dai; 259 codec->dai = &wm8728_dai;
301 codec->num_dai = 1; 260 codec->num_dai = 1;
@@ -307,11 +266,18 @@ static int wm8728_init(struct snd_soc_device *socdev)
307 if (codec->reg_cache == NULL) 266 if (codec->reg_cache == NULL)
308 return -ENOMEM; 267 return -ENOMEM;
309 268
269 ret = snd_soc_codec_set_cache_io(codec, 7, 9);
270 if (ret < 0) {
271 printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n",
272 ret);
273 goto err;
274 }
275
310 /* register pcms */ 276 /* register pcms */
311 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 277 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
312 if (ret < 0) { 278 if (ret < 0) {
313 printk(KERN_ERR "wm8728: failed to create pcms\n"); 279 printk(KERN_ERR "wm8728: failed to create pcms\n");
314 goto pcm_err; 280 goto err;
315 } 281 }
316 282
317 /* power on device */ 283 /* power on device */
@@ -331,7 +297,7 @@ static int wm8728_init(struct snd_soc_device *socdev)
331card_err: 297card_err:
332 snd_soc_free_pcms(socdev); 298 snd_soc_free_pcms(socdev);
333 snd_soc_dapm_free(socdev); 299 snd_soc_dapm_free(socdev);
334pcm_err: 300err:
335 kfree(codec->reg_cache); 301 kfree(codec->reg_cache);
336 return ret; 302 return ret;
337} 303}