diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/88pm860x-codec.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/ac97.c | 7 | ||||
-rw-r--r-- | sound/soc/codecs/ad1980.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/adau1701.c | 302 | ||||
-rw-r--r-- | sound/soc/codecs/stac9766.c | 26 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/wm8400.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8903.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/wm8904.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/wm8991.h | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/wm8995.h | 7 | ||||
-rw-r--r-- | sound/soc/codecs/wm9705.c | 16 | ||||
-rw-r--r-- | sound/soc/codecs/wm9712.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/wm9713.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 459 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 13 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 6 |
19 files changed, 789 insertions, 163 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 60159c07448d..e2bd3dd02c0e 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
@@ -120,10 +120,8 @@ | |||
120 | * before DAC & PGA in DAPM power-off sequence. | 120 | * before DAC & PGA in DAPM power-off sequence. |
121 | */ | 121 | */ |
122 | #define PM860X_DAPM_OUTPUT(wname, wevent) \ | 122 | #define PM860X_DAPM_OUTPUT(wname, wevent) \ |
123 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ | 123 | SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \ |
124 | .shift = 0, .invert = 0, .kcontrol_news = NULL, \ | 124 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD) |
125 | .num_kcontrols = 0, .event = wevent, \ | ||
126 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, } | ||
127 | 125 | ||
128 | struct pm860x_det { | 126 | struct pm860x_det { |
129 | struct snd_soc_jack *hp_jack; | 127 | struct snd_soc_jack *hp_jack; |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index ef2ae32ffc66..ec7351803c24 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = { | |||
62 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 62 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
63 | unsigned int reg) | 63 | unsigned int reg) |
64 | { | 64 | { |
65 | return soc_ac97_ops.read(codec->ac97, reg); | 65 | return soc_ac97_ops->read(codec->ac97, reg); |
66 | } | 66 | } |
67 | 67 | ||
68 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 68 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
69 | unsigned int val) | 69 | unsigned int val) |
70 | { | 70 | { |
71 | soc_ac97_ops.write(codec->ac97, reg, val); | 71 | soc_ac97_ops->write(codec->ac97, reg, val); |
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
@@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) | |||
79 | int ret; | 79 | int ret; |
80 | 80 | ||
81 | /* add codec as bus device for standard ac97 */ | 81 | /* add codec as bus device for standard ac97 */ |
82 | ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus); | 82 | ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL, |
83 | &ac97_bus); | ||
83 | if (ret < 0) | 84 | if (ret < 0) |
84 | return ret; | 85 | return ret; |
85 | 86 | ||
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index f385342947d3..89fcf7d6e7b8 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
108 | case AC97_EXTENDED_STATUS: | 108 | case AC97_EXTENDED_STATUS: |
109 | case AC97_VENDOR_ID1: | 109 | case AC97_VENDOR_ID1: |
110 | case AC97_VENDOR_ID2: | 110 | case AC97_VENDOR_ID2: |
111 | return soc_ac97_ops.read(codec->ac97, reg); | 111 | return soc_ac97_ops->read(codec->ac97, reg); |
112 | default: | 112 | default: |
113 | reg = reg >> 1; | 113 | reg = reg >> 1; |
114 | 114 | ||
@@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
124 | { | 124 | { |
125 | u16 *cache = codec->reg_cache; | 125 | u16 *cache = codec->reg_cache; |
126 | 126 | ||
127 | soc_ac97_ops.write(codec->ac97, reg, val); | 127 | soc_ac97_ops->write(codec->ac97, reg, val); |
128 | reg = reg >> 1; | 128 | reg = reg >> 1; |
129 | if (reg < ARRAY_SIZE(ad1980_reg)) | 129 | if (reg < ARRAY_SIZE(ad1980_reg)) |
130 | cache[reg] = val; | 130 | cache[reg] = val; |
@@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | |||
154 | u16 retry_cnt = 0; | 154 | u16 retry_cnt = 0; |
155 | 155 | ||
156 | retry: | 156 | retry: |
157 | if (try_warm && soc_ac97_ops.warm_reset) { | 157 | if (try_warm && soc_ac97_ops->warm_reset) { |
158 | soc_ac97_ops.warm_reset(codec->ac97); | 158 | soc_ac97_ops->warm_reset(codec->ac97); |
159 | if (ac97_read(codec, AC97_RESET) == 0x0090) | 159 | if (ac97_read(codec, AC97_RESET) == 0x0090) |
160 | return 1; | 160 | return 1; |
161 | } | 161 | } |
162 | 162 | ||
163 | soc_ac97_ops.reset(codec->ac97); | 163 | soc_ac97_ops->reset(codec->ac97); |
164 | /* Set bit 16slot in register 74h, then every slot will has only 16 | 164 | /* Set bit 16slot in register 74h, then every slot will has only 16 |
165 | * bits. This command is sent out in 20bit mode, in which case the | 165 | * bits. This command is sent out in 20bit mode, in which case the |
166 | * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ | 166 | * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ |
@@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) | |||
186 | 186 | ||
187 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | 187 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); |
188 | 188 | ||
189 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | 189 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); |
190 | if (ret < 0) { | 190 | if (ret < 0) { |
191 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | 191 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); |
192 | return ret; | 192 | return ret; |
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index dafdbe87edeb..0e250f118c0e 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -13,6 +13,10 @@ | |||
13 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/of.h> | ||
17 | #include <linux/of_gpio.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/regmap.h> | ||
16 | #include <sound/core.h> | 20 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
18 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
@@ -21,16 +25,19 @@ | |||
21 | #include "sigmadsp.h" | 25 | #include "sigmadsp.h" |
22 | #include "adau1701.h" | 26 | #include "adau1701.h" |
23 | 27 | ||
24 | #define ADAU1701_DSPCTRL 0x1c | 28 | #define ADAU1701_DSPCTRL 0x081c |
25 | #define ADAU1701_SEROCTL 0x1e | 29 | #define ADAU1701_SEROCTL 0x081e |
26 | #define ADAU1701_SERICTL 0x1f | 30 | #define ADAU1701_SERICTL 0x081f |
27 | 31 | ||
28 | #define ADAU1701_AUXNPOW 0x22 | 32 | #define ADAU1701_AUXNPOW 0x0822 |
33 | #define ADAU1701_PINCONF_0 0x0820 | ||
34 | #define ADAU1701_PINCONF_1 0x0821 | ||
35 | #define ADAU1701_AUXNPOW 0x0822 | ||
29 | 36 | ||
30 | #define ADAU1701_OSCIPOW 0x26 | 37 | #define ADAU1701_OSCIPOW 0x0826 |
31 | #define ADAU1701_DACSET 0x27 | 38 | #define ADAU1701_DACSET 0x0827 |
32 | 39 | ||
33 | #define ADAU1701_NUM_REGS 0x28 | 40 | #define ADAU1701_MAX_REGISTER 0x0828 |
34 | 41 | ||
35 | #define ADAU1701_DSPCTRL_CR (1 << 2) | 42 | #define ADAU1701_DSPCTRL_CR (1 << 2) |
36 | #define ADAU1701_DSPCTRL_DAM (1 << 3) | 43 | #define ADAU1701_DSPCTRL_DAM (1 << 3) |
@@ -84,10 +91,18 @@ | |||
84 | #define ADAU1701_OSCIPOW_OPD 0x04 | 91 | #define ADAU1701_OSCIPOW_OPD 0x04 |
85 | #define ADAU1701_DACSET_DACINIT 1 | 92 | #define ADAU1701_DACSET_DACINIT 1 |
86 | 93 | ||
94 | #define ADAU1707_CLKDIV_UNSET (-1UL) | ||
95 | |||
87 | #define ADAU1701_FIRMWARE "adau1701.bin" | 96 | #define ADAU1701_FIRMWARE "adau1701.bin" |
88 | 97 | ||
89 | struct adau1701 { | 98 | struct adau1701 { |
99 | int gpio_nreset; | ||
100 | int gpio_pll_mode[2]; | ||
90 | unsigned int dai_fmt; | 101 | unsigned int dai_fmt; |
102 | unsigned int pll_clkdiv; | ||
103 | unsigned int sysclk; | ||
104 | struct regmap *regmap; | ||
105 | u8 pin_config[12]; | ||
91 | }; | 106 | }; |
92 | 107 | ||
93 | static const struct snd_kcontrol_new adau1701_controls[] = { | 108 | static const struct snd_kcontrol_new adau1701_controls[] = { |
@@ -119,10 +134,13 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { | |||
119 | { "ADC", NULL, "IN1" }, | 134 | { "ADC", NULL, "IN1" }, |
120 | }; | 135 | }; |
121 | 136 | ||
122 | static unsigned int adau1701_register_size(struct snd_soc_codec *codec, | 137 | static unsigned int adau1701_register_size(struct device *dev, |
123 | unsigned int reg) | 138 | unsigned int reg) |
124 | { | 139 | { |
125 | switch (reg) { | 140 | switch (reg) { |
141 | case ADAU1701_PINCONF_0: | ||
142 | case ADAU1701_PINCONF_1: | ||
143 | return 3; | ||
126 | case ADAU1701_DSPCTRL: | 144 | case ADAU1701_DSPCTRL: |
127 | case ADAU1701_SEROCTL: | 145 | case ADAU1701_SEROCTL: |
128 | case ADAU1701_AUXNPOW: | 146 | case ADAU1701_AUXNPOW: |
@@ -133,33 +151,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec, | |||
133 | return 1; | 151 | return 1; |
134 | } | 152 | } |
135 | 153 | ||
136 | dev_err(codec->dev, "Unsupported register address: %d\n", reg); | 154 | dev_err(dev, "Unsupported register address: %d\n", reg); |
137 | return 0; | 155 | return 0; |
138 | } | 156 | } |
139 | 157 | ||
140 | static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, | 158 | static bool adau1701_volatile_reg(struct device *dev, unsigned int reg) |
141 | unsigned int value) | ||
142 | { | 159 | { |
160 | switch (reg) { | ||
161 | case ADAU1701_DACSET: | ||
162 | return true; | ||
163 | default: | ||
164 | return false; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static int adau1701_reg_write(void *context, unsigned int reg, | ||
169 | unsigned int value) | ||
170 | { | ||
171 | struct i2c_client *client = context; | ||
143 | unsigned int i; | 172 | unsigned int i; |
144 | unsigned int size; | 173 | unsigned int size; |
145 | uint8_t buf[4]; | 174 | uint8_t buf[5]; |
146 | int ret; | 175 | int ret; |
147 | 176 | ||
148 | size = adau1701_register_size(codec, reg); | 177 | size = adau1701_register_size(&client->dev, reg); |
149 | if (size == 0) | 178 | if (size == 0) |
150 | return -EINVAL; | 179 | return -EINVAL; |
151 | 180 | ||
152 | snd_soc_cache_write(codec, reg, value); | 181 | buf[0] = reg >> 8; |
153 | 182 | buf[1] = reg & 0xff; | |
154 | buf[0] = 0x08; | ||
155 | buf[1] = reg; | ||
156 | 183 | ||
157 | for (i = size + 1; i >= 2; --i) { | 184 | for (i = size + 1; i >= 2; --i) { |
158 | buf[i] = value; | 185 | buf[i] = value; |
159 | value >>= 8; | 186 | value >>= 8; |
160 | } | 187 | } |
161 | 188 | ||
162 | ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); | 189 | ret = i2c_master_send(client, buf, size + 2); |
163 | if (ret == size + 2) | 190 | if (ret == size + 2) |
164 | return 0; | 191 | return 0; |
165 | else if (ret < 0) | 192 | else if (ret < 0) |
@@ -168,21 +195,107 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, | |||
168 | return -EIO; | 195 | return -EIO; |
169 | } | 196 | } |
170 | 197 | ||
171 | static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) | 198 | static int adau1701_reg_read(void *context, unsigned int reg, |
199 | unsigned int *value) | ||
172 | { | 200 | { |
173 | unsigned int value; | 201 | int ret; |
174 | unsigned int ret; | 202 | unsigned int i; |
203 | unsigned int size; | ||
204 | uint8_t send_buf[2], recv_buf[3]; | ||
205 | struct i2c_client *client = context; | ||
206 | struct i2c_msg msgs[2]; | ||
207 | |||
208 | size = adau1701_register_size(&client->dev, reg); | ||
209 | if (size == 0) | ||
210 | return -EINVAL; | ||
211 | |||
212 | send_buf[0] = reg >> 8; | ||
213 | send_buf[1] = reg & 0xff; | ||
214 | |||
215 | msgs[0].addr = client->addr; | ||
216 | msgs[0].len = sizeof(send_buf); | ||
217 | msgs[0].buf = send_buf; | ||
218 | msgs[0].flags = 0; | ||
219 | |||
220 | msgs[1].addr = client->addr; | ||
221 | msgs[1].len = size; | ||
222 | msgs[1].buf = recv_buf; | ||
223 | msgs[1].flags = I2C_M_RD; | ||
175 | 224 | ||
176 | ret = snd_soc_cache_read(codec, reg, &value); | 225 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); |
177 | if (ret) | 226 | if (ret < 0) |
178 | return ret; | 227 | return ret; |
228 | else if (ret != ARRAY_SIZE(msgs)) | ||
229 | return -EIO; | ||
230 | |||
231 | *value = 0; | ||
232 | |||
233 | for (i = 0; i < size; i++) | ||
234 | *value |= recv_buf[i] << (i * 8); | ||
179 | 235 | ||
180 | return value; | 236 | return 0; |
181 | } | 237 | } |
182 | 238 | ||
183 | static int adau1701_load_firmware(struct snd_soc_codec *codec) | 239 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) |
184 | { | 240 | { |
185 | return process_sigma_firmware(codec->control_data, ADAU1701_FIRMWARE); | 241 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
242 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
243 | int ret; | ||
244 | |||
245 | if (clkdiv != ADAU1707_CLKDIV_UNSET && | ||
246 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && | ||
247 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { | ||
248 | switch (clkdiv) { | ||
249 | case 64: | ||
250 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | ||
251 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | ||
252 | break; | ||
253 | case 256: | ||
254 | gpio_set_value(adau1701->gpio_pll_mode[0], 0); | ||
255 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | ||
256 | break; | ||
257 | case 384: | ||
258 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | ||
259 | gpio_set_value(adau1701->gpio_pll_mode[1], 0); | ||
260 | break; | ||
261 | case 0: /* fallback */ | ||
262 | case 512: | ||
263 | gpio_set_value(adau1701->gpio_pll_mode[0], 1); | ||
264 | gpio_set_value(adau1701->gpio_pll_mode[1], 1); | ||
265 | break; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | adau1701->pll_clkdiv = clkdiv; | ||
270 | |||
271 | if (gpio_is_valid(adau1701->gpio_nreset)) { | ||
272 | gpio_set_value(adau1701->gpio_nreset, 0); | ||
273 | /* minimum reset time is 20ns */ | ||
274 | udelay(1); | ||
275 | gpio_set_value(adau1701->gpio_nreset, 1); | ||
276 | /* power-up time may be as long as 85ms */ | ||
277 | mdelay(85); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Postpone the firmware download to a point in time when we | ||
282 | * know the correct PLL setup | ||
283 | */ | ||
284 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { | ||
285 | ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); | ||
286 | if (ret) { | ||
287 | dev_warn(codec->dev, "Failed to load firmware\n"); | ||
288 | return ret; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); | ||
293 | regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); | ||
294 | |||
295 | regcache_mark_dirty(adau1701->regmap); | ||
296 | regcache_sync(adau1701->regmap); | ||
297 | |||
298 | return 0; | ||
186 | } | 299 | } |
187 | 300 | ||
188 | static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, | 301 | static int adau1701_set_capture_pcm_format(struct snd_soc_codec *codec, |
@@ -259,8 +372,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, | |||
259 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 372 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
260 | { | 373 | { |
261 | struct snd_soc_codec *codec = dai->codec; | 374 | struct snd_soc_codec *codec = dai->codec; |
375 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
376 | unsigned int clkdiv = adau1701->sysclk / params_rate(params); | ||
262 | snd_pcm_format_t format; | 377 | snd_pcm_format_t format; |
263 | unsigned int val; | 378 | unsigned int val; |
379 | int ret; | ||
380 | |||
381 | /* | ||
382 | * If the mclk/lrclk ratio changes, the chip needs updated PLL | ||
383 | * mode GPIO settings, and a full reset cycle, including a new | ||
384 | * firmware upload. | ||
385 | */ | ||
386 | if (clkdiv != adau1701->pll_clkdiv) { | ||
387 | ret = adau1701_reset(codec, clkdiv); | ||
388 | if (ret < 0) | ||
389 | return ret; | ||
390 | } | ||
264 | 391 | ||
265 | switch (params_rate(params)) { | 392 | switch (params_rate(params)) { |
266 | case 192000: | 393 | case 192000: |
@@ -352,8 +479,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
352 | 479 | ||
353 | adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | 480 | adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
354 | 481 | ||
355 | snd_soc_write(codec, ADAU1701_SERICTL, serictl); | 482 | regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl); |
356 | snd_soc_update_bits(codec, ADAU1701_SEROCTL, | 483 | regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, |
357 | ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); | 484 | ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); |
358 | 485 | ||
359 | return 0; | 486 | return 0; |
@@ -403,6 +530,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
403 | int source, unsigned int freq, int dir) | 530 | int source, unsigned int freq, int dir) |
404 | { | 531 | { |
405 | unsigned int val; | 532 | unsigned int val; |
533 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
406 | 534 | ||
407 | switch (clk_id) { | 535 | switch (clk_id) { |
408 | case ADAU1701_CLK_SRC_OSC: | 536 | case ADAU1701_CLK_SRC_OSC: |
@@ -416,6 +544,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
416 | } | 544 | } |
417 | 545 | ||
418 | snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); | 546 | snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); |
547 | adau1701->sysclk = freq; | ||
419 | 548 | ||
420 | return 0; | 549 | return 0; |
421 | } | 550 | } |
@@ -452,18 +581,47 @@ static struct snd_soc_dai_driver adau1701_dai = { | |||
452 | .symmetric_rates = 1, | 581 | .symmetric_rates = 1, |
453 | }; | 582 | }; |
454 | 583 | ||
584 | #ifdef CONFIG_OF | ||
585 | static const struct of_device_id adau1701_dt_ids[] = { | ||
586 | { .compatible = "adi,adau1701", }, | ||
587 | { } | ||
588 | }; | ||
589 | MODULE_DEVICE_TABLE(of, adau1701_dt_ids); | ||
590 | #endif | ||
591 | |||
455 | static int adau1701_probe(struct snd_soc_codec *codec) | 592 | static int adau1701_probe(struct snd_soc_codec *codec) |
456 | { | 593 | { |
457 | int ret; | 594 | int i, ret; |
595 | unsigned int val; | ||
596 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | ||
458 | 597 | ||
459 | codec->control_data = to_i2c_client(codec->dev); | 598 | codec->control_data = to_i2c_client(codec->dev); |
460 | 599 | ||
461 | ret = adau1701_load_firmware(codec); | 600 | /* |
462 | if (ret) | 601 | * Let the pll_clkdiv variable default to something that won't happen |
463 | dev_warn(codec->dev, "Failed to load firmware\n"); | 602 | * at runtime. That way, we can postpone the firmware download from |
603 | * adau1701_reset() to a point in time when we know the correct PLL | ||
604 | * mode parameters. | ||
605 | */ | ||
606 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; | ||
607 | |||
608 | /* initalize with pre-configured pll mode settings */ | ||
609 | ret = adau1701_reset(codec, adau1701->pll_clkdiv); | ||
610 | if (ret < 0) | ||
611 | return ret; | ||
612 | |||
613 | /* set up pin config */ | ||
614 | val = 0; | ||
615 | for (i = 0; i < 6; i++) | ||
616 | val |= adau1701->pin_config[i] << (i * 4); | ||
464 | 617 | ||
465 | snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); | 618 | regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val); |
466 | snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); | 619 | |
620 | val = 0; | ||
621 | for (i = 0; i < 6; i++) | ||
622 | val |= adau1701->pin_config[i + 6] << (i * 4); | ||
623 | |||
624 | regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); | ||
467 | 625 | ||
468 | return 0; | 626 | return 0; |
469 | } | 627 | } |
@@ -473,9 +631,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { | |||
473 | .set_bias_level = adau1701_set_bias_level, | 631 | .set_bias_level = adau1701_set_bias_level, |
474 | .idle_bias_off = true, | 632 | .idle_bias_off = true, |
475 | 633 | ||
476 | .reg_cache_size = ADAU1701_NUM_REGS, | ||
477 | .reg_word_size = sizeof(u16), | ||
478 | |||
479 | .controls = adau1701_controls, | 634 | .controls = adau1701_controls, |
480 | .num_controls = ARRAY_SIZE(adau1701_controls), | 635 | .num_controls = ARRAY_SIZE(adau1701_controls), |
481 | .dapm_widgets = adau1701_dapm_widgets, | 636 | .dapm_widgets = adau1701_dapm_widgets, |
@@ -483,22 +638,86 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { | |||
483 | .dapm_routes = adau1701_dapm_routes, | 638 | .dapm_routes = adau1701_dapm_routes, |
484 | .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), | 639 | .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), |
485 | 640 | ||
486 | .write = adau1701_write, | ||
487 | .read = adau1701_read, | ||
488 | |||
489 | .set_sysclk = adau1701_set_sysclk, | 641 | .set_sysclk = adau1701_set_sysclk, |
490 | }; | 642 | }; |
491 | 643 | ||
644 | static const struct regmap_config adau1701_regmap = { | ||
645 | .reg_bits = 16, | ||
646 | .val_bits = 32, | ||
647 | .max_register = ADAU1701_MAX_REGISTER, | ||
648 | .cache_type = REGCACHE_RBTREE, | ||
649 | .volatile_reg = adau1701_volatile_reg, | ||
650 | .reg_write = adau1701_reg_write, | ||
651 | .reg_read = adau1701_reg_read, | ||
652 | }; | ||
653 | |||
492 | static int adau1701_i2c_probe(struct i2c_client *client, | 654 | static int adau1701_i2c_probe(struct i2c_client *client, |
493 | const struct i2c_device_id *id) | 655 | const struct i2c_device_id *id) |
494 | { | 656 | { |
495 | struct adau1701 *adau1701; | 657 | struct adau1701 *adau1701; |
658 | struct device *dev = &client->dev; | ||
659 | int gpio_nreset = -EINVAL; | ||
660 | int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; | ||
496 | int ret; | 661 | int ret; |
497 | 662 | ||
498 | adau1701 = devm_kzalloc(&client->dev, sizeof(*adau1701), GFP_KERNEL); | 663 | adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); |
499 | if (!adau1701) | 664 | if (!adau1701) |
500 | return -ENOMEM; | 665 | return -ENOMEM; |
501 | 666 | ||
667 | adau1701->regmap = devm_regmap_init(dev, NULL, client, | ||
668 | &adau1701_regmap); | ||
669 | if (IS_ERR(adau1701->regmap)) | ||
670 | return PTR_ERR(adau1701->regmap); | ||
671 | |||
672 | if (dev->of_node) { | ||
673 | gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); | ||
674 | if (gpio_nreset < 0 && gpio_nreset != -ENOENT) | ||
675 | return gpio_nreset; | ||
676 | |||
677 | gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, | ||
678 | "adi,pll-mode-gpios", 0); | ||
679 | if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) | ||
680 | return gpio_pll_mode[0]; | ||
681 | |||
682 | gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, | ||
683 | "adi,pll-mode-gpios", 1); | ||
684 | if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) | ||
685 | return gpio_pll_mode[1]; | ||
686 | |||
687 | of_property_read_u32(dev->of_node, "adi,pll-clkdiv", | ||
688 | &adau1701->pll_clkdiv); | ||
689 | |||
690 | of_property_read_u8_array(dev->of_node, "adi,pin-config", | ||
691 | adau1701->pin_config, | ||
692 | ARRAY_SIZE(adau1701->pin_config)); | ||
693 | } | ||
694 | |||
695 | if (gpio_is_valid(gpio_nreset)) { | ||
696 | ret = devm_gpio_request_one(dev, gpio_nreset, GPIOF_OUT_INIT_LOW, | ||
697 | "ADAU1701 Reset"); | ||
698 | if (ret < 0) | ||
699 | return ret; | ||
700 | } | ||
701 | |||
702 | if (gpio_is_valid(gpio_pll_mode[0]) && | ||
703 | gpio_is_valid(gpio_pll_mode[1])) { | ||
704 | ret = devm_gpio_request_one(dev, gpio_pll_mode[0], | ||
705 | GPIOF_OUT_INIT_LOW, | ||
706 | "ADAU1701 PLL mode 0"); | ||
707 | if (ret < 0) | ||
708 | return ret; | ||
709 | |||
710 | ret = devm_gpio_request_one(dev, gpio_pll_mode[1], | ||
711 | GPIOF_OUT_INIT_LOW, | ||
712 | "ADAU1701 PLL mode 1"); | ||
713 | if (ret < 0) | ||
714 | return ret; | ||
715 | } | ||
716 | |||
717 | adau1701->gpio_nreset = gpio_nreset; | ||
718 | adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; | ||
719 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; | ||
720 | |||
502 | i2c_set_clientdata(client, adau1701); | 721 | i2c_set_clientdata(client, adau1701); |
503 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | 722 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, |
504 | &adau1701_dai, 1); | 723 | &adau1701_dai, 1); |
@@ -521,6 +740,7 @@ static struct i2c_driver adau1701_i2c_driver = { | |||
521 | .driver = { | 740 | .driver = { |
522 | .name = "adau1701", | 741 | .name = "adau1701", |
523 | .owner = THIS_MODULE, | 742 | .owner = THIS_MODULE, |
743 | .of_match_table = of_match_ptr(adau1701_dt_ids), | ||
524 | }, | 744 | }, |
525 | .probe = adau1701_i2c_probe, | 745 | .probe = adau1701_i2c_probe, |
526 | .remove = adau1701_i2c_remove, | 746 | .remove = adau1701_i2c_remove, |
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 2eda85ba79ac..a5455c1aea42 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
@@ -28,8 +28,6 @@ | |||
28 | 28 | ||
29 | #include "stac9766.h" | 29 | #include "stac9766.h" |
30 | 30 | ||
31 | #define STAC9766_VERSION "0.10" | ||
32 | |||
33 | /* | 31 | /* |
34 | * STAC9766 register cache | 32 | * STAC9766 register cache |
35 | */ | 33 | */ |
@@ -145,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
145 | 143 | ||
146 | if (reg > AC97_STAC_PAGE0) { | 144 | if (reg > AC97_STAC_PAGE0) { |
147 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 145 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
148 | soc_ac97_ops.write(codec->ac97, reg, val); | 146 | soc_ac97_ops->write(codec->ac97, reg, val); |
149 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 147 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
150 | return 0; | 148 | return 0; |
151 | } | 149 | } |
152 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) | 150 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) |
153 | return -EIO; | 151 | return -EIO; |
154 | 152 | ||
155 | soc_ac97_ops.write(codec->ac97, reg, val); | 153 | soc_ac97_ops->write(codec->ac97, reg, val); |
156 | cache[reg / 2] = val; | 154 | cache[reg / 2] = val; |
157 | return 0; | 155 | return 0; |
158 | } | 156 | } |
@@ -164,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | |||
164 | 162 | ||
165 | if (reg > AC97_STAC_PAGE0) { | 163 | if (reg > AC97_STAC_PAGE0) { |
166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 164 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
167 | val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0); | 165 | val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0); |
168 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
169 | return val; | 167 | return val; |
170 | } | 168 | } |
@@ -175,7 +173,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | |||
175 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || | 173 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || |
176 | reg == AC97_VENDOR_ID2) { | 174 | reg == AC97_VENDOR_ID2) { |
177 | 175 | ||
178 | val = soc_ac97_ops.read(codec->ac97, reg); | 176 | val = soc_ac97_ops->read(codec->ac97, reg); |
179 | return val; | 177 | return val; |
180 | } | 178 | } |
181 | return cache[reg / 2]; | 179 | return cache[reg / 2]; |
@@ -242,15 +240,15 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, | |||
242 | 240 | ||
243 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) | 241 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) |
244 | { | 242 | { |
245 | if (try_warm && soc_ac97_ops.warm_reset) { | 243 | if (try_warm && soc_ac97_ops->warm_reset) { |
246 | soc_ac97_ops.warm_reset(codec->ac97); | 244 | soc_ac97_ops->warm_reset(codec->ac97); |
247 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) | 245 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) |
248 | return 1; | 246 | return 1; |
249 | } | 247 | } |
250 | 248 | ||
251 | soc_ac97_ops.reset(codec->ac97); | 249 | soc_ac97_ops->reset(codec->ac97); |
252 | if (soc_ac97_ops.warm_reset) | 250 | if (soc_ac97_ops->warm_reset) |
253 | soc_ac97_ops.warm_reset(codec->ac97); | 251 | soc_ac97_ops->warm_reset(codec->ac97); |
254 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) | 252 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) |
255 | return -EIO; | 253 | return -EIO; |
256 | return 0; | 254 | return 0; |
@@ -274,7 +272,7 @@ reset: | |||
274 | return -EIO; | 272 | return -EIO; |
275 | } | 273 | } |
276 | codec->ac97->bus->ops->warm_reset(codec->ac97); | 274 | codec->ac97->bus->ops->warm_reset(codec->ac97); |
277 | id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2); | 275 | id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2); |
278 | if (id != 0x4c13) { | 276 | if (id != 0x4c13) { |
279 | stac9766_reset(codec, 0); | 277 | stac9766_reset(codec, 0); |
280 | reset++; | 278 | reset++; |
@@ -338,9 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) | |||
338 | { | 336 | { |
339 | int ret = 0; | 337 | int ret = 0; |
340 | 338 | ||
341 | printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); | 339 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); |
342 | |||
343 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
344 | if (ret < 0) | 340 | if (ret < 0) |
345 | goto codec_err; | 341 | goto codec_err; |
346 | 342 | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 1514bf845e4b..e5b926883131 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -128,10 +128,8 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | |||
128 | }; | 128 | }; |
129 | 129 | ||
130 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 130 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
131 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 131 | SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \ |
132 | .info = snd_soc_info_volsw, \ | 132 | snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x) |
133 | .get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw_aic3x, \ | ||
134 | .private_value = SOC_SINGLE_VALUE(reg, shift, mask, invert) } | ||
135 | 133 | ||
136 | /* | 134 | /* |
137 | * All input lines are connected when !0xf and disconnected with 0xf bit field, | 135 | * All input lines are connected when !0xf and disconnected with 0xf bit field, |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index af6d227e67be..d2a092850283 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -143,13 +143,8 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | |||
143 | } | 143 | } |
144 | 144 | ||
145 | #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \ | 145 | #define WM8400_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert, tlv_array) \ |
146 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 146 | SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \ |
147 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 147 | snd_soc_get_volsw, wm8400_outpga_put_volsw_vu, tlv_array) |
148 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
149 | .tlv.p = (tlv_array), \ | ||
150 | .info = snd_soc_info_volsw, \ | ||
151 | .get = snd_soc_get_volsw, .put = wm8400_outpga_put_volsw_vu, \ | ||
152 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
153 | 148 | ||
154 | 149 | ||
155 | static const char *wm8400_digital_sidetone[] = | 150 | static const char *wm8400_digital_sidetone[] = |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 9d88437cdcd1..fa24cedee687 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -403,10 +403,8 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, | |||
403 | } | 403 | } |
404 | 404 | ||
405 | #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \ | 405 | #define SOC_DAPM_SINGLE_W(xname, reg, shift, max, invert) \ |
406 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 406 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ |
407 | .info = snd_soc_info_volsw, \ | 407 | snd_soc_dapm_get_volsw, wm8903_class_w_put) |
408 | .get = snd_soc_dapm_get_volsw, .put = wm8903_class_w_put, \ | ||
409 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
410 | 408 | ||
411 | 409 | ||
412 | static int wm8903_deemph[] = { 0, 32000, 44100, 48000 }; | 410 | static int wm8903_deemph[] = { 0, 32000, 44100, 48000 }; |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 3ff195c541db..4c9fb142cb2d 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -603,13 +603,8 @@ SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, | |||
603 | 603 | ||
604 | SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), | 604 | SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), |
605 | SOC_ENUM("High Pass Filter Mode", hpf_mode), | 605 | SOC_ENUM("High Pass Filter Mode", hpf_mode), |
606 | 606 | SOC_SINGLE_EXT("ADC 128x OSR Switch", WM8904_ANALOGUE_ADC_0, 0, 1, 0, | |
607 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 607 | snd_soc_get_volsw, wm8904_adc_osr_put), |
608 | .name = "ADC 128x OSR Switch", | ||
609 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, | ||
610 | .put = wm8904_adc_osr_put, | ||
611 | .private_value = SOC_SINGLE_VALUE(WM8904_ANALOGUE_ADC_0, 0, 1, 0), | ||
612 | }, | ||
613 | }; | 608 | }; |
614 | 609 | ||
615 | static const char *drc_path_text[] = { | 610 | static const char *drc_path_text[] = { |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 837978e16e9d..253c88bb7a4c 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -151,14 +151,9 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | |||
151 | } | 151 | } |
152 | 152 | ||
153 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | 153 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ |
154 | tlv_array) {\ | 154 | tlv_array) \ |
155 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 155 | SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \ |
156 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 156 | snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array) |
157 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
158 | .tlv.p = (tlv_array), \ | ||
159 | .info = snd_soc_info_volsw, \ | ||
160 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
161 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
162 | 157 | ||
163 | 158 | ||
164 | static const char *wm8990_digital_sidetone[] = | 159 | static const char *wm8990_digital_sidetone[] = |
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h index 8a942efd18a5..07707d8d7e20 100644 --- a/sound/soc/codecs/wm8991.h +++ b/sound/soc/codecs/wm8991.h | |||
@@ -822,12 +822,7 @@ | |||
822 | 822 | ||
823 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | 823 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ |
824 | tlv_array) \ | 824 | tlv_array) \ |
825 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 825 | SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \ |
826 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | 826 | snd_soc_get_volsw, wm899x_outpga_put_volsw_vu, tlv_array) |
827 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
828 | .tlv.p = (tlv_array), \ | ||
829 | .info = snd_soc_info_volsw, \ | ||
830 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
831 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
832 | 827 | ||
833 | #endif /* _WM8991_H */ | 828 | #endif /* _WM8991_H */ |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 29e95f93d482..9e13edd81292 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -289,10 +289,8 @@ static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); | |||
289 | static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0); | 289 | static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0); |
290 | 290 | ||
291 | #define WM8994_DRC_SWITCH(xname, reg, shift) \ | 291 | #define WM8994_DRC_SWITCH(xname, reg, shift) \ |
292 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 292 | SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \ |
293 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | 293 | snd_soc_get_volsw, wm8994_put_drc_sw) |
294 | .put = wm8994_put_drc_sw, \ | ||
295 | .private_value = SOC_SINGLE_VALUE(reg, shift, 1, 0) } | ||
296 | 294 | ||
297 | static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, | 295 | static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol, |
298 | struct snd_ctl_elem_value *ucontrol) | 296 | struct snd_ctl_elem_value *ucontrol) |
@@ -1432,10 +1430,8 @@ SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, | |||
1432 | }; | 1430 | }; |
1433 | 1431 | ||
1434 | #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ | 1432 | #define WM8994_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ |
1435 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 1433 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ |
1436 | .info = snd_soc_info_volsw, \ | 1434 | snd_soc_get_volsw, wm8994_put_class_w) |
1437 | .get = snd_soc_dapm_get_volsw, .put = wm8994_put_class_w, \ | ||
1438 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
1439 | 1435 | ||
1440 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, | 1436 | static int wm8994_put_class_w(struct snd_kcontrol *kcontrol, |
1441 | struct snd_ctl_elem_value *ucontrol) | 1437 | struct snd_ctl_elem_value *ucontrol) |
diff --git a/sound/soc/codecs/wm8995.h b/sound/soc/codecs/wm8995.h index 5642121c4977..508ad27fe2bb 100644 --- a/sound/soc/codecs/wm8995.h +++ b/sound/soc/codecs/wm8995.h | |||
@@ -4237,11 +4237,8 @@ | |||
4237 | #define WM8995_SPK2_MUTE_SEQ1_WIDTH 8 /* SPK2_MUTE_SEQ1 - [7:0] */ | 4237 | #define WM8995_SPK2_MUTE_SEQ1_WIDTH 8 /* SPK2_MUTE_SEQ1 - [7:0] */ |
4238 | 4238 | ||
4239 | #define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ | 4239 | #define WM8995_CLASS_W_SWITCH(xname, reg, shift, max, invert) \ |
4240 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 4240 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ |
4241 | .info = snd_soc_info_volsw, \ | 4241 | snd_soc_dapm_get_volsw, wm8995_put_class_w) |
4242 | .get = snd_soc_dapm_get_volsw, .put = wm8995_put_class_w, \ | ||
4243 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) \ | ||
4244 | } | ||
4245 | 4242 | ||
4246 | struct wm8995_reg_access { | 4243 | struct wm8995_reg_access { |
4247 | u16 read; | 4244 | u16 read; |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 05b1f346695b..70ce6793c5bd 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
@@ -209,7 +209,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | |||
209 | case AC97_RESET: | 209 | case AC97_RESET: |
210 | case AC97_VENDOR_ID1: | 210 | case AC97_VENDOR_ID1: |
211 | case AC97_VENDOR_ID2: | 211 | case AC97_VENDOR_ID2: |
212 | return soc_ac97_ops.read(codec->ac97, reg); | 212 | return soc_ac97_ops->read(codec->ac97, reg); |
213 | default: | 213 | default: |
214 | reg = reg >> 1; | 214 | reg = reg >> 1; |
215 | 215 | ||
@@ -225,7 +225,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
225 | { | 225 | { |
226 | u16 *cache = codec->reg_cache; | 226 | u16 *cache = codec->reg_cache; |
227 | 227 | ||
228 | soc_ac97_ops.write(codec->ac97, reg, val); | 228 | soc_ac97_ops->write(codec->ac97, reg, val); |
229 | reg = reg >> 1; | 229 | reg = reg >> 1; |
230 | if (reg < (ARRAY_SIZE(wm9705_reg))) | 230 | if (reg < (ARRAY_SIZE(wm9705_reg))) |
231 | cache[reg] = val; | 231 | cache[reg] = val; |
@@ -294,8 +294,8 @@ static struct snd_soc_dai_driver wm9705_dai[] = { | |||
294 | 294 | ||
295 | static int wm9705_reset(struct snd_soc_codec *codec) | 295 | static int wm9705_reset(struct snd_soc_codec *codec) |
296 | { | 296 | { |
297 | if (soc_ac97_ops.reset) { | 297 | if (soc_ac97_ops->reset) { |
298 | soc_ac97_ops.reset(codec->ac97); | 298 | soc_ac97_ops->reset(codec->ac97); |
299 | if (ac97_read(codec, 0) == wm9705_reg[0]) | 299 | if (ac97_read(codec, 0) == wm9705_reg[0]) |
300 | return 0; /* Success */ | 300 | return 0; /* Success */ |
301 | } | 301 | } |
@@ -306,7 +306,7 @@ static int wm9705_reset(struct snd_soc_codec *codec) | |||
306 | #ifdef CONFIG_PM | 306 | #ifdef CONFIG_PM |
307 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) | 307 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) |
308 | { | 308 | { |
309 | soc_ac97_ops.write(codec->ac97, AC97_POWERDOWN, 0xffff); | 309 | soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff); |
310 | 310 | ||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
@@ -323,7 +323,7 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) | |||
323 | } | 323 | } |
324 | 324 | ||
325 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { | 325 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { |
326 | soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); | 326 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); |
327 | } | 327 | } |
328 | 328 | ||
329 | return 0; | 329 | return 0; |
@@ -337,9 +337,7 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) | |||
337 | { | 337 | { |
338 | int ret = 0; | 338 | int ret = 0; |
339 | 339 | ||
340 | printk(KERN_INFO "WM9705 SoC Audio Codec\n"); | 340 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); |
341 | |||
342 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | ||
343 | if (ret < 0) { | 341 | if (ret < 0) { |
344 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); | 342 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); |
345 | return ret; | 343 | return ret; |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 8e9a6a3eeb1a..c5eb746087b4 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -455,7 +455,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
455 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 455 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
456 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 456 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
457 | reg == AC97_REC_GAIN) | 457 | reg == AC97_REC_GAIN) |
458 | return soc_ac97_ops.read(codec->ac97, reg); | 458 | return soc_ac97_ops->read(codec->ac97, reg); |
459 | else { | 459 | else { |
460 | reg = reg >> 1; | 460 | reg = reg >> 1; |
461 | 461 | ||
@@ -472,7 +472,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
472 | u16 *cache = codec->reg_cache; | 472 | u16 *cache = codec->reg_cache; |
473 | 473 | ||
474 | if (reg < 0x7c) | 474 | if (reg < 0x7c) |
475 | soc_ac97_ops.write(codec->ac97, reg, val); | 475 | soc_ac97_ops->write(codec->ac97, reg, val); |
476 | reg = reg >> 1; | 476 | reg = reg >> 1; |
477 | if (reg < (ARRAY_SIZE(wm9712_reg))) | 477 | if (reg < (ARRAY_SIZE(wm9712_reg))) |
478 | cache[reg] = val; | 478 | cache[reg] = val; |
@@ -581,15 +581,15 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, | |||
581 | 581 | ||
582 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | 582 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) |
583 | { | 583 | { |
584 | if (try_warm && soc_ac97_ops.warm_reset) { | 584 | if (try_warm && soc_ac97_ops->warm_reset) { |
585 | soc_ac97_ops.warm_reset(codec->ac97); | 585 | soc_ac97_ops->warm_reset(codec->ac97); |
586 | if (ac97_read(codec, 0) == wm9712_reg[0]) | 586 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
587 | return 1; | 587 | return 1; |
588 | } | 588 | } |
589 | 589 | ||
590 | soc_ac97_ops.reset(codec->ac97); | 590 | soc_ac97_ops->reset(codec->ac97); |
591 | if (soc_ac97_ops.warm_reset) | 591 | if (soc_ac97_ops->warm_reset) |
592 | soc_ac97_ops.warm_reset(codec->ac97); | 592 | soc_ac97_ops->warm_reset(codec->ac97); |
593 | if (ac97_read(codec, 0) != wm9712_reg[0]) | 593 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
594 | goto err; | 594 | goto err; |
595 | return 0; | 595 | return 0; |
@@ -624,7 +624,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
624 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || | 624 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || |
625 | (i > 0x58 && i != 0x5c)) | 625 | (i > 0x58 && i != 0x5c)) |
626 | continue; | 626 | continue; |
627 | soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); | 627 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); |
628 | } | 628 | } |
629 | } | 629 | } |
630 | 630 | ||
@@ -635,7 +635,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) | |||
635 | { | 635 | { |
636 | int ret = 0; | 636 | int ret = 0; |
637 | 637 | ||
638 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | 638 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); |
639 | if (ret < 0) { | 639 | if (ret < 0) { |
640 | printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); | 640 | printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); |
641 | return ret; | 641 | return ret; |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index f7afa68d8c7f..a53e175c015a 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -652,7 +652,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
652 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 652 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
653 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 653 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
654 | reg == AC97_CD) | 654 | reg == AC97_CD) |
655 | return soc_ac97_ops.read(codec->ac97, reg); | 655 | return soc_ac97_ops->read(codec->ac97, reg); |
656 | else { | 656 | else { |
657 | reg = reg >> 1; | 657 | reg = reg >> 1; |
658 | 658 | ||
@@ -668,7 +668,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
668 | { | 668 | { |
669 | u16 *cache = codec->reg_cache; | 669 | u16 *cache = codec->reg_cache; |
670 | if (reg < 0x7c) | 670 | if (reg < 0x7c) |
671 | soc_ac97_ops.write(codec->ac97, reg, val); | 671 | soc_ac97_ops->write(codec->ac97, reg, val); |
672 | reg = reg >> 1; | 672 | reg = reg >> 1; |
673 | if (reg < (ARRAY_SIZE(wm9713_reg))) | 673 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
674 | cache[reg] = val; | 674 | cache[reg] = val; |
@@ -1095,15 +1095,15 @@ static struct snd_soc_dai_driver wm9713_dai[] = { | |||
1095 | 1095 | ||
1096 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | 1096 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) |
1097 | { | 1097 | { |
1098 | if (try_warm && soc_ac97_ops.warm_reset) { | 1098 | if (try_warm && soc_ac97_ops->warm_reset) { |
1099 | soc_ac97_ops.warm_reset(codec->ac97); | 1099 | soc_ac97_ops->warm_reset(codec->ac97); |
1100 | if (ac97_read(codec, 0) == wm9713_reg[0]) | 1100 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1101 | return 1; | 1101 | return 1; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | soc_ac97_ops.reset(codec->ac97); | 1104 | soc_ac97_ops->reset(codec->ac97); |
1105 | if (soc_ac97_ops.warm_reset) | 1105 | if (soc_ac97_ops->warm_reset) |
1106 | soc_ac97_ops.warm_reset(codec->ac97); | 1106 | soc_ac97_ops->warm_reset(codec->ac97); |
1107 | if (ac97_read(codec, 0) != wm9713_reg[0]) | 1107 | if (ac97_read(codec, 0) != wm9713_reg[0]) |
1108 | return -EIO; | 1108 | return -EIO; |
1109 | return 0; | 1109 | return 0; |
@@ -1180,7 +1180,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1180 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || | 1180 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || |
1181 | i == AC97_EXTENDED_MSTATUS || i > 0x66) | 1181 | i == AC97_EXTENDED_MSTATUS || i > 0x66) |
1182 | continue; | 1182 | continue; |
1183 | soc_ac97_ops.write(codec->ac97, i, cache[i>>1]); | 1183 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); |
1184 | } | 1184 | } |
1185 | } | 1185 | } |
1186 | 1186 | ||
@@ -1197,7 +1197,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) | |||
1197 | return -ENOMEM; | 1197 | return -ENOMEM; |
1198 | snd_soc_codec_set_drvdata(codec, wm9713); | 1198 | snd_soc_codec_set_drvdata(codec, wm9713); |
1199 | 1199 | ||
1200 | ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); | 1200 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); |
1201 | if (ret < 0) | 1201 | if (ret < 0) |
1202 | goto codec_err; | 1202 | goto codec_err; |
1203 | 1203 | ||
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 3470b649c0b2..ddba3fea39eb 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
22 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/workqueue.h> | ||
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
26 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
@@ -215,6 +216,36 @@ static struct { | |||
215 | [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, | 216 | [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, |
216 | }; | 217 | }; |
217 | 218 | ||
219 | struct wm_coeff_ctl_ops { | ||
220 | int (*xget)(struct snd_kcontrol *kcontrol, | ||
221 | struct snd_ctl_elem_value *ucontrol); | ||
222 | int (*xput)(struct snd_kcontrol *kcontrol, | ||
223 | struct snd_ctl_elem_value *ucontrol); | ||
224 | int (*xinfo)(struct snd_kcontrol *kcontrol, | ||
225 | struct snd_ctl_elem_info *uinfo); | ||
226 | }; | ||
227 | |||
228 | struct wm_coeff { | ||
229 | struct device *dev; | ||
230 | struct list_head ctl_list; | ||
231 | struct regmap *regmap; | ||
232 | }; | ||
233 | |||
234 | struct wm_coeff_ctl { | ||
235 | const char *name; | ||
236 | struct snd_card *card; | ||
237 | struct wm_adsp_alg_region region; | ||
238 | struct wm_coeff_ctl_ops ops; | ||
239 | struct wm_adsp *adsp; | ||
240 | void *private; | ||
241 | unsigned int enabled:1; | ||
242 | struct list_head list; | ||
243 | void *cache; | ||
244 | size_t len; | ||
245 | unsigned int set:1; | ||
246 | struct snd_kcontrol *kcontrol; | ||
247 | }; | ||
248 | |||
218 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, | 249 | static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, |
219 | struct snd_ctl_elem_value *ucontrol) | 250 | struct snd_ctl_elem_value *ucontrol) |
220 | { | 251 | { |
@@ -334,6 +365,181 @@ static unsigned int wm_adsp_region_to_reg(struct wm_adsp_region const *region, | |||
334 | } | 365 | } |
335 | } | 366 | } |
336 | 367 | ||
368 | static int wm_coeff_info(struct snd_kcontrol *kcontrol, | ||
369 | struct snd_ctl_elem_info *uinfo) | ||
370 | { | ||
371 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | ||
372 | |||
373 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
374 | uinfo->count = ctl->len; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int wm_coeff_write_control(struct snd_kcontrol *kcontrol, | ||
379 | const void *buf, size_t len) | ||
380 | { | ||
381 | struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol); | ||
382 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | ||
383 | struct wm_adsp_alg_region *region = &ctl->region; | ||
384 | const struct wm_adsp_region *mem; | ||
385 | struct wm_adsp *adsp = ctl->adsp; | ||
386 | void *scratch; | ||
387 | int ret; | ||
388 | unsigned int reg; | ||
389 | |||
390 | mem = wm_adsp_find_region(adsp, region->type); | ||
391 | if (!mem) { | ||
392 | adsp_err(adsp, "No base for region %x\n", | ||
393 | region->type); | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | reg = ctl->region.base; | ||
398 | reg = wm_adsp_region_to_reg(mem, reg); | ||
399 | |||
400 | scratch = kmemdup(buf, ctl->len, GFP_KERNEL | GFP_DMA); | ||
401 | if (!scratch) | ||
402 | return -ENOMEM; | ||
403 | |||
404 | ret = regmap_raw_write(wm_coeff->regmap, reg, scratch, | ||
405 | ctl->len); | ||
406 | if (ret) { | ||
407 | adsp_err(adsp, "Failed to write %zu bytes to %x\n", | ||
408 | ctl->len, reg); | ||
409 | kfree(scratch); | ||
410 | return ret; | ||
411 | } | ||
412 | |||
413 | kfree(scratch); | ||
414 | |||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int wm_coeff_put(struct snd_kcontrol *kcontrol, | ||
419 | struct snd_ctl_elem_value *ucontrol) | ||
420 | { | ||
421 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | ||
422 | char *p = ucontrol->value.bytes.data; | ||
423 | |||
424 | memcpy(ctl->cache, p, ctl->len); | ||
425 | |||
426 | if (!ctl->enabled) { | ||
427 | ctl->set = 1; | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | return wm_coeff_write_control(kcontrol, p, ctl->len); | ||
432 | } | ||
433 | |||
434 | static int wm_coeff_read_control(struct snd_kcontrol *kcontrol, | ||
435 | void *buf, size_t len) | ||
436 | { | ||
437 | struct wm_coeff *wm_coeff= snd_kcontrol_chip(kcontrol); | ||
438 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | ||
439 | struct wm_adsp_alg_region *region = &ctl->region; | ||
440 | const struct wm_adsp_region *mem; | ||
441 | struct wm_adsp *adsp = ctl->adsp; | ||
442 | void *scratch; | ||
443 | int ret; | ||
444 | unsigned int reg; | ||
445 | |||
446 | mem = wm_adsp_find_region(adsp, region->type); | ||
447 | if (!mem) { | ||
448 | adsp_err(adsp, "No base for region %x\n", | ||
449 | region->type); | ||
450 | return -EINVAL; | ||
451 | } | ||
452 | |||
453 | reg = ctl->region.base; | ||
454 | reg = wm_adsp_region_to_reg(mem, reg); | ||
455 | |||
456 | scratch = kmalloc(ctl->len, GFP_KERNEL | GFP_DMA); | ||
457 | if (!scratch) | ||
458 | return -ENOMEM; | ||
459 | |||
460 | ret = regmap_raw_read(wm_coeff->regmap, reg, scratch, ctl->len); | ||
461 | if (ret) { | ||
462 | adsp_err(adsp, "Failed to read %zu bytes from %x\n", | ||
463 | ctl->len, reg); | ||
464 | kfree(scratch); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | memcpy(buf, scratch, ctl->len); | ||
469 | kfree(scratch); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int wm_coeff_get(struct snd_kcontrol *kcontrol, | ||
475 | struct snd_ctl_elem_value *ucontrol) | ||
476 | { | ||
477 | struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; | ||
478 | char *p = ucontrol->value.bytes.data; | ||
479 | |||
480 | memcpy(p, ctl->cache, ctl->len); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int wm_coeff_add_kcontrol(struct wm_coeff *wm_coeff, | ||
485 | struct wm_coeff_ctl *ctl, | ||
486 | const struct snd_kcontrol_new *kctl) | ||
487 | { | ||
488 | int ret; | ||
489 | struct snd_kcontrol *kcontrol; | ||
490 | |||
491 | kcontrol = snd_ctl_new1(kctl, wm_coeff); | ||
492 | ret = snd_ctl_add(ctl->card, kcontrol); | ||
493 | if (ret < 0) { | ||
494 | dev_err(wm_coeff->dev, "Failed to add %s: %d\n", | ||
495 | kctl->name, ret); | ||
496 | return ret; | ||
497 | } | ||
498 | ctl->kcontrol = kcontrol; | ||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | struct wmfw_ctl_work { | ||
503 | struct wm_coeff *wm_coeff; | ||
504 | struct wm_coeff_ctl *ctl; | ||
505 | struct work_struct work; | ||
506 | }; | ||
507 | |||
508 | static int wmfw_add_ctl(struct wm_coeff *wm_coeff, | ||
509 | struct wm_coeff_ctl *ctl) | ||
510 | { | ||
511 | struct snd_kcontrol_new *kcontrol; | ||
512 | int ret; | ||
513 | |||
514 | if (!wm_coeff || !ctl || !ctl->name || !ctl->card) | ||
515 | return -EINVAL; | ||
516 | |||
517 | kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); | ||
518 | if (!kcontrol) | ||
519 | return -ENOMEM; | ||
520 | kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
521 | |||
522 | kcontrol->name = ctl->name; | ||
523 | kcontrol->info = wm_coeff_info; | ||
524 | kcontrol->get = wm_coeff_get; | ||
525 | kcontrol->put = wm_coeff_put; | ||
526 | kcontrol->private_value = (unsigned long)ctl; | ||
527 | |||
528 | ret = wm_coeff_add_kcontrol(wm_coeff, | ||
529 | ctl, kcontrol); | ||
530 | if (ret < 0) | ||
531 | goto err_kcontrol; | ||
532 | |||
533 | kfree(kcontrol); | ||
534 | |||
535 | list_add(&ctl->list, &wm_coeff->ctl_list); | ||
536 | return 0; | ||
537 | |||
538 | err_kcontrol: | ||
539 | kfree(kcontrol); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
337 | static int wm_adsp_load(struct wm_adsp *dsp) | 543 | static int wm_adsp_load(struct wm_adsp *dsp) |
338 | { | 544 | { |
339 | LIST_HEAD(buf_list); | 545 | LIST_HEAD(buf_list); |
@@ -547,7 +753,157 @@ out: | |||
547 | return ret; | 753 | return ret; |
548 | } | 754 | } |
549 | 755 | ||
550 | static int wm_adsp_setup_algs(struct wm_adsp *dsp) | 756 | static int wm_coeff_init_control_caches(struct wm_coeff *wm_coeff) |
757 | { | ||
758 | struct wm_coeff_ctl *ctl; | ||
759 | int ret; | ||
760 | |||
761 | list_for_each_entry(ctl, &wm_coeff->ctl_list, | ||
762 | list) { | ||
763 | if (!ctl->enabled || ctl->set) | ||
764 | continue; | ||
765 | ret = wm_coeff_read_control(ctl->kcontrol, | ||
766 | ctl->cache, | ||
767 | ctl->len); | ||
768 | if (ret < 0) | ||
769 | return ret; | ||
770 | } | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int wm_coeff_sync_controls(struct wm_coeff *wm_coeff) | ||
776 | { | ||
777 | struct wm_coeff_ctl *ctl; | ||
778 | int ret; | ||
779 | |||
780 | list_for_each_entry(ctl, &wm_coeff->ctl_list, | ||
781 | list) { | ||
782 | if (!ctl->enabled) | ||
783 | continue; | ||
784 | if (ctl->set) { | ||
785 | ret = wm_coeff_write_control(ctl->kcontrol, | ||
786 | ctl->cache, | ||
787 | ctl->len); | ||
788 | if (ret < 0) | ||
789 | return ret; | ||
790 | } | ||
791 | } | ||
792 | |||
793 | return 0; | ||
794 | } | ||
795 | |||
796 | static void wm_adsp_ctl_work(struct work_struct *work) | ||
797 | { | ||
798 | struct wmfw_ctl_work *ctl_work = container_of(work, | ||
799 | struct wmfw_ctl_work, | ||
800 | work); | ||
801 | |||
802 | wmfw_add_ctl(ctl_work->wm_coeff, ctl_work->ctl); | ||
803 | kfree(ctl_work); | ||
804 | } | ||
805 | |||
806 | static int wm_adsp_create_control(struct snd_soc_codec *codec, | ||
807 | const struct wm_adsp_alg_region *region) | ||
808 | |||
809 | { | ||
810 | struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); | ||
811 | struct wm_coeff_ctl *ctl; | ||
812 | struct wmfw_ctl_work *ctl_work; | ||
813 | char *name; | ||
814 | char *region_name; | ||
815 | int ret; | ||
816 | |||
817 | name = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
818 | if (!name) | ||
819 | return -ENOMEM; | ||
820 | |||
821 | switch (region->type) { | ||
822 | case WMFW_ADSP1_PM: | ||
823 | region_name = "PM"; | ||
824 | break; | ||
825 | case WMFW_ADSP1_DM: | ||
826 | region_name = "DM"; | ||
827 | break; | ||
828 | case WMFW_ADSP2_XM: | ||
829 | region_name = "XM"; | ||
830 | break; | ||
831 | case WMFW_ADSP2_YM: | ||
832 | region_name = "YM"; | ||
833 | break; | ||
834 | case WMFW_ADSP1_ZM: | ||
835 | region_name = "ZM"; | ||
836 | break; | ||
837 | default: | ||
838 | ret = -EINVAL; | ||
839 | goto err_name; | ||
840 | } | ||
841 | |||
842 | snprintf(name, PAGE_SIZE, "DSP%d %s %x", | ||
843 | dsp->num, region_name, region->alg); | ||
844 | |||
845 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | ||
846 | list) { | ||
847 | if (!strcmp(ctl->name, name)) { | ||
848 | if (!ctl->enabled) | ||
849 | ctl->enabled = 1; | ||
850 | goto found; | ||
851 | } | ||
852 | } | ||
853 | |||
854 | ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); | ||
855 | if (!ctl) { | ||
856 | ret = -ENOMEM; | ||
857 | goto err_name; | ||
858 | } | ||
859 | ctl->region = *region; | ||
860 | ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); | ||
861 | if (!ctl->name) { | ||
862 | ret = -ENOMEM; | ||
863 | goto err_ctl; | ||
864 | } | ||
865 | ctl->enabled = 1; | ||
866 | ctl->set = 0; | ||
867 | ctl->ops.xget = wm_coeff_get; | ||
868 | ctl->ops.xput = wm_coeff_put; | ||
869 | ctl->card = codec->card->snd_card; | ||
870 | ctl->adsp = dsp; | ||
871 | |||
872 | ctl->len = region->len; | ||
873 | ctl->cache = kzalloc(ctl->len, GFP_KERNEL); | ||
874 | if (!ctl->cache) { | ||
875 | ret = -ENOMEM; | ||
876 | goto err_ctl_name; | ||
877 | } | ||
878 | |||
879 | ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); | ||
880 | if (!ctl_work) { | ||
881 | ret = -ENOMEM; | ||
882 | goto err_ctl_cache; | ||
883 | } | ||
884 | |||
885 | ctl_work->wm_coeff = dsp->wm_coeff; | ||
886 | ctl_work->ctl = ctl; | ||
887 | INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); | ||
888 | schedule_work(&ctl_work->work); | ||
889 | |||
890 | found: | ||
891 | kfree(name); | ||
892 | |||
893 | return 0; | ||
894 | |||
895 | err_ctl_cache: | ||
896 | kfree(ctl->cache); | ||
897 | err_ctl_name: | ||
898 | kfree(ctl->name); | ||
899 | err_ctl: | ||
900 | kfree(ctl); | ||
901 | err_name: | ||
902 | kfree(name); | ||
903 | return ret; | ||
904 | } | ||
905 | |||
906 | static int wm_adsp_setup_algs(struct wm_adsp *dsp, struct snd_soc_codec *codec) | ||
551 | { | 907 | { |
552 | struct regmap *regmap = dsp->regmap; | 908 | struct regmap *regmap = dsp->regmap; |
553 | struct wmfw_adsp1_id_hdr adsp1_id; | 909 | struct wmfw_adsp1_id_hdr adsp1_id; |
@@ -730,7 +1086,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
730 | region->type = WMFW_ADSP1_DM; | 1086 | region->type = WMFW_ADSP1_DM; |
731 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1087 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
732 | region->base = be32_to_cpu(adsp1_alg[i].dm); | 1088 | region->base = be32_to_cpu(adsp1_alg[i].dm); |
1089 | region->len = 0; | ||
733 | list_add_tail(®ion->list, &dsp->alg_regions); | 1090 | list_add_tail(®ion->list, &dsp->alg_regions); |
1091 | if (i + 1 < algs) { | ||
1092 | region->len = be32_to_cpu(adsp1_alg[i + 1].dm); | ||
1093 | region->len -= be32_to_cpu(adsp1_alg[i].dm); | ||
1094 | wm_adsp_create_control(codec, region); | ||
1095 | } else { | ||
1096 | adsp_warn(dsp, "Missing length info for region DM with ID %x\n", | ||
1097 | be32_to_cpu(adsp1_alg[i].alg.id)); | ||
1098 | } | ||
734 | 1099 | ||
735 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1100 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
736 | if (!region) | 1101 | if (!region) |
@@ -738,7 +1103,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
738 | region->type = WMFW_ADSP1_ZM; | 1103 | region->type = WMFW_ADSP1_ZM; |
739 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1104 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
740 | region->base = be32_to_cpu(adsp1_alg[i].zm); | 1105 | region->base = be32_to_cpu(adsp1_alg[i].zm); |
1106 | region->len = 0; | ||
741 | list_add_tail(®ion->list, &dsp->alg_regions); | 1107 | list_add_tail(®ion->list, &dsp->alg_regions); |
1108 | if (i + 1 < algs) { | ||
1109 | region->len = be32_to_cpu(adsp1_alg[i + 1].zm); | ||
1110 | region->len -= be32_to_cpu(adsp1_alg[i].zm); | ||
1111 | wm_adsp_create_control(codec, region); | ||
1112 | } else { | ||
1113 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | ||
1114 | be32_to_cpu(adsp1_alg[i].alg.id)); | ||
1115 | } | ||
742 | break; | 1116 | break; |
743 | 1117 | ||
744 | case WMFW_ADSP2: | 1118 | case WMFW_ADSP2: |
@@ -758,7 +1132,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
758 | region->type = WMFW_ADSP2_XM; | 1132 | region->type = WMFW_ADSP2_XM; |
759 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1133 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
760 | region->base = be32_to_cpu(adsp2_alg[i].xm); | 1134 | region->base = be32_to_cpu(adsp2_alg[i].xm); |
1135 | region->len = 0; | ||
761 | list_add_tail(®ion->list, &dsp->alg_regions); | 1136 | list_add_tail(®ion->list, &dsp->alg_regions); |
1137 | if (i + 1 < algs) { | ||
1138 | region->len = be32_to_cpu(adsp2_alg[i + 1].xm); | ||
1139 | region->len -= be32_to_cpu(adsp2_alg[i].xm); | ||
1140 | wm_adsp_create_control(codec, region); | ||
1141 | } else { | ||
1142 | adsp_warn(dsp, "Missing length info for region XM with ID %x\n", | ||
1143 | be32_to_cpu(adsp2_alg[i].alg.id)); | ||
1144 | } | ||
762 | 1145 | ||
763 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1146 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
764 | if (!region) | 1147 | if (!region) |
@@ -766,7 +1149,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
766 | region->type = WMFW_ADSP2_YM; | 1149 | region->type = WMFW_ADSP2_YM; |
767 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1150 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
768 | region->base = be32_to_cpu(adsp2_alg[i].ym); | 1151 | region->base = be32_to_cpu(adsp2_alg[i].ym); |
1152 | region->len = 0; | ||
769 | list_add_tail(®ion->list, &dsp->alg_regions); | 1153 | list_add_tail(®ion->list, &dsp->alg_regions); |
1154 | if (i + 1 < algs) { | ||
1155 | region->len = be32_to_cpu(adsp2_alg[i + 1].ym); | ||
1156 | region->len -= be32_to_cpu(adsp2_alg[i].ym); | ||
1157 | wm_adsp_create_control(codec, region); | ||
1158 | } else { | ||
1159 | adsp_warn(dsp, "Missing length info for region YM with ID %x\n", | ||
1160 | be32_to_cpu(adsp2_alg[i].alg.id)); | ||
1161 | } | ||
770 | 1162 | ||
771 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1163 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
772 | if (!region) | 1164 | if (!region) |
@@ -774,7 +1166,16 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
774 | region->type = WMFW_ADSP2_ZM; | 1166 | region->type = WMFW_ADSP2_ZM; |
775 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1167 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
776 | region->base = be32_to_cpu(adsp2_alg[i].zm); | 1168 | region->base = be32_to_cpu(adsp2_alg[i].zm); |
1169 | region->len = 0; | ||
777 | list_add_tail(®ion->list, &dsp->alg_regions); | 1170 | list_add_tail(®ion->list, &dsp->alg_regions); |
1171 | if (i + 1 < algs) { | ||
1172 | region->len = be32_to_cpu(adsp2_alg[i + 1].zm); | ||
1173 | region->len -= be32_to_cpu(adsp2_alg[i].zm); | ||
1174 | wm_adsp_create_control(codec, region); | ||
1175 | } else { | ||
1176 | adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", | ||
1177 | be32_to_cpu(adsp2_alg[i].alg.id)); | ||
1178 | } | ||
778 | break; | 1179 | break; |
779 | } | 1180 | } |
780 | } | 1181 | } |
@@ -986,6 +1387,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
986 | struct snd_soc_codec *codec = w->codec; | 1387 | struct snd_soc_codec *codec = w->codec; |
987 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 1388 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
988 | struct wm_adsp *dsp = &dsps[w->shift]; | 1389 | struct wm_adsp *dsp = &dsps[w->shift]; |
1390 | struct wm_coeff_ctl *ctl; | ||
989 | int ret; | 1391 | int ret; |
990 | int val; | 1392 | int val; |
991 | 1393 | ||
@@ -1023,7 +1425,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1023 | if (ret != 0) | 1425 | if (ret != 0) |
1024 | goto err; | 1426 | goto err; |
1025 | 1427 | ||
1026 | ret = wm_adsp_setup_algs(dsp); | 1428 | ret = wm_adsp_setup_algs(dsp, codec); |
1027 | if (ret != 0) | 1429 | if (ret != 0) |
1028 | goto err; | 1430 | goto err; |
1029 | 1431 | ||
@@ -1031,6 +1433,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1031 | if (ret != 0) | 1433 | if (ret != 0) |
1032 | goto err; | 1434 | goto err; |
1033 | 1435 | ||
1436 | /* Initialize caches for enabled and unset controls */ | ||
1437 | ret = wm_coeff_init_control_caches(dsp->wm_coeff); | ||
1438 | if (ret != 0) | ||
1439 | goto err; | ||
1440 | |||
1441 | /* Sync set controls */ | ||
1442 | ret = wm_coeff_sync_controls(dsp->wm_coeff); | ||
1443 | if (ret != 0) | ||
1444 | goto err; | ||
1445 | |||
1034 | /* Start the core running */ | 1446 | /* Start the core running */ |
1035 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, | 1447 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, |
1036 | ADSP1_CORE_ENA | ADSP1_START, | 1448 | ADSP1_CORE_ENA | ADSP1_START, |
@@ -1047,6 +1459,11 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, | |||
1047 | 1459 | ||
1048 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, | 1460 | regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, |
1049 | ADSP1_SYS_ENA, 0); | 1461 | ADSP1_SYS_ENA, 0); |
1462 | |||
1463 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | ||
1464 | list) { | ||
1465 | ctl->enabled = 0; | ||
1466 | } | ||
1050 | break; | 1467 | break; |
1051 | 1468 | ||
1052 | default: | 1469 | default: |
@@ -1099,6 +1516,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1099 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); | 1516 | struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); |
1100 | struct wm_adsp *dsp = &dsps[w->shift]; | 1517 | struct wm_adsp *dsp = &dsps[w->shift]; |
1101 | struct wm_adsp_alg_region *alg_region; | 1518 | struct wm_adsp_alg_region *alg_region; |
1519 | struct wm_coeff_ctl *ctl; | ||
1102 | unsigned int val; | 1520 | unsigned int val; |
1103 | int ret; | 1521 | int ret; |
1104 | 1522 | ||
@@ -1164,7 +1582,7 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1164 | if (ret != 0) | 1582 | if (ret != 0) |
1165 | goto err; | 1583 | goto err; |
1166 | 1584 | ||
1167 | ret = wm_adsp_setup_algs(dsp); | 1585 | ret = wm_adsp_setup_algs(dsp, codec); |
1168 | if (ret != 0) | 1586 | if (ret != 0) |
1169 | goto err; | 1587 | goto err; |
1170 | 1588 | ||
@@ -1172,6 +1590,16 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1172 | if (ret != 0) | 1590 | if (ret != 0) |
1173 | goto err; | 1591 | goto err; |
1174 | 1592 | ||
1593 | /* Initialize caches for enabled and unset controls */ | ||
1594 | ret = wm_coeff_init_control_caches(dsp->wm_coeff); | ||
1595 | if (ret != 0) | ||
1596 | goto err; | ||
1597 | |||
1598 | /* Sync set controls */ | ||
1599 | ret = wm_coeff_sync_controls(dsp->wm_coeff); | ||
1600 | if (ret != 0) | ||
1601 | goto err; | ||
1602 | |||
1175 | ret = regmap_update_bits(dsp->regmap, | 1603 | ret = regmap_update_bits(dsp->regmap, |
1176 | dsp->base + ADSP2_CONTROL, | 1604 | dsp->base + ADSP2_CONTROL, |
1177 | ADSP2_CORE_ENA | ADSP2_START, | 1605 | ADSP2_CORE_ENA | ADSP2_START, |
@@ -1209,6 +1637,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1209 | ret); | 1637 | ret); |
1210 | } | 1638 | } |
1211 | 1639 | ||
1640 | list_for_each_entry(ctl, &dsp->wm_coeff->ctl_list, | ||
1641 | list) { | ||
1642 | ctl->enabled = 0; | ||
1643 | } | ||
1644 | |||
1212 | while (!list_empty(&dsp->alg_regions)) { | 1645 | while (!list_empty(&dsp->alg_regions)) { |
1213 | alg_region = list_first_entry(&dsp->alg_regions, | 1646 | alg_region = list_first_entry(&dsp->alg_regions, |
1214 | struct wm_adsp_alg_region, | 1647 | struct wm_adsp_alg_region, |
@@ -1247,36 +1680,48 @@ int wm_adsp2_init(struct wm_adsp *adsp, bool dvfs) | |||
1247 | 1680 | ||
1248 | INIT_LIST_HEAD(&adsp->alg_regions); | 1681 | INIT_LIST_HEAD(&adsp->alg_regions); |
1249 | 1682 | ||
1683 | adsp->wm_coeff = kzalloc(sizeof(*adsp->wm_coeff), | ||
1684 | GFP_KERNEL); | ||
1685 | if (!adsp->wm_coeff) | ||
1686 | return -ENOMEM; | ||
1687 | adsp->wm_coeff->regmap = adsp->regmap; | ||
1688 | adsp->wm_coeff->dev = adsp->dev; | ||
1689 | INIT_LIST_HEAD(&adsp->wm_coeff->ctl_list); | ||
1690 | |||
1250 | if (dvfs) { | 1691 | if (dvfs) { |
1251 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); | 1692 | adsp->dvfs = devm_regulator_get(adsp->dev, "DCVDD"); |
1252 | if (IS_ERR(adsp->dvfs)) { | 1693 | if (IS_ERR(adsp->dvfs)) { |
1253 | ret = PTR_ERR(adsp->dvfs); | 1694 | ret = PTR_ERR(adsp->dvfs); |
1254 | dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); | 1695 | dev_err(adsp->dev, "Failed to get DCVDD: %d\n", ret); |
1255 | return ret; | 1696 | goto out_coeff; |
1256 | } | 1697 | } |
1257 | 1698 | ||
1258 | ret = regulator_enable(adsp->dvfs); | 1699 | ret = regulator_enable(adsp->dvfs); |
1259 | if (ret != 0) { | 1700 | if (ret != 0) { |
1260 | dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", | 1701 | dev_err(adsp->dev, "Failed to enable DCVDD: %d\n", |
1261 | ret); | 1702 | ret); |
1262 | return ret; | 1703 | goto out_coeff; |
1263 | } | 1704 | } |
1264 | 1705 | ||
1265 | ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); | 1706 | ret = regulator_set_voltage(adsp->dvfs, 1200000, 1800000); |
1266 | if (ret != 0) { | 1707 | if (ret != 0) { |
1267 | dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", | 1708 | dev_err(adsp->dev, "Failed to initialise DVFS: %d\n", |
1268 | ret); | 1709 | ret); |
1269 | return ret; | 1710 | goto out_coeff; |
1270 | } | 1711 | } |
1271 | 1712 | ||
1272 | ret = regulator_disable(adsp->dvfs); | 1713 | ret = regulator_disable(adsp->dvfs); |
1273 | if (ret != 0) { | 1714 | if (ret != 0) { |
1274 | dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", | 1715 | dev_err(adsp->dev, "Failed to disable DCVDD: %d\n", |
1275 | ret); | 1716 | ret); |
1276 | return ret; | 1717 | goto out_coeff; |
1277 | } | 1718 | } |
1278 | } | 1719 | } |
1279 | 1720 | ||
1280 | return 0; | 1721 | return 0; |
1722 | |||
1723 | out_coeff: | ||
1724 | kfree(adsp->wm_coeff); | ||
1725 | return ret; | ||
1281 | } | 1726 | } |
1282 | EXPORT_SYMBOL_GPL(wm_adsp2_init); | 1727 | EXPORT_SYMBOL_GPL(wm_adsp2_init); |
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index fea514627526..9f922c82536c 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -30,6 +30,7 @@ struct wm_adsp_alg_region { | |||
30 | unsigned int alg; | 30 | unsigned int alg; |
31 | int type; | 31 | int type; |
32 | unsigned int base; | 32 | unsigned int base; |
33 | size_t len; | ||
33 | }; | 34 | }; |
34 | 35 | ||
35 | struct wm_adsp { | 36 | struct wm_adsp { |
@@ -55,17 +56,17 @@ struct wm_adsp { | |||
55 | bool running; | 56 | bool running; |
56 | 57 | ||
57 | struct regulator *dvfs; | 58 | struct regulator *dvfs; |
59 | |||
60 | struct wm_coeff *wm_coeff; | ||
58 | }; | 61 | }; |
59 | 62 | ||
60 | #define WM_ADSP1(wname, num) \ | 63 | #define WM_ADSP1(wname, num) \ |
61 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ | 64 | SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ |
62 | .shift = num, .event = wm_adsp1_event, \ | 65 | wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) |
63 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } | ||
64 | 66 | ||
65 | #define WM_ADSP2(wname, num) \ | 67 | #define WM_ADSP2(wname, num) \ |
66 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ | 68 | SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ |
67 | .shift = num, .event = wm_adsp2_event, \ | 69 | wm_adsp2_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) |
68 | .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } | ||
69 | 70 | ||
70 | extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; | 71 | extern const struct snd_kcontrol_new wm_adsp1_fw_controls[]; |
71 | extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; | 72 | extern const struct snd_kcontrol_new wm_adsp2_fw_controls[]; |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index f5d81b948759..2d9e099415a5 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -693,10 +693,8 @@ void wm_hubs_update_class_w(struct snd_soc_codec *codec) | |||
693 | EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); | 693 | EXPORT_SYMBOL_GPL(wm_hubs_update_class_w); |
694 | 694 | ||
695 | #define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \ | 695 | #define WM_HUBS_SINGLE_W(xname, reg, shift, max, invert) \ |
696 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 696 | SOC_SINGLE_EXT(xname, reg, shift, max, invert, \ |
697 | .info = snd_soc_info_volsw, \ | 697 | snd_soc_dapm_get_volsw, class_w_put_volsw) |
698 | .get = snd_soc_dapm_get_volsw, .put = class_w_put_volsw, \ | ||
699 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
700 | 698 | ||
701 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, | 699 | static int class_w_put_volsw(struct snd_kcontrol *kcontrol, |
702 | struct snd_ctl_elem_value *ucontrol) | 700 | struct snd_ctl_elem_value *ucontrol) |