diff options
Diffstat (limited to 'sound/soc/codecs/wm8990.c')
| -rw-r--r-- | sound/soc/codecs/wm8990.c | 43 |
1 files changed, 34 insertions, 9 deletions
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 572d22b0880b..5b5afc144478 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
| @@ -106,6 +106,7 @@ static const u16 wm8990_reg[] = { | |||
| 106 | 0x0008, /* R60 - PLL1 */ | 106 | 0x0008, /* R60 - PLL1 */ |
| 107 | 0x0031, /* R61 - PLL2 */ | 107 | 0x0031, /* R61 - PLL2 */ |
| 108 | 0x0026, /* R62 - PLL3 */ | 108 | 0x0026, /* R62 - PLL3 */ |
| 109 | 0x0000, /* R63 - Driver internal */ | ||
| 109 | }; | 110 | }; |
| 110 | 111 | ||
| 111 | /* | 112 | /* |
| @@ -126,10 +127,9 @@ static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, | |||
| 126 | unsigned int reg, unsigned int value) | 127 | unsigned int reg, unsigned int value) |
| 127 | { | 128 | { |
| 128 | u16 *cache = codec->reg_cache; | 129 | u16 *cache = codec->reg_cache; |
| 129 | BUG_ON(reg > (ARRAY_SIZE(wm8990_reg)) - 1); | ||
| 130 | 130 | ||
| 131 | /* Reset register is uncached */ | 131 | /* Reset register and reserved registers are uncached */ |
| 132 | if (reg == 0) | 132 | if (reg == 0 || reg > ARRAY_SIZE(wm8990_reg) - 1) |
| 133 | return; | 133 | return; |
| 134 | 134 | ||
| 135 | cache[reg] = value; | 135 | cache[reg] = value; |
| @@ -1172,7 +1172,8 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
| 1172 | * Set PCM DAI bit size and sample rate. | 1172 | * Set PCM DAI bit size and sample rate. |
| 1173 | */ | 1173 | */ |
| 1174 | static int wm8990_hw_params(struct snd_pcm_substream *substream, | 1174 | static int wm8990_hw_params(struct snd_pcm_substream *substream, |
| 1175 | struct snd_pcm_hw_params *params) | 1175 | struct snd_pcm_hw_params *params, |
| 1176 | struct snd_soc_dai *dai) | ||
| 1176 | { | 1177 | { |
| 1177 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1178 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 1178 | struct snd_soc_device *socdev = rtd->socdev; | 1179 | struct snd_soc_device *socdev = rtd->socdev; |
| @@ -1222,8 +1223,14 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, | |||
| 1222 | switch (level) { | 1223 | switch (level) { |
| 1223 | case SND_SOC_BIAS_ON: | 1224 | case SND_SOC_BIAS_ON: |
| 1224 | break; | 1225 | break; |
| 1226 | |||
| 1225 | case SND_SOC_BIAS_PREPARE: | 1227 | case SND_SOC_BIAS_PREPARE: |
| 1228 | /* VMID=2*50k */ | ||
| 1229 | val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & | ||
| 1230 | ~WM8990_VMID_MODE_MASK; | ||
| 1231 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); | ||
| 1226 | break; | 1232 | break; |
| 1233 | |||
| 1227 | case SND_SOC_BIAS_STANDBY: | 1234 | case SND_SOC_BIAS_STANDBY: |
| 1228 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 1235 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
| 1229 | /* Enable all output discharge bits */ | 1236 | /* Enable all output discharge bits */ |
| @@ -1272,10 +1279,17 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, | |||
| 1272 | 1279 | ||
| 1273 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | 1280 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ |
| 1274 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); | 1281 | wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); |
| 1275 | } else { | ||
| 1276 | /* ON -> standby */ | ||
| 1277 | 1282 | ||
| 1283 | /* Enable workaround for ADC clocking issue. */ | ||
| 1284 | wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); | ||
| 1285 | wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); | ||
| 1286 | wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); | ||
| 1278 | } | 1287 | } |
| 1288 | |||
| 1289 | /* VMID=2*250k */ | ||
| 1290 | val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & | ||
| 1291 | ~WM8990_VMID_MODE_MASK; | ||
| 1292 | wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); | ||
| 1279 | break; | 1293 | break; |
| 1280 | 1294 | ||
| 1281 | case SND_SOC_BIAS_OFF: | 1295 | case SND_SOC_BIAS_OFF: |
| @@ -1349,8 +1363,7 @@ struct snd_soc_dai wm8990_dai = { | |||
| 1349 | .rates = WM8990_RATES, | 1363 | .rates = WM8990_RATES, |
| 1350 | .formats = WM8990_FORMATS,}, | 1364 | .formats = WM8990_FORMATS,}, |
| 1351 | .ops = { | 1365 | .ops = { |
| 1352 | .hw_params = wm8990_hw_params,}, | 1366 | .hw_params = wm8990_hw_params, |
| 1353 | .dai_ops = { | ||
| 1354 | .digital_mute = wm8990_mute, | 1367 | .digital_mute = wm8990_mute, |
| 1355 | .set_fmt = wm8990_set_dai_fmt, | 1368 | .set_fmt = wm8990_set_dai_fmt, |
| 1356 | .set_clkdiv = wm8990_set_dai_clkdiv, | 1369 | .set_clkdiv = wm8990_set_dai_clkdiv, |
| @@ -1449,7 +1462,7 @@ static int wm8990_init(struct snd_soc_device *socdev) | |||
| 1449 | 1462 | ||
| 1450 | wm8990_add_controls(codec); | 1463 | wm8990_add_controls(codec); |
| 1451 | wm8990_add_widgets(codec); | 1464 | wm8990_add_widgets(codec); |
| 1452 | ret = snd_soc_register_card(socdev); | 1465 | ret = snd_soc_init_card(socdev); |
| 1453 | if (ret < 0) { | 1466 | if (ret < 0) { |
| 1454 | printk(KERN_ERR "wm8990: failed to register card\n"); | 1467 | printk(KERN_ERR "wm8990: failed to register card\n"); |
| 1455 | goto card_err; | 1468 | goto card_err; |
| @@ -1630,6 +1643,18 @@ struct snd_soc_codec_device soc_codec_dev_wm8990 = { | |||
| 1630 | }; | 1643 | }; |
| 1631 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); | 1644 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8990); |
| 1632 | 1645 | ||
| 1646 | static int __init wm8990_modinit(void) | ||
| 1647 | { | ||
| 1648 | return snd_soc_register_dai(&wm8990_dai); | ||
| 1649 | } | ||
| 1650 | module_init(wm8990_modinit); | ||
| 1651 | |||
| 1652 | static void __exit wm8990_exit(void) | ||
| 1653 | { | ||
| 1654 | snd_soc_unregister_dai(&wm8990_dai); | ||
| 1655 | } | ||
| 1656 | module_exit(wm8990_exit); | ||
| 1657 | |||
| 1633 | MODULE_DESCRIPTION("ASoC WM8990 driver"); | 1658 | MODULE_DESCRIPTION("ASoC WM8990 driver"); |
| 1634 | MODULE_AUTHOR("Liam Girdwood"); | 1659 | MODULE_AUTHOR("Liam Girdwood"); |
| 1635 | MODULE_LICENSE("GPL"); | 1660 | MODULE_LICENSE("GPL"); |
