Commit 02890535269338a6d2034ad3ce8b22beb24b449a
Committed by
Mark Brown
1 parent
a9d1974ea1
Exists in
master
and in
6 other branches
ASoC: ssm2602: Support setting the oscillator and the clock output state
Currently the oscillator is always enabled and the clock output is always disabled. This patch adds support for controlling the oscillator and clock output state through snd_soc_dai_set_sysclk. Which makes it possible to disable or enable them dynamically according to the requirements of the board on which the CODEC is used. This patch also slightly modifies the behavior as to when the oscillator is going to be disabled in low-power states. Previously it would only be disabled in BIAS_OFF, now it is also going to be disabled in BIAS_STANDBY, since no components which depend on it should be active in this state. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 2 changed files with 56 additions and 17 deletions Side-by-side Diff
sound/soc/codecs/ssm2602.c
... | ... | @@ -59,6 +59,7 @@ |
59 | 59 | struct snd_pcm_substream *slave_substream; |
60 | 60 | |
61 | 61 | enum ssm2602_type type; |
62 | + unsigned int clk_out_pwr; | |
62 | 63 | }; |
63 | 64 | |
64 | 65 | /* |
65 | 66 | |
... | ... | @@ -356,16 +357,46 @@ |
356 | 357 | { |
357 | 358 | struct snd_soc_codec *codec = codec_dai->codec; |
358 | 359 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
359 | - switch (freq) { | |
360 | - case 11289600: | |
361 | - case 12000000: | |
362 | - case 12288000: | |
363 | - case 16934400: | |
364 | - case 18432000: | |
365 | - ssm2602->sysclk = freq; | |
366 | - return 0; | |
360 | + | |
361 | + if (dir == SND_SOC_CLOCK_IN) { | |
362 | + if (clk_id != SSM2602_SYSCLK) | |
363 | + return -EINVAL; | |
364 | + | |
365 | + switch (freq) { | |
366 | + case 11289600: | |
367 | + case 12000000: | |
368 | + case 12288000: | |
369 | + case 16934400: | |
370 | + case 18432000: | |
371 | + ssm2602->sysclk = freq; | |
372 | + break; | |
373 | + default: | |
374 | + return -EINVAL; | |
375 | + } | |
376 | + } else { | |
377 | + unsigned int mask; | |
378 | + | |
379 | + switch (clk_id) { | |
380 | + case SSM2602_CLK_CLKOUT: | |
381 | + mask = PWR_CLK_OUT_PDN; | |
382 | + break; | |
383 | + case SSM2602_CLK_XTO: | |
384 | + mask = PWR_OSC_PDN; | |
385 | + break; | |
386 | + default: | |
387 | + return -EINVAL; | |
388 | + } | |
389 | + | |
390 | + if (freq == 0) | |
391 | + ssm2602->clk_out_pwr |= mask; | |
392 | + else | |
393 | + ssm2602->clk_out_pwr &= ~mask; | |
394 | + | |
395 | + snd_soc_update_bits(codec, SSM2602_PWR, | |
396 | + PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr); | |
367 | 397 | } |
368 | - return -EINVAL; | |
398 | + | |
399 | + return 0; | |
369 | 400 | } |
370 | 401 | |
371 | 402 | static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, |
372 | 403 | |
373 | 404 | |
374 | 405 | |
... | ... | @@ -430,23 +461,27 @@ |
430 | 461 | static int ssm2602_set_bias_level(struct snd_soc_codec *codec, |
431 | 462 | enum snd_soc_bias_level level) |
432 | 463 | { |
433 | - u16 reg = snd_soc_read(codec, SSM2602_PWR); | |
434 | - reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN); | |
464 | + struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | |
435 | 465 | |
436 | 466 | switch (level) { |
437 | 467 | case SND_SOC_BIAS_ON: |
438 | - /* vref/mid, osc on, dac unmute */ | |
439 | - snd_soc_write(codec, SSM2602_PWR, reg); | |
468 | + /* vref/mid on, osc and clkout on if enabled */ | |
469 | + snd_soc_update_bits(codec, SSM2602_PWR, | |
470 | + PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, | |
471 | + ssm2602->clk_out_pwr); | |
440 | 472 | break; |
441 | 473 | case SND_SOC_BIAS_PREPARE: |
442 | 474 | break; |
443 | 475 | case SND_SOC_BIAS_STANDBY: |
444 | 476 | /* everything off except vref/vmid, */ |
445 | - snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); | |
477 | + snd_soc_update_bits(codec, SSM2602_PWR, | |
478 | + PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN, | |
479 | + PWR_CLK_OUT_PDN | PWR_OSC_PDN); | |
446 | 480 | break; |
447 | 481 | case SND_SOC_BIAS_OFF: |
448 | - /* everything off, dac mute, inactive */ | |
449 | - snd_soc_write(codec, SSM2602_PWR, 0xffff); | |
482 | + /* everything off */ | |
483 | + snd_soc_update_bits(codec, SSM2602_PWR, | |
484 | + PWR_POWER_OFF, PWR_POWER_OFF); | |
450 | 485 | break; |
451 | 486 | |
452 | 487 | } |