aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/wm2200.c9
-rw-r--r--sound/soc/codecs/wm5100.c7
-rw-r--r--sound/soc/codecs/wm8731.c34
-rw-r--r--sound/soc/codecs/wm8804-i2c.c1
-rw-r--r--sound/soc/codecs/wm8804-spi.c1
-rw-r--r--sound/soc/codecs/wm8804.c297
-rw-r--r--sound/soc/codecs/wm8804.h1
-rw-r--r--sound/soc/codecs/wm8996.c12
8 files changed, 227 insertions, 135 deletions
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c
index 15599845a660..5a9da28f4f33 100644
--- a/sound/soc/codecs/wm2200.c
+++ b/sound/soc/codecs/wm2200.c
@@ -1554,7 +1554,6 @@ static int wm2200_probe(struct snd_soc_codec *codec)
1554 int ret; 1554 int ret;
1555 1555
1556 wm2200->codec = codec; 1556 wm2200->codec = codec;
1557 codec->dapm.bias_level = SND_SOC_BIAS_OFF;
1558 1557
1559 ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2); 1558 ret = snd_soc_add_codec_controls(codec, wm_adsp1_fw_controls, 2);
1560 if (ret != 0) 1559 if (ret != 0)
@@ -1942,6 +1941,7 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1942 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec); 1941 struct wm2200_priv *wm2200 = snd_soc_codec_get_drvdata(codec);
1943 struct _fll_div factors; 1942 struct _fll_div factors;
1944 int ret, i, timeout; 1943 int ret, i, timeout;
1944 unsigned long time_left;
1945 1945
1946 if (!Fout) { 1946 if (!Fout) {
1947 dev_dbg(codec->dev, "FLL disabled"); 1947 dev_dbg(codec->dev, "FLL disabled");
@@ -2021,9 +2021,10 @@ static int wm2200_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2021 /* Poll for the lock; will use the interrupt to exit quickly */ 2021 /* Poll for the lock; will use the interrupt to exit quickly */
2022 for (i = 0; i < timeout; i++) { 2022 for (i = 0; i < timeout; i++) {
2023 if (i2c->irq) { 2023 if (i2c->irq) {
2024 ret = wait_for_completion_timeout(&wm2200->fll_lock, 2024 time_left = wait_for_completion_timeout(
2025 msecs_to_jiffies(25)); 2025 &wm2200->fll_lock,
2026 if (ret > 0) 2026 msecs_to_jiffies(25));
2027 if (time_left > 0)
2027 break; 2028 break;
2028 } else { 2029 } else {
2029 msleep(1); 2030 msleep(1);
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c
index ea09db585aa1..96740379b711 100644
--- a/sound/soc/codecs/wm5100.c
+++ b/sound/soc/codecs/wm5100.c
@@ -1762,6 +1762,7 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1762 struct _fll_div factors; 1762 struct _fll_div factors;
1763 struct wm5100_fll *fll; 1763 struct wm5100_fll *fll;
1764 int ret, base, lock, i, timeout; 1764 int ret, base, lock, i, timeout;
1765 unsigned long time_left;
1765 1766
1766 switch (fll_id) { 1767 switch (fll_id) {
1767 case WM5100_FLL1: 1768 case WM5100_FLL1:
@@ -1842,9 +1843,9 @@ static int wm5100_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
1842 /* Poll for the lock; will use interrupt when we can test */ 1843 /* Poll for the lock; will use interrupt when we can test */
1843 for (i = 0; i < timeout; i++) { 1844 for (i = 0; i < timeout; i++) {
1844 if (i2c->irq) { 1845 if (i2c->irq) {
1845 ret = wait_for_completion_timeout(&fll->lock, 1846 time_left = wait_for_completion_timeout(&fll->lock,
1846 msecs_to_jiffies(25)); 1847 msecs_to_jiffies(25));
1847 if (ret > 0) 1848 if (time_left > 0)
1848 break; 1849 break;
1849 } else { 1850 } else {
1850 msleep(1); 1851 msleep(1);
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index c6d10533e2bd..2245b6a32f3d 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -25,6 +25,7 @@
25#include <linux/spi/spi.h> 25#include <linux/spi/spi.h>
26#include <linux/of_device.h> 26#include <linux/of_device.h>
27#include <linux/mutex.h> 27#include <linux/mutex.h>
28#include <linux/clk.h>
28#include <sound/core.h> 29#include <sound/core.h>
29#include <sound/pcm.h> 30#include <sound/pcm.h>
30#include <sound/pcm_params.h> 31#include <sound/pcm_params.h>
@@ -45,6 +46,7 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
45/* codec private data */ 46/* codec private data */
46struct wm8731_priv { 47struct wm8731_priv {
47 struct regmap *regmap; 48 struct regmap *regmap;
49 struct clk *mclk;
48 struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; 50 struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
49 const struct snd_pcm_hw_constraint_list *constraints; 51 const struct snd_pcm_hw_constraint_list *constraints;
50 unsigned int sysclk; 52 unsigned int sysclk;
@@ -390,6 +392,8 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
390 switch (clk_id) { 392 switch (clk_id) {
391 case WM8731_SYSCLK_XTAL: 393 case WM8731_SYSCLK_XTAL:
392 case WM8731_SYSCLK_MCLK: 394 case WM8731_SYSCLK_MCLK:
395 if (wm8731->mclk && clk_set_rate(wm8731->mclk, freq))
396 return -EINVAL;
393 wm8731->sysclk_type = clk_id; 397 wm8731->sysclk_type = clk_id;
394 break; 398 break;
395 default: 399 default:
@@ -491,6 +495,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
491 495
492 switch (level) { 496 switch (level) {
493 case SND_SOC_BIAS_ON: 497 case SND_SOC_BIAS_ON:
498 if (wm8731->mclk)
499 clk_prepare_enable(wm8731->mclk);
494 break; 500 break;
495 case SND_SOC_BIAS_PREPARE: 501 case SND_SOC_BIAS_PREPARE:
496 break; 502 break;
@@ -509,6 +515,8 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
509 snd_soc_write(codec, WM8731_PWR, reg | 0x0040); 515 snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
510 break; 516 break;
511 case SND_SOC_BIAS_OFF: 517 case SND_SOC_BIAS_OFF:
518 if (wm8731->mclk)
519 clk_disable_unprepare(wm8731->mclk);
512 snd_soc_write(codec, WM8731_PWR, 0xffff); 520 snd_soc_write(codec, WM8731_PWR, 0xffff);
513 regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), 521 regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
514 wm8731->supplies); 522 wm8731->supplies);
@@ -667,6 +675,19 @@ static int wm8731_spi_probe(struct spi_device *spi)
667 if (wm8731 == NULL) 675 if (wm8731 == NULL)
668 return -ENOMEM; 676 return -ENOMEM;
669 677
678 wm8731->mclk = devm_clk_get(&spi->dev, "mclk");
679 if (IS_ERR(wm8731->mclk)) {
680 ret = PTR_ERR(wm8731->mclk);
681 if (ret == -ENOENT) {
682 wm8731->mclk = NULL;
683 dev_warn(&spi->dev, "Assuming static MCLK\n");
684 } else {
685 dev_err(&spi->dev, "Failed to get MCLK: %d\n",
686 ret);
687 return ret;
688 }
689 }
690
670 mutex_init(&wm8731->lock); 691 mutex_init(&wm8731->lock);
671 692
672 wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); 693 wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
@@ -718,6 +739,19 @@ static int wm8731_i2c_probe(struct i2c_client *i2c,
718 if (wm8731 == NULL) 739 if (wm8731 == NULL)
719 return -ENOMEM; 740 return -ENOMEM;
720 741
742 wm8731->mclk = devm_clk_get(&i2c->dev, "mclk");
743 if (IS_ERR(wm8731->mclk)) {
744 ret = PTR_ERR(wm8731->mclk);
745 if (ret == -ENOENT) {
746 wm8731->mclk = NULL;
747 dev_warn(&i2c->dev, "Assuming static MCLK\n");
748 } else {
749 dev_err(&i2c->dev, "Failed to get MCLK: %d\n",
750 ret);
751 return ret;
752 }
753 }
754
721 mutex_init(&wm8731->lock); 755 mutex_init(&wm8731->lock);
722 756
723 wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); 757 wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap);
diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c
index 5bd4af2b4059..6596f5f3a0c3 100644
--- a/sound/soc/codecs/wm8804-i2c.c
+++ b/sound/soc/codecs/wm8804-i2c.c
@@ -50,6 +50,7 @@ static struct i2c_driver wm8804_i2c_driver = {
50 .driver = { 50 .driver = {
51 .name = "wm8804", 51 .name = "wm8804",
52 .owner = THIS_MODULE, 52 .owner = THIS_MODULE,
53 .pm = &wm8804_pm,
53 .of_match_table = wm8804_of_match, 54 .of_match_table = wm8804_of_match,
54 }, 55 },
55 .probe = wm8804_i2c_probe, 56 .probe = wm8804_i2c_probe,
diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c
index 287e11e90794..407a3cf391e5 100644
--- a/sound/soc/codecs/wm8804-spi.c
+++ b/sound/soc/codecs/wm8804-spi.c
@@ -43,6 +43,7 @@ static struct spi_driver wm8804_spi_driver = {
43 .driver = { 43 .driver = {
44 .name = "wm8804", 44 .name = "wm8804",
45 .owner = THIS_MODULE, 45 .owner = THIS_MODULE,
46 .pm = &wm8804_pm,
46 .of_match_table = wm8804_of_match, 47 .of_match_table = wm8804_of_match,
47 }, 48 },
48 .probe = wm8804_spi_probe, 49 .probe = wm8804_spi_probe,
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 1bd4ace29594..1e403f67cf16 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -13,8 +13,10 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/moduleparam.h> 14#include <linux/moduleparam.h>
15#include <linux/init.h> 15#include <linux/init.h>
16#include <linux/gpio/consumer.h>
16#include <linux/delay.h> 17#include <linux/delay.h>
17#include <linux/pm.h> 18#include <linux/pm.h>
19#include <linux/pm_runtime.h>
18#include <linux/of_device.h> 20#include <linux/of_device.h>
19#include <linux/regulator/consumer.h> 21#include <linux/regulator/consumer.h>
20#include <linux/slab.h> 22#include <linux/slab.h>
@@ -24,6 +26,7 @@
24#include <sound/soc.h> 26#include <sound/soc.h>
25#include <sound/initval.h> 27#include <sound/initval.h>
26#include <sound/tlv.h> 28#include <sound/tlv.h>
29#include <sound/soc-dapm.h>
27 30
28#include "wm8804.h" 31#include "wm8804.h"
29 32
@@ -57,18 +60,23 @@ static const struct reg_default wm8804_reg_defaults[] = {
57}; 60};
58 61
59struct wm8804_priv { 62struct wm8804_priv {
63 struct device *dev;
60 struct regmap *regmap; 64 struct regmap *regmap;
61 struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES]; 65 struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
62 struct notifier_block disable_nb[WM8804_NUM_SUPPLIES]; 66 struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
63 int mclk_div; 67 int mclk_div;
64};
65 68
66static int txsrc_get(struct snd_kcontrol *kcontrol, 69 struct gpio_desc *reset;
67 struct snd_ctl_elem_value *ucontrol); 70
71 int aif_pwr;
72};
68 73
69static int txsrc_put(struct snd_kcontrol *kcontrol, 74static int txsrc_put(struct snd_kcontrol *kcontrol,
70 struct snd_ctl_elem_value *ucontrol); 75 struct snd_ctl_elem_value *ucontrol);
71 76
77static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
78 struct snd_kcontrol *kcontrol, int event);
79
72/* 80/*
73 * We can't use the same notifier block for more than one supply and 81 * We can't use the same notifier block for more than one supply and
74 * there's no way I can see to get from a callback to the caller 82 * there's no way I can see to get from a callback to the caller
@@ -90,26 +98,62 @@ WM8804_REGULATOR_EVENT(0)
90WM8804_REGULATOR_EVENT(1) 98WM8804_REGULATOR_EVENT(1)
91 99
92static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; 100static const char *txsrc_text[] = { "S/PDIF RX", "AIF" };
93static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); 101static const SOC_ENUM_SINGLE_DECL(txsrc, WM8804_SPDTX4, 6, txsrc_text);
94 102
95static const struct snd_kcontrol_new wm8804_snd_controls[] = { 103static const struct snd_kcontrol_new wm8804_tx_source_mux[] = {
96 SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), 104 SOC_DAPM_ENUM_EXT("Input Source", txsrc,
97 SOC_SINGLE("TX Playback Switch", WM8804_PWRDN, 2, 1, 1), 105 snd_soc_dapm_get_enum_double, txsrc_put),
98 SOC_SINGLE("AIF Playback Switch", WM8804_PWRDN, 4, 1, 1)
99}; 106};
100 107
101static int txsrc_get(struct snd_kcontrol *kcontrol, 108static const struct snd_soc_dapm_widget wm8804_dapm_widgets[] = {
102 struct snd_ctl_elem_value *ucontrol) 109SND_SOC_DAPM_OUTPUT("SPDIF Out"),
103{ 110SND_SOC_DAPM_INPUT("SPDIF In"),
104 struct snd_soc_codec *codec; 111
105 unsigned int src; 112SND_SOC_DAPM_PGA("SPDIFTX", WM8804_PWRDN, 2, 1, NULL, 0),
113SND_SOC_DAPM_PGA("SPDIFRX", WM8804_PWRDN, 1, 1, NULL, 0),
114
115SND_SOC_DAPM_MUX("Tx Source", SND_SOC_NOPM, 6, 0, wm8804_tx_source_mux),
116
117SND_SOC_DAPM_AIF_OUT_E("AIFTX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
118 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
119SND_SOC_DAPM_AIF_IN_E("AIFRX", NULL, 0, SND_SOC_NOPM, 0, 0, wm8804_aif_event,
120 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
121};
122
123static const struct snd_soc_dapm_route wm8804_dapm_routes[] = {
124 { "AIFRX", NULL, "Playback" },
125 { "Tx Source", "AIF", "AIFRX" },
126
127 { "SPDIFRX", NULL, "SPDIF In" },
128 { "Tx Source", "S/PDIF RX", "SPDIFRX" },
106 129
107 codec = snd_soc_kcontrol_codec(kcontrol); 130 { "SPDIFTX", NULL, "Tx Source" },
108 src = snd_soc_read(codec, WM8804_SPDTX4); 131 { "SPDIF Out", NULL, "SPDIFTX" },
109 if (src & 0x40) 132
110 ucontrol->value.integer.value[0] = 1; 133 { "AIFTX", NULL, "SPDIFRX" },
111 else 134 { "Capture", NULL, "AIFTX" },
112 ucontrol->value.integer.value[0] = 0; 135};
136
137static int wm8804_aif_event(struct snd_soc_dapm_widget *w,
138 struct snd_kcontrol *kcontrol, int event)
139{
140 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
141 struct wm8804_priv *wm8804 = snd_soc_codec_get_drvdata(codec);
142
143 switch (event) {
144 case SND_SOC_DAPM_POST_PMU:
145 /* power up the aif */
146 if (!wm8804->aif_pwr)
147 snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0x0);
148 wm8804->aif_pwr++;
149 break;
150 case SND_SOC_DAPM_POST_PMD:
151 /* power down only both paths are disabled */
152 wm8804->aif_pwr--;
153 if (!wm8804->aif_pwr)
154 snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0x10);
155 break;
156 }
113 157
114 return 0; 158 return 0;
115} 159}
@@ -117,48 +161,33 @@ static int txsrc_get(struct snd_kcontrol *kcontrol,
117static int txsrc_put(struct snd_kcontrol *kcontrol, 161static int txsrc_put(struct snd_kcontrol *kcontrol,
118 struct snd_ctl_elem_value *ucontrol) 162 struct snd_ctl_elem_value *ucontrol)
119{ 163{
120 struct snd_soc_codec *codec; 164 struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
121 unsigned int src, txpwr; 165 struct snd_soc_dapm_context *dapm = &codec->dapm;
166 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
167 unsigned int val = ucontrol->value.enumerated.item[0] << e->shift_l;
168 unsigned int mask = 1 << e->shift_l;
169 unsigned int txpwr;
170
171 if (val != 0 && val != mask)
172 return -EINVAL;
122 173
123 codec = snd_soc_kcontrol_codec(kcontrol); 174 snd_soc_dapm_mutex_lock(dapm);
124 175
125 if (ucontrol->value.integer.value[0] != 0 176 if (snd_soc_test_bits(codec, e->reg, mask, val)) {
126 && ucontrol->value.integer.value[0] != 1) 177 /* save the current power state of the transmitter */
127 return -EINVAL; 178 txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4;
128 179
129 src = snd_soc_read(codec, WM8804_SPDTX4); 180 /* power down the transmitter */
130 switch ((src & 0x40) >> 6) { 181 snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4);
131 case 0:
132 if (!ucontrol->value.integer.value[0])
133 return 0;
134 break;
135 case 1:
136 if (ucontrol->value.integer.value[1])
137 return 0;
138 break;
139 }
140 182
141 /* save the current power state of the transmitter */ 183 /* set the tx source */
142 txpwr = snd_soc_read(codec, WM8804_PWRDN) & 0x4; 184 snd_soc_update_bits(codec, e->reg, mask, val);
143 /* power down the transmitter */ 185
144 snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x4); 186 /* restore the transmitter's configuration */
145 /* set the tx source */ 187 snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
146 snd_soc_update_bits(codec, WM8804_SPDTX4, 0x40,
147 ucontrol->value.integer.value[0] << 6);
148
149 if (ucontrol->value.integer.value[0]) {
150 /* power down the receiver */
151 snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0x2);
152 /* power up the AIF */
153 snd_soc_update_bits(codec, WM8804_PWRDN, 0x10, 0);
154 } else {
155 /* don't power down the AIF -- may be used as an output */
156 /* power up the receiver */
157 snd_soc_update_bits(codec, WM8804_PWRDN, 0x2, 0);
158 } 188 }
159 189
160 /* restore the transmitter's configuration */ 190 snd_soc_dapm_mutex_unlock(dapm);
161 snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, txpwr);
162 191
163 return 0; 192 return 0;
164} 193}
@@ -182,7 +211,7 @@ static bool wm8804_volatile(struct device *dev, unsigned int reg)
182 } 211 }
183} 212}
184 213
185static int wm8804_reset(struct wm8804_priv *wm8804) 214static int wm8804_soft_reset(struct wm8804_priv *wm8804)
186{ 215{
187 return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0); 216 return regmap_write(wm8804->regmap, WM8804_RST_DEVID1, 0x0);
188} 217}
@@ -376,19 +405,19 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
376 int source, unsigned int freq_in, 405 int source, unsigned int freq_in,
377 unsigned int freq_out) 406 unsigned int freq_out)
378{ 407{
379 struct snd_soc_codec *codec; 408 struct snd_soc_codec *codec = dai->codec;
409 struct wm8804_priv *wm8804 = snd_soc_codec_get_drvdata(codec);
410 bool change;
380 411
381 codec = dai->codec;
382 if (!freq_in || !freq_out) { 412 if (!freq_in || !freq_out) {
383 /* disable the PLL */ 413 /* disable the PLL */
384 snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1); 414 regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
385 return 0; 415 0x1, 0x1, &change);
416 if (change)
417 pm_runtime_put(wm8804->dev);
386 } else { 418 } else {
387 int ret; 419 int ret;
388 struct pll_div pll_div; 420 struct pll_div pll_div;
389 struct wm8804_priv *wm8804;
390
391 wm8804 = snd_soc_codec_get_drvdata(codec);
392 421
393 ret = pll_factors(&pll_div, freq_out, freq_in, 422 ret = pll_factors(&pll_div, freq_out, freq_in,
394 wm8804->mclk_div); 423 wm8804->mclk_div);
@@ -396,7 +425,10 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
396 return ret; 425 return ret;
397 426
398 /* power down the PLL before reprogramming it */ 427 /* power down the PLL before reprogramming it */
399 snd_soc_update_bits(codec, WM8804_PWRDN, 0x1, 0x1); 428 regmap_update_bits_check(wm8804->regmap, WM8804_PWRDN,
429 0x1, 0x1, &change);
430 if (!change)
431 pm_runtime_get_sync(wm8804->dev);
400 432
401 /* set PLLN and PRESCALE */ 433 /* set PLLN and PRESCALE */
402 snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10, 434 snd_soc_update_bits(codec, WM8804_PLL4, 0xf | 0x10,
@@ -474,47 +506,6 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
474 return 0; 506 return 0;
475} 507}
476 508
477static int wm8804_set_bias_level(struct snd_soc_codec *codec,
478 enum snd_soc_bias_level level)
479{
480 int ret;
481 struct wm8804_priv *wm8804;
482
483 wm8804 = snd_soc_codec_get_drvdata(codec);
484 switch (level) {
485 case SND_SOC_BIAS_ON:
486 break;
487 case SND_SOC_BIAS_PREPARE:
488 /* power up the OSC and the PLL */
489 snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
490 break;
491 case SND_SOC_BIAS_STANDBY:
492 if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
493 ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
494 wm8804->supplies);
495 if (ret) {
496 dev_err(codec->dev,
497 "Failed to enable supplies: %d\n",
498 ret);
499 return ret;
500 }
501 regcache_sync(wm8804->regmap);
502 }
503 /* power down the OSC and the PLL */
504 snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
505 break;
506 case SND_SOC_BIAS_OFF:
507 /* power down the OSC and the PLL */
508 snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0x9);
509 regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
510 wm8804->supplies);
511 break;
512 }
513
514 codec->dapm.bias_level = level;
515 return 0;
516}
517
518static const struct snd_soc_dai_ops wm8804_dai_ops = { 509static const struct snd_soc_dai_ops wm8804_dai_ops = {
519 .hw_params = wm8804_hw_params, 510 .hw_params = wm8804_hw_params,
520 .set_fmt = wm8804_set_fmt, 511 .set_fmt = wm8804_set_fmt,
@@ -552,11 +543,12 @@ static struct snd_soc_dai_driver wm8804_dai = {
552}; 543};
553 544
554static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = { 545static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
555 .set_bias_level = wm8804_set_bias_level,
556 .idle_bias_off = true, 546 .idle_bias_off = true,
557 547
558 .controls = wm8804_snd_controls, 548 .dapm_widgets = wm8804_dapm_widgets,
559 .num_controls = ARRAY_SIZE(wm8804_snd_controls), 549 .num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets),
550 .dapm_routes = wm8804_dapm_routes,
551 .num_dapm_routes = ARRAY_SIZE(wm8804_dapm_routes),
560}; 552};
561 553
562const struct regmap_config wm8804_regmap_config = { 554const struct regmap_config wm8804_regmap_config = {
@@ -584,8 +576,17 @@ int wm8804_probe(struct device *dev, struct regmap *regmap)
584 576
585 dev_set_drvdata(dev, wm8804); 577 dev_set_drvdata(dev, wm8804);
586 578
579 wm8804->dev = dev;
587 wm8804->regmap = regmap; 580 wm8804->regmap = regmap;
588 581
582 wm8804->reset = devm_gpiod_get_optional(dev, "wlf,reset",
583 GPIOD_OUT_LOW);
584 if (IS_ERR(wm8804->reset)) {
585 ret = PTR_ERR(wm8804->reset);
586 dev_err(dev, "Failed to get reset line: %d\n", ret);
587 return ret;
588 }
589
589 for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) 590 for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++)
590 wm8804->supplies[i].supply = wm8804_supply_names[i]; 591 wm8804->supplies[i].supply = wm8804_supply_names[i];
591 592
@@ -601,12 +602,15 @@ int wm8804_probe(struct device *dev, struct regmap *regmap)
601 602
602 /* This should really be moved into the regulator core */ 603 /* This should really be moved into the regulator core */
603 for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) { 604 for (i = 0; i < ARRAY_SIZE(wm8804->supplies); i++) {
604 ret = regulator_register_notifier(wm8804->supplies[i].consumer, 605 struct regulator *regulator = wm8804->supplies[i].consumer;
605 &wm8804->disable_nb[i]); 606
607 ret = devm_regulator_register_notifier(regulator,
608 &wm8804->disable_nb[i]);
606 if (ret != 0) { 609 if (ret != 0) {
607 dev_err(dev, 610 dev_err(dev,
608 "Failed to register regulator notifier: %d\n", 611 "Failed to register regulator notifier: %d\n",
609 ret); 612 ret);
613 return ret;
610 } 614 }
611 } 615 }
612 616
@@ -614,9 +618,12 @@ int wm8804_probe(struct device *dev, struct regmap *regmap)
614 wm8804->supplies); 618 wm8804->supplies);
615 if (ret) { 619 if (ret) {
616 dev_err(dev, "Failed to enable supplies: %d\n", ret); 620 dev_err(dev, "Failed to enable supplies: %d\n", ret);
617 goto err_reg_enable; 621 return ret;
618 } 622 }
619 623
624 if (wm8804->reset)
625 gpiod_set_value_cansleep(wm8804->reset, 1);
626
620 ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1); 627 ret = regmap_read(regmap, WM8804_RST_DEVID1, &id1);
621 if (ret < 0) { 628 if (ret < 0) {
622 dev_err(dev, "Failed to read device ID: %d\n", ret); 629 dev_err(dev, "Failed to read device ID: %d\n", ret);
@@ -645,14 +652,26 @@ int wm8804_probe(struct device *dev, struct regmap *regmap)
645 } 652 }
646 dev_info(dev, "revision %c\n", id1 + 'A'); 653 dev_info(dev, "revision %c\n", id1 + 'A');
647 654
648 ret = wm8804_reset(wm8804); 655 if (!wm8804->reset) {
656 ret = wm8804_soft_reset(wm8804);
657 if (ret < 0) {
658 dev_err(dev, "Failed to issue reset: %d\n", ret);
659 goto err_reg_enable;
660 }
661 }
662
663 ret = snd_soc_register_codec(dev, &soc_codec_dev_wm8804,
664 &wm8804_dai, 1);
649 if (ret < 0) { 665 if (ret < 0) {
650 dev_err(dev, "Failed to issue reset: %d\n", ret); 666 dev_err(dev, "Failed to register CODEC: %d\n", ret);
651 goto err_reg_enable; 667 goto err_reg_enable;
652 } 668 }
653 669
654 return snd_soc_register_codec(dev, &soc_codec_dev_wm8804, 670 pm_runtime_set_active(dev);
655 &wm8804_dai, 1); 671 pm_runtime_enable(dev);
672 pm_runtime_idle(dev);
673
674 return 0;
656 675
657err_reg_enable: 676err_reg_enable:
658 regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies); 677 regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies), wm8804->supplies);
@@ -662,18 +681,50 @@ EXPORT_SYMBOL_GPL(wm8804_probe);
662 681
663void wm8804_remove(struct device *dev) 682void wm8804_remove(struct device *dev)
664{ 683{
665 struct wm8804_priv *wm8804; 684 pm_runtime_disable(dev);
666 int i; 685 snd_soc_unregister_codec(dev);
686}
687EXPORT_SYMBOL_GPL(wm8804_remove);
667 688
668 wm8804 = dev_get_drvdata(dev); 689#if IS_ENABLED(CONFIG_PM)
690static int wm8804_runtime_resume(struct device *dev)
691{
692 struct wm8804_priv *wm8804 = dev_get_drvdata(dev);
693 int ret;
669 694
670 for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) 695 ret = regulator_bulk_enable(ARRAY_SIZE(wm8804->supplies),
671 regulator_unregister_notifier(wm8804->supplies[i].consumer, 696 wm8804->supplies);
672 &wm8804->disable_nb[i]); 697 if (ret) {
698 dev_err(wm8804->dev, "Failed to enable supplies: %d\n", ret);
699 return ret;
700 }
673 701
674 snd_soc_unregister_codec(dev); 702 regcache_sync(wm8804->regmap);
703
704 /* Power up OSCCLK */
705 regmap_update_bits(wm8804->regmap, WM8804_PWRDN, 0x8, 0x0);
706
707 return 0;
675} 708}
676EXPORT_SYMBOL_GPL(wm8804_remove); 709
710static int wm8804_runtime_suspend(struct device *dev)
711{
712 struct wm8804_priv *wm8804 = dev_get_drvdata(dev);
713
714 /* Power down OSCCLK */
715 regmap_update_bits(wm8804->regmap, WM8804_PWRDN, 0x8, 0x8);
716
717 regulator_bulk_disable(ARRAY_SIZE(wm8804->supplies),
718 wm8804->supplies);
719
720 return 0;
721}
722#endif
723
724const struct dev_pm_ops wm8804_pm = {
725 SET_RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL)
726};
727EXPORT_SYMBOL_GPL(wm8804_pm);
677 728
678MODULE_DESCRIPTION("ASoC WM8804 driver"); 729MODULE_DESCRIPTION("ASoC WM8804 driver");
679MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); 730MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
index a39a2563dc67..aa72fa66c932 100644
--- a/sound/soc/codecs/wm8804.h
+++ b/sound/soc/codecs/wm8804.h
@@ -65,6 +65,7 @@
65#define WM8804_MCLKDIV_128FS 1 65#define WM8804_MCLKDIV_128FS 1
66 66
67extern const struct regmap_config wm8804_regmap_config; 67extern const struct regmap_config wm8804_regmap_config;
68extern const struct dev_pm_ops wm8804_pm;
68 69
69int wm8804_probe(struct device *dev, struct regmap *regmap); 70int wm8804_probe(struct device *dev, struct regmap *regmap);
70void wm8804_remove(struct device *dev); 71void wm8804_remove(struct device *dev);
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index dc92d5e4e942..308748a022c5 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -2009,7 +2009,7 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2009 struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); 2009 struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec);
2010 struct i2c_client *i2c = to_i2c_client(codec->dev); 2010 struct i2c_client *i2c = to_i2c_client(codec->dev);
2011 struct _fll_div fll_div; 2011 struct _fll_div fll_div;
2012 unsigned long timeout; 2012 unsigned long timeout, time_left;
2013 int ret, reg, retry; 2013 int ret, reg, retry;
2014 2014
2015 /* Any change? */ 2015 /* Any change? */
@@ -2110,13 +2110,15 @@ static int wm8996_set_fll(struct snd_soc_codec *codec, int fll_id, int source,
2110 if (i2c->irq) 2110 if (i2c->irq)
2111 timeout *= 10; 2111 timeout *= 10;
2112 else 2112 else
2113 timeout /= 2; 2113 /* ensure timeout of atleast 1 jiffies */
2114 timeout = timeout/2 ? : 1;
2114 2115
2115 for (retry = 0; retry < 10; retry++) { 2116 for (retry = 0; retry < 10; retry++) {
2116 ret = wait_for_completion_timeout(&wm8996->fll_lock, 2117 time_left = wait_for_completion_timeout(&wm8996->fll_lock,
2117 timeout); 2118 timeout);
2118 if (ret != 0) { 2119 if (time_left != 0) {
2119 WARN_ON(!i2c->irq); 2120 WARN_ON(!i2c->irq);
2121 ret = 1;
2120 break; 2122 break;
2121 } 2123 }
2122 2124