aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2011-09-27 05:08:48 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2011-09-27 08:30:48 -0400
commit02890535269338a6d2034ad3ce8b22beb24b449a (patch)
tree2832216154fafb2530c3e3f5a9b0d9035d975ff9
parenta9d1974ea13b361bf60a9d493a6a05e5a42b0ba2 (diff)
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>
-rw-r--r--sound/soc/codecs/ssm2602.c67
-rw-r--r--sound/soc/codecs/ssm2602.h6
2 files changed, 56 insertions, 17 deletions
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index c9e0fdbf0565..e149ec61e6be 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -59,6 +59,7 @@ struct ssm2602_priv {
59 struct snd_pcm_substream *slave_substream; 59 struct snd_pcm_substream *slave_substream;
60 60
61 enum ssm2602_type type; 61 enum ssm2602_type type;
62 unsigned int clk_out_pwr;
62}; 63};
63 64
64/* 65/*
@@ -356,16 +357,46 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
356{ 357{
357 struct snd_soc_codec *codec = codec_dai->codec; 358 struct snd_soc_codec *codec = codec_dai->codec;
358 struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); 359 struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
359 switch (freq) { 360
360 case 11289600: 361 if (dir == SND_SOC_CLOCK_IN) {
361 case 12000000: 362 if (clk_id != SSM2602_SYSCLK)
362 case 12288000: 363 return -EINVAL;
363 case 16934400: 364
364 case 18432000: 365 switch (freq) {
365 ssm2602->sysclk = freq; 366 case 11289600:
366 return 0; 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
371static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, 402static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
@@ -430,23 +461,27 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
430static int ssm2602_set_bias_level(struct snd_soc_codec *codec, 461static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
431 enum snd_soc_bias_level level) 462 enum snd_soc_bias_level level)
432{ 463{
433 u16 reg = snd_soc_read(codec, SSM2602_PWR); 464 struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
434 reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
435 465
436 switch (level) { 466 switch (level) {
437 case SND_SOC_BIAS_ON: 467 case SND_SOC_BIAS_ON:
438 /* vref/mid, osc on, dac unmute */ 468 /* vref/mid on, osc and clkout on if enabled */
439 snd_soc_write(codec, SSM2602_PWR, reg); 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 break; 472 break;
441 case SND_SOC_BIAS_PREPARE: 473 case SND_SOC_BIAS_PREPARE:
442 break; 474 break;
443 case SND_SOC_BIAS_STANDBY: 475 case SND_SOC_BIAS_STANDBY:
444 /* everything off except vref/vmid, */ 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 break; 480 break;
447 case SND_SOC_BIAS_OFF: 481 case SND_SOC_BIAS_OFF:
448 /* everything off, dac mute, inactive */ 482 /* everything off */
449 snd_soc_write(codec, SSM2602_PWR, 0xffff); 483 snd_soc_update_bits(codec, SSM2602_PWR,
484 PWR_POWER_OFF, PWR_POWER_OFF);
450 break; 485 break;
451 486
452 } 487 }
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h
index b98c69168036..fbd07d7b73ca 100644
--- a/sound/soc/codecs/ssm2602.h
+++ b/sound/soc/codecs/ssm2602.h
@@ -116,6 +116,10 @@
116 116
117#define SSM2602_CACHEREGNUM 10 117#define SSM2602_CACHEREGNUM 10
118 118
119#define SSM2602_SYSCLK 0 119enum ssm2602_clk {
120 SSM2602_SYSCLK,
121 SSM2602_CLK_CLKOUT,
122 SSM2602_CLK_XTO
123};
120 124
121#endif 125#endif