aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8994.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r--sound/soc/codecs/wm8994.c148
1 files changed, 130 insertions, 18 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 83014a7c2e14..09e680ae88b2 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -195,10 +195,6 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
195 aif + 1, rate); 195 aif + 1, rate);
196 } 196 }
197 197
198 if (rate && rate < 3000000)
199 dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n",
200 aif + 1, rate);
201
202 wm8994->aifclk[aif] = rate; 198 wm8994->aifclk[aif] = rate;
203 199
204 snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset, 200 snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
@@ -1146,13 +1142,33 @@ SND_SOC_DAPM_PGA_E("Late DAC2L Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1146 late_enable_ev, SND_SOC_DAPM_PRE_PMU), 1142 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1147SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, 1143SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
1148 late_enable_ev, SND_SOC_DAPM_PRE_PMU), 1144 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1145SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0,
1146 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1147
1148SND_SOC_DAPM_MIXER_E("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
1149 left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer),
1150 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1151SND_SOC_DAPM_MIXER_E("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
1152 right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer),
1153 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1154SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux,
1155 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1156SND_SOC_DAPM_MUX_E("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux,
1157 late_enable_ev, SND_SOC_DAPM_PRE_PMU),
1149 1158
1150SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) 1159SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev)
1151}; 1160};
1152 1161
1153static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { 1162static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = {
1154SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), 1163SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0),
1155SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) 1164SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0),
1165SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0),
1166SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
1167 left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
1168SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
1169 right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
1170SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
1171SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
1156}; 1172};
1157 1173
1158static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { 1174static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = {
@@ -1282,14 +1298,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0),
1282SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), 1298SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0),
1283SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), 1299SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0),
1284 1300
1285SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux),
1286SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux),
1287
1288SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0,
1289 left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)),
1290SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0,
1291 right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)),
1292
1293SND_SOC_DAPM_POST("Debug log", post_ev), 1301SND_SOC_DAPM_POST("Debug log", post_ev),
1294}; 1302};
1295 1303
@@ -1624,6 +1632,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1624 int reg_offset, ret; 1632 int reg_offset, ret;
1625 struct fll_div fll; 1633 struct fll_div fll;
1626 u16 reg, aif1, aif2; 1634 u16 reg, aif1, aif2;
1635 unsigned long timeout;
1627 1636
1628 aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) 1637 aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1)
1629 & WM8994_AIF1CLK_ENA; 1638 & WM8994_AIF1CLK_ENA;
@@ -1705,6 +1714,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1705 (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | 1714 (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
1706 (src - 1)); 1715 (src - 1));
1707 1716
1717 /* Clear any pending completion from a previous failure */
1718 try_wait_for_completion(&wm8994->fll_locked[id]);
1719
1708 /* Enable (with fractional mode if required) */ 1720 /* Enable (with fractional mode if required) */
1709 if (freq_out) { 1721 if (freq_out) {
1710 if (fll.k) 1722 if (fll.k)
@@ -1715,7 +1727,15 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1715 WM8994_FLL1_ENA | WM8994_FLL1_FRAC, 1727 WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
1716 reg); 1728 reg);
1717 1729
1718 msleep(5); 1730 if (wm8994->fll_locked_irq) {
1731 timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
1732 msecs_to_jiffies(10));
1733 if (timeout == 0)
1734 dev_warn(codec->dev,
1735 "Timed out waiting for FLL lock\n");
1736 } else {
1737 msleep(5);
1738 }
1719 } 1739 }
1720 1740
1721 wm8994->fll[id].in = freq_in; 1741 wm8994->fll[id].in = freq_in;
@@ -1733,6 +1753,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
1733 return 0; 1753 return 0;
1734} 1754}
1735 1755
1756static irqreturn_t wm8994_fll_locked_irq(int irq, void *data)
1757{
1758 struct completion *completion = data;
1759
1760 complete(completion);
1761
1762 return IRQ_HANDLED;
1763}
1736 1764
1737static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; 1765static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 };
1738 1766
@@ -2272,6 +2300,33 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
2272 return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1); 2300 return snd_soc_update_bits(codec, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
2273} 2301}
2274 2302
2303static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
2304 struct snd_soc_dai *dai)
2305{
2306 struct snd_soc_codec *codec = dai->codec;
2307 int rate_reg = 0;
2308
2309 switch (dai->id) {
2310 case 1:
2311 rate_reg = WM8994_AIF1_RATE;
2312 break;
2313 case 2:
2314 rate_reg = WM8994_AIF1_RATE;
2315 break;
2316 default:
2317 break;
2318 }
2319
2320 /* If the DAI is idle then configure the divider tree for the
2321 * lowest output rate to save a little power if the clock is
2322 * still active (eg, because it is system clock).
2323 */
2324 if (rate_reg && !dai->playback_active && !dai->capture_active)
2325 snd_soc_update_bits(codec, rate_reg,
2326 WM8994_AIF1_SR_MASK |
2327 WM8994_AIF1CLK_RATE_MASK, 0x9);
2328}
2329
2275static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) 2330static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
2276{ 2331{
2277 struct snd_soc_codec *codec = codec_dai->codec; 2332 struct snd_soc_codec *codec = codec_dai->codec;
@@ -2338,6 +2393,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
2338 .set_sysclk = wm8994_set_dai_sysclk, 2393 .set_sysclk = wm8994_set_dai_sysclk,
2339 .set_fmt = wm8994_set_dai_fmt, 2394 .set_fmt = wm8994_set_dai_fmt,
2340 .hw_params = wm8994_hw_params, 2395 .hw_params = wm8994_hw_params,
2396 .shutdown = wm8994_aif_shutdown,
2341 .digital_mute = wm8994_aif_mute, 2397 .digital_mute = wm8994_aif_mute,
2342 .set_pll = wm8994_set_fll, 2398 .set_pll = wm8994_set_fll,
2343 .set_tristate = wm8994_set_tristate, 2399 .set_tristate = wm8994_set_tristate,
@@ -2347,6 +2403,7 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
2347 .set_sysclk = wm8994_set_dai_sysclk, 2403 .set_sysclk = wm8994_set_dai_sysclk,
2348 .set_fmt = wm8994_set_dai_fmt, 2404 .set_fmt = wm8994_set_dai_fmt,
2349 .hw_params = wm8994_hw_params, 2405 .hw_params = wm8994_hw_params,
2406 .shutdown = wm8994_aif_shutdown,
2350 .digital_mute = wm8994_aif_mute, 2407 .digital_mute = wm8994_aif_mute,
2351 .set_pll = wm8994_set_fll, 2408 .set_pll = wm8994_set_fll,
2352 .set_tristate = wm8994_set_tristate, 2409 .set_tristate = wm8994_set_tristate,
@@ -2850,6 +2907,15 @@ out:
2850 return IRQ_HANDLED; 2907 return IRQ_HANDLED;
2851} 2908}
2852 2909
2910static irqreturn_t wm8994_fifo_error(int irq, void *data)
2911{
2912 struct snd_soc_codec *codec = data;
2913
2914 dev_err(codec->dev, "FIFO error\n");
2915
2916 return IRQ_HANDLED;
2917}
2918
2853static int wm8994_codec_probe(struct snd_soc_codec *codec) 2919static int wm8994_codec_probe(struct snd_soc_codec *codec)
2854{ 2920{
2855 struct wm8994 *control; 2921 struct wm8994 *control;
@@ -2868,6 +2934,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2868 wm8994->pdata = dev_get_platdata(codec->dev->parent); 2934 wm8994->pdata = dev_get_platdata(codec->dev->parent);
2869 wm8994->codec = codec; 2935 wm8994->codec = codec;
2870 2936
2937 for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
2938 init_completion(&wm8994->fll_locked[i]);
2939
2871 if (wm8994->pdata && wm8994->pdata->micdet_irq) 2940 if (wm8994->pdata && wm8994->pdata->micdet_irq)
2872 wm8994->micdet_irq = wm8994->pdata->micdet_irq; 2941 wm8994->micdet_irq = wm8994->pdata->micdet_irq;
2873 else if (wm8994->pdata && wm8994->pdata->irq_base) 2942 else if (wm8994->pdata && wm8994->pdata->irq_base)
@@ -2906,6 +2975,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2906 wm8994->hubs.dcs_codes = -5; 2975 wm8994->hubs.dcs_codes = -5;
2907 wm8994->hubs.hp_startup_mode = 1; 2976 wm8994->hubs.hp_startup_mode = 1;
2908 wm8994->hubs.dcs_readback_mode = 1; 2977 wm8994->hubs.dcs_readback_mode = 1;
2978 wm8994->hubs.series_startup = 1;
2909 break; 2979 break;
2910 default: 2980 default:
2911 wm8994->hubs.dcs_readback_mode = 1; 2981 wm8994->hubs.dcs_readback_mode = 1;
@@ -2920,6 +2990,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2920 break; 2990 break;
2921 } 2991 }
2922 2992
2993 wm8994_request_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR,
2994 wm8994_fifo_error, "FIFO error", codec);
2995
2996 ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
2997 wm_hubs_dcs_done, "DC servo done",
2998 &wm8994->hubs);
2999 if (ret == 0)
3000 wm8994->hubs.dcs_done_irq = true;
3001
2923 switch (control->type) { 3002 switch (control->type) {
2924 case WM8994: 3003 case WM8994:
2925 if (wm8994->micdet_irq) { 3004 if (wm8994->micdet_irq) {
@@ -2976,6 +3055,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
2976 } 3055 }
2977 } 3056 }
2978 3057
3058 wm8994->fll_locked_irq = true;
3059 for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) {
3060 ret = wm8994_request_irq(codec->control_data,
3061 WM8994_IRQ_FLL1_LOCK + i,
3062 wm8994_fll_locked_irq, "FLL lock",
3063 &wm8994->fll_locked[i]);
3064 if (ret != 0)
3065 wm8994->fll_locked_irq = false;
3066 }
3067
2979 /* Remember if AIFnLRCLK is configured as a GPIO. This should be 3068 /* Remember if AIFnLRCLK is configured as a GPIO. This should be
2980 * configured on init - if a system wants to do this dynamically 3069 * configured on init - if a system wants to do this dynamically
2981 * at runtime we can deal with that then. 3070 * at runtime we can deal with that then.
@@ -3051,10 +3140,18 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
3051 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, 3140 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT,
3052 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); 3141 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT);
3053 3142
3054 /* Unconditionally enable AIF1 ADC TDM mode; it only affects 3143 /* Unconditionally enable AIF1 ADC TDM mode on chips which can
3055 * behaviour on idle TDM clock cycles. */ 3144 * use this; it only affects behaviour on idle TDM clock
3056 snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, 3145 * cycles. */
3057 WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); 3146 switch (control->type) {
3147 case WM8994:
3148 case WM8958:
3149 snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1,
3150 WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM);
3151 break;
3152 default:
3153 break;
3154 }
3058 3155
3059 wm8994_update_class_w(codec); 3156 wm8994_update_class_w(codec);
3060 3157
@@ -3153,6 +3250,12 @@ err_irq:
3153 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); 3250 wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
3154 if (wm8994->micdet_irq) 3251 if (wm8994->micdet_irq)
3155 free_irq(wm8994->micdet_irq, wm8994); 3252 free_irq(wm8994->micdet_irq, wm8994);
3253 for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
3254 wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
3255 &wm8994->fll_locked[i]);
3256 wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
3257 &wm8994->hubs);
3258 wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
3156err: 3259err:
3157 kfree(wm8994); 3260 kfree(wm8994);
3158 return ret; 3261 return ret;
@@ -3162,11 +3265,20 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
3162{ 3265{
3163 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); 3266 struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
3164 struct wm8994 *control = codec->control_data; 3267 struct wm8994 *control = codec->control_data;
3268 int i;
3165 3269
3166 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); 3270 wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
3167 3271
3168 pm_runtime_disable(codec->dev); 3272 pm_runtime_disable(codec->dev);
3169 3273
3274 for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
3275 wm8994_free_irq(codec->control_data, WM8994_IRQ_FLL1_LOCK + i,
3276 &wm8994->fll_locked[i]);
3277
3278 wm8994_free_irq(codec->control_data, WM8994_IRQ_DCS_DONE,
3279 &wm8994->hubs);
3280 wm8994_free_irq(codec->control_data, WM8994_IRQ_FIFOS_ERR, codec);
3281
3170 switch (control->type) { 3282 switch (control->type) {
3171 case WM8994: 3283 case WM8994:
3172 if (wm8994->micdet_irq) 3284 if (wm8994->micdet_irq)