Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>

+36 -7
+1 -1
sound/soc/atmel/sam9g20_wm8731.c
··· 146 146 "at91sam9g20ek_wm8731 " 147 147 ": at91sam9g20ek_wm8731_init() called\n"); 148 148 149 - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, 149 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, 150 150 MCLK_RATE, SND_SOC_CLOCK_IN); 151 151 if (ret < 0) { 152 152 printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
+1 -1
sound/soc/au1x/db1200.c
··· 49 49 int ret; 50 50 51 51 /* WM8731 has its own 12MHz crystal */ 52 - snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, 52 + snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, 53 53 12000000, SND_SOC_CLOCK_IN); 54 54 55 55 /* codec is bitclock and lrclk master */
+29 -2
sound/soc/codecs/wm8731.c
··· 46 46 struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; 47 47 u16 reg_cache[WM8731_CACHEREGNUM]; 48 48 unsigned int sysclk; 49 + int sysclk_type; 49 50 }; 50 51 51 52 ··· 111 110 SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); 112 111 113 112 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { 113 + SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0), 114 114 SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, 115 115 &wm8731_output_mixer_controls[0], 116 116 ARRAY_SIZE(wm8731_output_mixer_controls)), ··· 129 127 SND_SOC_DAPM_INPUT("LLINEIN"), 130 128 }; 131 129 130 + static int wm8731_check_osc(struct snd_soc_dapm_widget *source, 131 + struct snd_soc_dapm_widget *sink) 132 + { 133 + struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec); 134 + 135 + return wm8731->sysclk_type == WM8731_SYSCLK_MCLK; 136 + } 137 + 132 138 static const struct snd_soc_dapm_route intercon[] = { 139 + {"DAC", NULL, "OSC", wm8731_check_osc}, 140 + {"ADC", NULL, "OSC", wm8731_check_osc}, 141 + 133 142 /* output mixer */ 134 143 {"Output Mixer", "Line Bypass Switch", "Line Input"}, 135 144 {"Output Mixer", "HiFi Playback Switch", "DAC"}, ··· 298 285 struct snd_soc_codec *codec = codec_dai->codec; 299 286 struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 300 287 288 + switch (clk_id) { 289 + case WM8731_SYSCLK_XTAL: 290 + case WM8731_SYSCLK_MCLK: 291 + wm8731->sysclk_type = clk_id; 292 + break; 293 + default: 294 + return -EINVAL; 295 + } 296 + 301 297 switch (freq) { 302 298 case 11289600: 303 299 case 12000000: ··· 314 292 case 16934400: 315 293 case 18432000: 316 294 wm8731->sysclk = freq; 317 - return 0; 295 + break; 296 + default: 297 + return -EINVAL; 318 298 } 319 - return -EINVAL; 299 + 300 + snd_soc_dapm_sync(codec); 301 + 302 + return 0; 320 303 } 321 304 322 305
+3 -1
sound/soc/codecs/wm8731.h
··· 31 31 32 32 #define WM8731_CACHEREGNUM 10 33 33 34 - #define WM8731_SYSCLK 0 34 + #define WM8731_SYSCLK_XTAL 1 35 + #define WM8731_SYSCLK_MCLK 2 36 + 35 37 #define WM8731_DAI 0 36 38 37 39 #endif
+1 -1
sound/soc/pxa/corgi.c
··· 149 149 return ret; 150 150 151 151 /* set the codec system clock for DAC and ADC */ 152 - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, 152 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk, 153 153 SND_SOC_CLOCK_IN); 154 154 if (ret < 0) 155 155 return ret;
+1 -1
sound/soc/pxa/poodle.c
··· 128 128 return ret; 129 129 130 130 /* set the codec system clock for DAC and ADC */ 131 - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, 131 + ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk, 132 132 SND_SOC_CLOCK_IN); 133 133 if (ret < 0) 134 134 return ret;