diff options
Diffstat (limited to 'sound/soc/codecs/wm8728.c')
-rw-r--r-- | sound/soc/codecs/wm8728.c | 111 |
1 files changed, 26 insertions, 85 deletions
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index e7ff2121ede9..16e969a762c3 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 | ||
46 | static 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 | |||
54 | static 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 | */ | ||
65 | static 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 | |||
85 | static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); | 46 | static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); |
86 | 47 | ||
87 | static const struct snd_kcontrol_new wm8728_snd_controls[] = { | 48 | static const struct snd_kcontrol_new wm8728_snd_controls[] = { |
@@ -121,12 +82,12 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec) | |||
121 | static int wm8728_mute(struct snd_soc_dai *dai, int mute) | 82 | static 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; |
@@ -287,15 +248,14 @@ static int wm8728_resume(struct platform_device *pdev) | |||
287 | * initialise the WM8728 driver | 248 | * initialise the WM8728 driver |
288 | * register the mixer and dsp interfaces with the kernel | 249 | * register the mixer and dsp interfaces with the kernel |
289 | */ | 250 | */ |
290 | static int wm8728_init(struct snd_soc_device *socdev) | 251 | static int wm8728_init(struct snd_soc_device *socdev, |
252 | enum snd_soc_control_type control) | ||
291 | { | 253 | { |
292 | struct snd_soc_codec *codec = socdev->card->codec; | 254 | struct snd_soc_codec *codec = socdev->card->codec; |
293 | int ret = 0; | 255 | int ret = 0; |
294 | 256 | ||
295 | codec->name = "WM8728"; | 257 | codec->name = "WM8728"; |
296 | codec->owner = THIS_MODULE; | 258 | 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; | 259 | codec->set_bias_level = wm8728_set_bias_level; |
300 | codec->dai = &wm8728_dai; | 260 | codec->dai = &wm8728_dai; |
301 | codec->num_dai = 1; | 261 | codec->num_dai = 1; |
@@ -307,11 +267,18 @@ static int wm8728_init(struct snd_soc_device *socdev) | |||
307 | if (codec->reg_cache == NULL) | 267 | if (codec->reg_cache == NULL) |
308 | return -ENOMEM; | 268 | return -ENOMEM; |
309 | 269 | ||
270 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
271 | if (ret < 0) { | ||
272 | printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", | ||
273 | ret); | ||
274 | goto err; | ||
275 | } | ||
276 | |||
310 | /* register pcms */ | 277 | /* register pcms */ |
311 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 278 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
312 | if (ret < 0) { | 279 | if (ret < 0) { |
313 | printk(KERN_ERR "wm8728: failed to create pcms\n"); | 280 | printk(KERN_ERR "wm8728: failed to create pcms\n"); |
314 | goto pcm_err; | 281 | goto err; |
315 | } | 282 | } |
316 | 283 | ||
317 | /* power on device */ | 284 | /* power on device */ |
@@ -331,7 +298,7 @@ static int wm8728_init(struct snd_soc_device *socdev) | |||
331 | card_err: | 298 | card_err: |
332 | snd_soc_free_pcms(socdev); | 299 | snd_soc_free_pcms(socdev); |
333 | snd_soc_dapm_free(socdev); | 300 | snd_soc_dapm_free(socdev); |
334 | pcm_err: | 301 | err: |
335 | kfree(codec->reg_cache); | 302 | kfree(codec->reg_cache); |
336 | return ret; | 303 | return ret; |
337 | } | 304 | } |
@@ -357,7 +324,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c, | |||
357 | i2c_set_clientdata(i2c, codec); | 324 | i2c_set_clientdata(i2c, codec); |
358 | codec->control_data = i2c; | 325 | codec->control_data = i2c; |
359 | 326 | ||
360 | ret = wm8728_init(socdev); | 327 | ret = wm8728_init(socdev, SND_SOC_I2C); |
361 | if (ret < 0) | 328 | if (ret < 0) |
362 | pr_err("failed to initialise WM8728\n"); | 329 | pr_err("failed to initialise WM8728\n"); |
363 | 330 | ||
@@ -437,7 +404,7 @@ static int __devinit wm8728_spi_probe(struct spi_device *spi) | |||
437 | 404 | ||
438 | codec->control_data = spi; | 405 | codec->control_data = spi; |
439 | 406 | ||
440 | ret = wm8728_init(socdev); | 407 | ret = wm8728_init(socdev, SND_SOC_SPI); |
441 | if (ret < 0) | 408 | if (ret < 0) |
442 | dev_err(&spi->dev, "failed to initialise WM8728\n"); | 409 | dev_err(&spi->dev, "failed to initialise WM8728\n"); |
443 | 410 | ||
@@ -458,30 +425,6 @@ static struct spi_driver wm8728_spi_driver = { | |||
458 | .probe = wm8728_spi_probe, | 425 | .probe = wm8728_spi_probe, |
459 | .remove = __devexit_p(wm8728_spi_remove), | 426 | .remove = __devexit_p(wm8728_spi_remove), |
460 | }; | 427 | }; |
461 | |||
462 | static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) | ||
463 | { | ||
464 | struct spi_transfer t; | ||
465 | struct spi_message m; | ||
466 | u8 msg[2]; | ||
467 | |||
468 | if (len <= 0) | ||
469 | return 0; | ||
470 | |||
471 | msg[0] = data[0]; | ||
472 | msg[1] = data[1]; | ||
473 | |||
474 | spi_message_init(&m); | ||
475 | memset(&t, 0, (sizeof t)); | ||
476 | |||
477 | t.tx_buf = &msg[0]; | ||
478 | t.len = len; | ||
479 | |||
480 | spi_message_add_tail(&t, &m); | ||
481 | spi_sync(spi, &m); | ||
482 | |||
483 | return len; | ||
484 | } | ||
485 | #endif /* CONFIG_SPI_MASTER */ | 428 | #endif /* CONFIG_SPI_MASTER */ |
486 | 429 | ||
487 | static int wm8728_probe(struct platform_device *pdev) | 430 | static int wm8728_probe(struct platform_device *pdev) |
@@ -506,13 +449,11 @@ static int wm8728_probe(struct platform_device *pdev) | |||
506 | 449 | ||
507 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 450 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
508 | if (setup->i2c_address) { | 451 | if (setup->i2c_address) { |
509 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
510 | ret = wm8728_add_i2c_device(pdev, setup); | 452 | ret = wm8728_add_i2c_device(pdev, setup); |
511 | } | 453 | } |
512 | #endif | 454 | #endif |
513 | #if defined(CONFIG_SPI_MASTER) | 455 | #if defined(CONFIG_SPI_MASTER) |
514 | if (setup->spi) { | 456 | if (setup->spi) { |
515 | codec->hw_write = (hw_write_t)wm8728_spi_write; | ||
516 | ret = spi_register_driver(&wm8728_spi_driver); | 457 | ret = spi_register_driver(&wm8728_spi_driver); |
517 | if (ret != 0) | 458 | if (ret != 0) |
518 | printk(KERN_ERR "can't add spi driver"); | 459 | printk(KERN_ERR "can't add spi driver"); |