diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-08 09:44:06 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-06-08 10:24:48 -0400 |
commit | 417ceff939bc61d4c71d24f071fad3f20ba4a1bd (patch) | |
tree | fb8170cfd1bb8a214f06ac5e94804284ba994afe /sound/soc/codecs/wm8962.c | |
parent | 8f63aaa887d723f52d44b41074486defcd42ad95 (diff) |
ASoC: Defer all WM8962 clocking configuration until power up
Don't require an audio rate SYSCLK in hw_params() in order to better
support microphone detection use cases.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/wm8962.c')
-rw-r--r-- | sound/soc/codecs/wm8962.c | 60 |
1 files changed, 33 insertions, 27 deletions
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 2b3d961eb6b5..9b6c46f54b4d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -2790,18 +2790,44 @@ static const int bclk_divs[] = { | |||
2790 | 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 | 2790 | 1, -1, 2, 3, 4, -1, 6, 8, -1, 12, 16, 24, -1, 32, 32, 32 |
2791 | }; | 2791 | }; |
2792 | 2792 | ||
2793 | static const int sysclk_rates[] = { | ||
2794 | 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, | ||
2795 | }; | ||
2796 | |||
2793 | static void wm8962_configure_bclk(struct snd_soc_codec *codec) | 2797 | static void wm8962_configure_bclk(struct snd_soc_codec *codec) |
2794 | { | 2798 | { |
2795 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 2799 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
2796 | int dspclk, i; | 2800 | int dspclk, i; |
2797 | int clocking2 = 0; | 2801 | int clocking2 = 0; |
2802 | int clocking4 = 0; | ||
2798 | int aif2 = 0; | 2803 | int aif2 = 0; |
2799 | 2804 | ||
2800 | if (!wm8962->bclk) { | 2805 | if (!wm8962->sysclk_rate) { |
2801 | dev_dbg(codec->dev, "No BCLK rate configured\n"); | 2806 | dev_dbg(codec->dev, "No SYSCLK configured\n"); |
2802 | return; | 2807 | return; |
2803 | } | 2808 | } |
2804 | 2809 | ||
2810 | if (!wm8962->bclk || !wm8962->lrclk) { | ||
2811 | dev_dbg(codec->dev, "No audio clocks configured\n"); | ||
2812 | return; | ||
2813 | } | ||
2814 | |||
2815 | for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { | ||
2816 | if (sysclk_rates[i] == wm8962->sysclk_rate / wm8962->lrclk) { | ||
2817 | clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; | ||
2818 | break; | ||
2819 | } | ||
2820 | } | ||
2821 | |||
2822 | if (i == ARRAY_SIZE(sysclk_rates)) { | ||
2823 | dev_err(codec->dev, "Unsupported sysclk ratio %d\n", | ||
2824 | wm8962->sysclk_rate / wm8962->lrclk); | ||
2825 | return; | ||
2826 | } | ||
2827 | |||
2828 | snd_soc_update_bits(codec, WM8962_CLOCKING_4, | ||
2829 | WM8962_SYSCLK_RATE_MASK, clocking4); | ||
2830 | |||
2805 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); | 2831 | dspclk = snd_soc_read(codec, WM8962_CLOCKING1); |
2806 | if (dspclk < 0) { | 2832 | if (dspclk < 0) { |
2807 | dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); | 2833 | dev_err(codec->dev, "Failed to read DSPCLK: %d\n", dspclk); |
@@ -2871,6 +2897,8 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2871 | /* VMID 2*50k */ | 2897 | /* VMID 2*50k */ |
2872 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, | 2898 | snd_soc_update_bits(codec, WM8962_PWR_MGMT_1, |
2873 | WM8962_VMID_SEL_MASK, 0x80); | 2899 | WM8962_VMID_SEL_MASK, 0x80); |
2900 | |||
2901 | wm8962_configure_bclk(codec); | ||
2874 | break; | 2902 | break; |
2875 | 2903 | ||
2876 | case SND_SOC_BIAS_STANDBY: | 2904 | case SND_SOC_BIAS_STANDBY: |
@@ -2903,8 +2931,6 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec, | |||
2903 | snd_soc_update_bits(codec, WM8962_CLOCKING2, | 2931 | snd_soc_update_bits(codec, WM8962_CLOCKING2, |
2904 | WM8962_CLKREG_OVD, | 2932 | WM8962_CLKREG_OVD, |
2905 | WM8962_CLKREG_OVD); | 2933 | WM8962_CLKREG_OVD); |
2906 | |||
2907 | wm8962_configure_bclk(codec); | ||
2908 | } | 2934 | } |
2909 | 2935 | ||
2910 | /* VMID 2*250k */ | 2936 | /* VMID 2*250k */ |
@@ -2945,10 +2971,6 @@ static const struct { | |||
2945 | { 96000, 6 }, | 2971 | { 96000, 6 }, |
2946 | }; | 2972 | }; |
2947 | 2973 | ||
2948 | static const int sysclk_rates[] = { | ||
2949 | 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536, | ||
2950 | }; | ||
2951 | |||
2952 | static int wm8962_hw_params(struct snd_pcm_substream *substream, | 2974 | static int wm8962_hw_params(struct snd_pcm_substream *substream, |
2953 | struct snd_pcm_hw_params *params, | 2975 | struct snd_pcm_hw_params *params, |
2954 | struct snd_soc_dai *dai) | 2976 | struct snd_soc_dai *dai) |
@@ -2956,41 +2978,27 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
2956 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2978 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2957 | struct snd_soc_codec *codec = rtd->codec; | 2979 | struct snd_soc_codec *codec = rtd->codec; |
2958 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 2980 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
2959 | int rate = params_rate(params); | ||
2960 | int i; | 2981 | int i; |
2961 | int aif0 = 0; | 2982 | int aif0 = 0; |
2962 | int adctl3 = 0; | 2983 | int adctl3 = 0; |
2963 | int clocking4 = 0; | ||
2964 | 2984 | ||
2965 | wm8962->bclk = snd_soc_params_to_bclk(params); | 2985 | wm8962->bclk = snd_soc_params_to_bclk(params); |
2966 | wm8962->lrclk = params_rate(params); | 2986 | wm8962->lrclk = params_rate(params); |
2967 | 2987 | ||
2968 | for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { | 2988 | for (i = 0; i < ARRAY_SIZE(sr_vals); i++) { |
2969 | if (sr_vals[i].rate == rate) { | 2989 | if (sr_vals[i].rate == wm8962->lrclk) { |
2970 | adctl3 |= sr_vals[i].reg; | 2990 | adctl3 |= sr_vals[i].reg; |
2971 | break; | 2991 | break; |
2972 | } | 2992 | } |
2973 | } | 2993 | } |
2974 | if (i == ARRAY_SIZE(sr_vals)) { | 2994 | if (i == ARRAY_SIZE(sr_vals)) { |
2975 | dev_err(codec->dev, "Unsupported rate %dHz\n", rate); | 2995 | dev_err(codec->dev, "Unsupported rate %dHz\n", wm8962->lrclk); |
2976 | return -EINVAL; | 2996 | return -EINVAL; |
2977 | } | 2997 | } |
2978 | 2998 | ||
2979 | if (rate % 8000 == 0) | 2999 | if (wm8962->lrclk % 8000 == 0) |
2980 | adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; | 3000 | adctl3 |= WM8962_SAMPLE_RATE_INT_MODE; |
2981 | 3001 | ||
2982 | for (i = 0; i < ARRAY_SIZE(sysclk_rates); i++) { | ||
2983 | if (sysclk_rates[i] == wm8962->sysclk_rate / rate) { | ||
2984 | clocking4 |= i << WM8962_SYSCLK_RATE_SHIFT; | ||
2985 | break; | ||
2986 | } | ||
2987 | } | ||
2988 | if (i == ARRAY_SIZE(sysclk_rates)) { | ||
2989 | dev_err(codec->dev, "Unsupported sysclk ratio %d\n", | ||
2990 | wm8962->sysclk_rate / rate); | ||
2991 | return -EINVAL; | ||
2992 | } | ||
2993 | |||
2994 | switch (params_format(params)) { | 3002 | switch (params_format(params)) { |
2995 | case SNDRV_PCM_FORMAT_S16_LE: | 3003 | case SNDRV_PCM_FORMAT_S16_LE: |
2996 | break; | 3004 | break; |
@@ -3012,8 +3020,6 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
3012 | snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, | 3020 | snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_3, |
3013 | WM8962_SAMPLE_RATE_INT_MODE | | 3021 | WM8962_SAMPLE_RATE_INT_MODE | |
3014 | WM8962_SAMPLE_RATE_MASK, adctl3); | 3022 | WM8962_SAMPLE_RATE_MASK, adctl3); |
3015 | snd_soc_update_bits(codec, WM8962_CLOCKING_4, | ||
3016 | WM8962_SYSCLK_RATE_MASK, clocking4); | ||
3017 | 3023 | ||
3018 | wm8962_configure_bclk(codec); | 3024 | wm8962_configure_bclk(codec); |
3019 | 3025 | ||