diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-03-16 16:55:37 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-03-22 14:41:27 -0400 |
commit | f20d77ce2663b31c2994462d9ab9143726b67f3e (patch) | |
tree | cd6f2f5d68b3398eff77e61826cabcaa70d0c18e /sound | |
parent | fbbf592002ee46ed14d5bd88f1150c604b34e705 (diff) |
ASoC: Refactor WM8958 DSP to support additional algorithms
In preparation for the addition of additional WM8958 algorithms
reorganise the code to make it easier to add such support later.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@ti.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/wm8958-dsp2.c | 96 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.h | 1 |
2 files changed, 44 insertions, 53 deletions
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 58fe40416709..9c1cbe5b61ae 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c | |||
@@ -189,7 +189,7 @@ ok: | |||
189 | return ret; | 189 | return ret; |
190 | } | 190 | } |
191 | 191 | ||
192 | static void wm8958_mbc_apply(struct snd_soc_codec *codec, int mbc, int start) | 192 | static void wm8958_dsp_start_mbc(struct snd_soc_codec *codec, int path) |
193 | { | 193 | { |
194 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 194 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
195 | struct wm8994_pdata *pdata = wm8994->pdata; | 195 | struct wm8994_pdata *pdata = wm8994->pdata; |
@@ -237,9 +237,9 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start) | |||
237 | { | 237 | { |
238 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 238 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
239 | int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5); | 239 | int pwr_reg = snd_soc_read(codec, WM8994_POWER_MANAGEMENT_5); |
240 | int ena, reg, aif, i; | 240 | int ena, reg, aif; |
241 | 241 | ||
242 | switch (mbc) { | 242 | switch (path) { |
243 | case 0: | 243 | case 0: |
244 | pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA); | 244 | pwr_reg &= (WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA); |
245 | aif = 0; | 245 | aif = 0; |
@@ -257,64 +257,34 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start) | |||
257 | return; | 257 | return; |
258 | } | 258 | } |
259 | 259 | ||
260 | /* We can only enable the MBC if the AIF is enabled and we | 260 | /* Do we have both an active AIF and an active algorithm? */ |
261 | * want it to be enabled. */ | 261 | ena = wm8994->mbc_ena[path]; |
262 | ena = pwr_reg && wm8994->mbc_ena[mbc]; | 262 | if (!pwr_reg) |
263 | ena = 0; | ||
263 | 264 | ||
264 | reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM); | 265 | reg = snd_soc_read(codec, WM8958_DSP2_PROGRAM); |
265 | 266 | ||
266 | dev_dbg(codec->dev, "MBC %d startup: %d, power: %x, DSP: %x\n", | 267 | dev_dbg(codec->dev, "DSP path %d %d startup: %d, power: %x, DSP: %x\n", |
267 | mbc, start, pwr_reg, reg); | 268 | path, wm8994->dsp_active, start, pwr_reg, reg); |
268 | 269 | ||
269 | if (start && ena) { | 270 | if (start && ena) { |
270 | /* If the DSP is already running then noop */ | 271 | /* If either AIFnCLK is not yet enabled postpone */ |
271 | if (reg & WM8958_DSP2_ENA) | ||
272 | return; | ||
273 | |||
274 | /* If neither AIFnCLK is not yet enabled postpone */ | ||
275 | if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) | 272 | if (!(snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) |
276 | & WM8994_AIF1CLK_ENA_MASK) && | 273 | & WM8994_AIF1CLK_ENA_MASK) && |
277 | !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1) | 274 | !(snd_soc_read(codec, WM8994_AIF2_CLOCKING_1) |
278 | & WM8994_AIF2CLK_ENA_MASK)) | 275 | & WM8994_AIF2CLK_ENA_MASK)) |
279 | return; | 276 | return; |
280 | 277 | ||
281 | /* If we have MBC firmware download it */ | ||
282 | if (wm8994->mbc && wm8994->mbc_ena[mbc]) | ||
283 | wm8958_dsp2_fw(codec, "MBC", wm8994->mbc, false); | ||
284 | |||
285 | /* Switch the clock over to the appropriate AIF */ | 278 | /* Switch the clock over to the appropriate AIF */ |
286 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, | 279 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, |
287 | WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA, | 280 | WM8958_DSP2CLK_SRC | WM8958_DSP2CLK_ENA, |
288 | aif << WM8958_DSP2CLK_SRC_SHIFT | | 281 | aif << WM8958_DSP2CLK_SRC_SHIFT | |
289 | WM8958_DSP2CLK_ENA); | 282 | WM8958_DSP2CLK_ENA); |
290 | 283 | ||
291 | snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, | 284 | if (wm8994->mbc_ena[path]) |
292 | WM8958_DSP2_ENA, WM8958_DSP2_ENA); | 285 | wm8958_dsp_start_mbc(codec, path); |
293 | |||
294 | /* If we've got user supplied MBC settings use them */ | ||
295 | if (pdata && pdata->num_mbc_cfgs) { | ||
296 | struct wm8958_mbc_cfg *cfg | ||
297 | = &pdata->mbc_cfgs[wm8994->mbc_cfg]; | ||
298 | |||
299 | for (i = 0; i < ARRAY_SIZE(cfg->coeff_regs); i++) | ||
300 | snd_soc_write(codec, i + WM8958_MBC_BAND_1_K_1, | ||
301 | cfg->coeff_regs[i]); | ||
302 | |||
303 | for (i = 0; i < ARRAY_SIZE(cfg->cutoff_regs); i++) | ||
304 | snd_soc_write(codec, | ||
305 | i + WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1, | ||
306 | cfg->cutoff_regs[i]); | ||
307 | } | ||
308 | |||
309 | /* Run the DSP */ | ||
310 | snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, | ||
311 | WM8958_DSP2_RUNR); | ||
312 | 286 | ||
313 | /* And we're off! */ | 287 | dev_dbg(codec->dev, "DSP running\n"); |
314 | snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, | ||
315 | WM8958_MBC_ENA | WM8958_MBC_SEL_MASK, | ||
316 | mbc << WM8958_MBC_SEL_SHIFT | | ||
317 | WM8958_MBC_ENA); | ||
318 | } else { | 288 | } else { |
319 | /* If the DSP is already stopped then noop */ | 289 | /* If the DSP is already stopped then noop */ |
320 | if (!(reg & WM8958_DSP2_ENA)) | 290 | if (!(reg & WM8958_DSP2_ENA)) |
@@ -322,10 +292,16 @@ static void wm8958_dsp_apply(struct snd_soc_codec *codec, int path, int start) | |||
322 | 292 | ||
323 | snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, | 293 | snd_soc_update_bits(codec, WM8958_DSP2_CONFIG, |
324 | WM8958_MBC_ENA, 0); | 294 | WM8958_MBC_ENA, 0); |
295 | snd_soc_write(codec, WM8958_DSP2_EXECCONTROL, | ||
296 | WM8958_DSP2_STOP); | ||
325 | snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, | 297 | snd_soc_update_bits(codec, WM8958_DSP2_PROGRAM, |
326 | WM8958_DSP2_ENA, 0); | 298 | WM8958_DSP2_ENA, 0); |
327 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, | 299 | snd_soc_update_bits(codec, WM8994_CLOCKING_1, |
328 | WM8958_DSP2CLK_ENA, 0); | 300 | WM8958_DSP2CLK_ENA, 0); |
301 | |||
302 | wm8994->dsp_active = -1; | ||
303 | |||
304 | dev_dbg(codec->dev, "DSP stopped\n"); | ||
329 | } | 305 | } |
330 | } | 306 | } |
331 | 307 | ||
@@ -339,18 +315,33 @@ int wm8958_aif_ev(struct snd_soc_dapm_widget *w, | |||
339 | case SND_SOC_DAPM_POST_PMU: | 315 | case SND_SOC_DAPM_POST_PMU: |
340 | case SND_SOC_DAPM_PRE_PMU: | 316 | case SND_SOC_DAPM_PRE_PMU: |
341 | for (i = 0; i < 3; i++) | 317 | for (i = 0; i < 3; i++) |
342 | wm8958_mbc_apply(codec, i, 1); | 318 | wm8958_dsp_apply(codec, i, 1); |
343 | break; | 319 | break; |
344 | case SND_SOC_DAPM_POST_PMD: | 320 | case SND_SOC_DAPM_POST_PMD: |
345 | case SND_SOC_DAPM_PRE_PMD: | 321 | case SND_SOC_DAPM_PRE_PMD: |
346 | for (i = 0; i < 3; i++) | 322 | for (i = 0; i < 3; i++) |
347 | wm8958_mbc_apply(codec, i, 0); | 323 | wm8958_dsp_apply(codec, i, 0); |
348 | break; | 324 | break; |
349 | } | 325 | } |
350 | 326 | ||
351 | return 0; | 327 | return 0; |
352 | } | 328 | } |
353 | 329 | ||
330 | /* Check if DSP2 is in use on another AIF */ | ||
331 | static int wm8958_dsp2_busy(struct wm8994_priv *wm8994, int aif) | ||
332 | { | ||
333 | int i; | ||
334 | |||
335 | for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) { | ||
336 | if (i == aif) | ||
337 | continue; | ||
338 | if (wm8994->mbc_ena[i]) | ||
339 | return 1; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
354 | static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, | 345 | static int wm8958_put_mbc_enum(struct snd_kcontrol *kcontrol, |
355 | struct snd_ctl_elem_value *ucontrol) | 346 | struct snd_ctl_elem_value *ucontrol) |
356 | { | 347 | { |
@@ -410,23 +401,20 @@ static int wm8958_mbc_put(struct snd_kcontrol *kcontrol, | |||
410 | struct snd_ctl_elem_value *ucontrol) | 401 | struct snd_ctl_elem_value *ucontrol) |
411 | { | 402 | { |
412 | int mbc = kcontrol->private_value; | 403 | int mbc = kcontrol->private_value; |
413 | int i; | ||
414 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 404 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
415 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 405 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
416 | 406 | ||
417 | if (ucontrol->value.integer.value[0] > 1) | 407 | if (ucontrol->value.integer.value[0] > 1) |
418 | return -EINVAL; | 408 | return -EINVAL; |
419 | 409 | ||
420 | for (i = 0; i < ARRAY_SIZE(wm8994->mbc_ena); i++) { | 410 | if (wm8958_dsp2_busy(wm8994, mbc)) { |
421 | if (mbc != i && wm8994->mbc_ena[i]) { | 411 | dev_dbg(codec->dev, "DSP2 active on %d already\n", mbc); |
422 | dev_dbg(codec->dev, "MBC %d active already\n", mbc); | 412 | return -EBUSY; |
423 | return -EBUSY; | ||
424 | } | ||
425 | } | 413 | } |
426 | 414 | ||
427 | wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0]; | 415 | wm8994->mbc_ena[mbc] = ucontrol->value.integer.value[0]; |
428 | 416 | ||
429 | wm8958_mbc_apply(codec, mbc, wm8994->mbc_ena[mbc]); | 417 | wm8958_dsp_apply(codec, mbc, wm8994->mbc_ena[mbc]); |
430 | 418 | ||
431 | return 0; | 419 | return 0; |
432 | } | 420 | } |
@@ -462,10 +450,12 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
462 | struct wm8994_pdata *pdata = wm8994->pdata; | 450 | struct wm8994_pdata *pdata = wm8994->pdata; |
463 | int ret, i; | 451 | int ret, i; |
464 | 452 | ||
453 | wm8994->dsp_active = -1; | ||
454 | |||
465 | snd_soc_add_controls(codec, wm8958_mbc_snd_controls, | 455 | snd_soc_add_controls(codec, wm8958_mbc_snd_controls, |
466 | ARRAY_SIZE(wm8958_mbc_snd_controls)); | 456 | ARRAY_SIZE(wm8958_mbc_snd_controls)); |
467 | 457 | ||
468 | /* We don't require firmware and don't want to delay boot */ | 458 | /* We don't *require* firmware and don't want to delay boot */ |
469 | request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, | 459 | request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, |
470 | "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, | 460 | "wm8958_mbc.wfw", codec->dev, GFP_KERNEL, |
471 | codec, wm8958_mbc_loaded); | 461 | codec, wm8958_mbc_loaded); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 1aa365b31b08..a4bfde83065f 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -116,6 +116,7 @@ struct wm8994_priv { | |||
116 | unsigned int aif1clk_disable:1; | 116 | unsigned int aif1clk_disable:1; |
117 | unsigned int aif2clk_disable:1; | 117 | unsigned int aif2clk_disable:1; |
118 | 118 | ||
119 | int dsp_active; | ||
119 | const struct firmware *cur_fw; | 120 | const struct firmware *cur_fw; |
120 | const struct firmware *mbc; | 121 | const struct firmware *mbc; |
121 | }; | 122 | }; |