ASoC: Support non-crystal master clocks for WM8731
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 17 Aug 2010 22:40:24 +0000 (23:40 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 18 Aug 2010 15:52:56 +0000 (16:52 +0100)
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>
sound/soc/atmel/sam9g20_wm8731.c
sound/soc/au1x/db1200.c
sound/soc/codecs/wm8731.c
sound/soc/codecs/wm8731.h
sound/soc/pxa/corgi.c
sound/soc/pxa/poodle.c

index 66a6f187968906195cfee0049eebe0b2851bd4a1..8399ac46cb33577499f942eb31ab8fae07505131 100644 (file)
@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
                        "at91sam9g20ek_wm8731 "
                        ": 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);
        if (ret < 0) {
                printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
index 8780c90107fc78cbe2787e6fcb5f6cf80258863e..d8dc8225576a2f83ca32bc188c5809c961f81d03 100644 (file)
@@ -49,7 +49,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
        int ret;
 
        /* 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);
 
        /* codec is bitclock and lrclk master */
index 19844fc8cb1dfd8edf39e929853b573e68d25298..56f540838745a0407d3f1611cbd50eac4b8377b8 100644 (file)
@@ -46,6 +46,7 @@ struct wm8731_priv {
        struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
        u16 reg_cache[WM8731_CACHEREGNUM];
        unsigned int sysclk;
+       int sysclk_type;
 };
 
 
@@ -110,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
 SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
 
 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,
        &wm8731_output_mixer_controls[0],
        ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -127,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
 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[] = {
+       {"DAC", NULL, "OSC", wm8731_check_osc},
+       {"ADC", NULL, "OSC", wm8731_check_osc},
+
        /* output mixer */
        {"Output Mixer", "Line Bypass Switch", "Line Input"},
        {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -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 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) {
        case 11289600:
        case 12000000:
@@ -292,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        case 16934400:
        case 18432000:
                wm8731->sysclk = freq;
-               return 0;
+               break;
+       default:
+               return -EINVAL;
        }
-       return -EINVAL;
+
+       snd_soc_dapm_sync(codec);
+
+       return 0;
 }
 
 
index 73a70e206ba9be98e27c446cc9638b56f22da46a..e9c0c76ab73bf4ca72f667e5ef2d2d063ff5028a 100644 (file)
@@ -31,7 +31,9 @@
 
 #define WM8731_CACHEREGNUM     10
 
-#define WM8731_SYSCLK  0
+#define WM8731_SYSCLK_XTAL 1
+#define WM8731_SYSCLK_MCLK 2
+
 #define WM8731_DAI             0
 
 #endif
index 555689cf67274357fc0e34c9a70fa11f569f92a5..97e9423615c9c84d859a2b5b5b31695d73f4ab2f 100644 (file)
@@ -149,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* 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);
        if (ret < 0)
                return ret;
index add0e1c25bc8e6d0d5431167769e0d167eb8f8ad..fa752f6ec37d819e167f497781c889a360f54db7 100644 (file)
@@ -128,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
                return ret;
 
        /* 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);
        if (ret < 0)
                return ret;