Commit e7712510 authored by Mark Brown's avatar Mark Brown

ASoC: Support non-crystal master clocks for WM8731

Instead of unconditionally enabling the crystal oscillator on the WM8731
only enable it when explicitly selected via set_sysclk(), allowing machine
drivers to specify that they drive a clock into MCLK alone. This avoids
any conflicts between the oscillator and the external MCLK source and saves
power for systems which do not need the oscillator.

This should also deliver a small power saving on systems using the crystal
since the oscillator will only be enabled when the ADC or DAC is active.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: default avatarLiam Girdwood <lrg@slimlogic.co.uk>
parent 720ffa4c
...@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) ...@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
"at91sam9g20ek_wm8731 " "at91sam9g20ek_wm8731 "
": at91sam9g20ek_wm8731_init() called\n"); ": at91sam9g20ek_wm8731_init() called\n");
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
MCLK_RATE, SND_SOC_CLOCK_IN); MCLK_RATE, SND_SOC_CLOCK_IN);
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
......
...@@ -49,7 +49,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream) ...@@ -49,7 +49,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
int ret; int ret;
/* WM8731 has its own 12MHz crystal */ /* WM8731 has its own 12MHz crystal */
snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
12000000, SND_SOC_CLOCK_IN); 12000000, SND_SOC_CLOCK_IN);
/* codec is bitclock and lrclk master */ /* codec is bitclock and lrclk master */
......
...@@ -46,6 +46,7 @@ struct wm8731_priv { ...@@ -46,6 +46,7 @@ struct wm8731_priv {
struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
u16 reg_cache[WM8731_CACHEREGNUM]; u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk; unsigned int sysclk;
int sysclk_type;
}; };
...@@ -110,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls = ...@@ -110,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
&wm8731_output_mixer_controls[0], &wm8731_output_mixer_controls[0],
ARRAY_SIZE(wm8731_output_mixer_controls)), ARRAY_SIZE(wm8731_output_mixer_controls)),
...@@ -127,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"), ...@@ -127,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
SND_SOC_DAPM_INPUT("LLINEIN"), SND_SOC_DAPM_INPUT("LLINEIN"),
}; };
static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
}
static const struct snd_soc_dapm_route intercon[] = { static const struct snd_soc_dapm_route intercon[] = {
{"DAC", NULL, "OSC", wm8731_check_osc},
{"ADC", NULL, "OSC", wm8731_check_osc},
/* output mixer */ /* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"}, {"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"}, {"Output Mixer", "HiFi Playback Switch", "DAC"},
...@@ -285,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -285,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
switch (clk_id) {
case WM8731_SYSCLK_XTAL:
case WM8731_SYSCLK_MCLK:
wm8731->sysclk_type = clk_id;
break;
default:
return -EINVAL;
}
switch (freq) { switch (freq) {
case 11289600: case 11289600:
case 12000000: case 12000000:
...@@ -292,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai, ...@@ -292,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case 16934400: case 16934400:
case 18432000: case 18432000:
wm8731->sysclk = freq; wm8731->sysclk = freq;
return 0; break;
} default:
return -EINVAL; return -EINVAL;
}
snd_soc_dapm_sync(codec);
return 0;
} }
......
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
#define WM8731_CACHEREGNUM 10 #define WM8731_CACHEREGNUM 10
#define WM8731_SYSCLK 0 #define WM8731_SYSCLK_XTAL 1
#define WM8731_SYSCLK_MCLK 2
#define WM8731_DAI 0 #define WM8731_DAI 0
#endif #endif
...@@ -149,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream, ...@@ -149,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
/* set the codec system clock for DAC and ADC */ /* set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN); SND_SOC_CLOCK_IN);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
...@@ -128,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream, ...@@ -128,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
return ret; return ret;
/* set the codec system clock for DAC and ADC */ /* set the codec system clock for DAC and ADC */
ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
SND_SOC_CLOCK_IN); SND_SOC_CLOCK_IN);
if (ret < 0) if (ret < 0)
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment