diff options
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 157 |
1 files changed, 135 insertions, 22 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c2fc0356c2a4..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), |
1147 | SND_SOC_DAPM_PGA_E("Late DAC2R Enable PGA", SND_SOC_NOPM, 0, 0, NULL, 0, | 1143 | SND_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), |
1145 | SND_SOC_DAPM_PGA_E("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0, | ||
1146 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1147 | |||
1148 | SND_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), | ||
1151 | SND_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), | ||
1154 | SND_SOC_DAPM_MUX_E("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux, | ||
1155 | late_enable_ev, SND_SOC_DAPM_PRE_PMU), | ||
1156 | SND_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 | ||
1150 | SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) | 1159 | SND_SOC_DAPM_POST("Late Disable PGA", late_disable_ev) |
1151 | }; | 1160 | }; |
1152 | 1161 | ||
1153 | static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { | 1162 | static const struct snd_soc_dapm_widget wm8994_lateclk_widgets[] = { |
1154 | SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), | 1163 | SND_SOC_DAPM_SUPPLY("AIF1CLK", WM8994_AIF1_CLOCKING_1, 0, 0, NULL, 0), |
1155 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0) | 1164 | SND_SOC_DAPM_SUPPLY("AIF2CLK", WM8994_AIF2_CLOCKING_1, 0, 0, NULL, 0), |
1165 | SND_SOC_DAPM_PGA("Direct Voice", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1166 | SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
1167 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
1168 | SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
1169 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
1170 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
1171 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
1156 | }; | 1172 | }; |
1157 | 1173 | ||
1158 | static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { | 1174 | static const struct snd_soc_dapm_widget wm8994_dac_revd_widgets[] = { |
@@ -1190,7 +1206,6 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"), | |||
1190 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 1206 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
1191 | SND_SOC_DAPM_INPUT("Clock"), | 1207 | SND_SOC_DAPM_INPUT("Clock"), |
1192 | 1208 | ||
1193 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0), | ||
1194 | SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, | 1209 | SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, |
1195 | SND_SOC_DAPM_PRE_PMU), | 1210 | SND_SOC_DAPM_PRE_PMU), |
1196 | 1211 | ||
@@ -1283,14 +1298,6 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), | |||
1283 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), | 1298 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), |
1284 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), | 1299 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), |
1285 | 1300 | ||
1286 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
1287 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
1288 | |||
1289 | SND_SOC_DAPM_MIXER("SPKL", WM8994_POWER_MANAGEMENT_3, 8, 0, | ||
1290 | left_speaker_mixer, ARRAY_SIZE(left_speaker_mixer)), | ||
1291 | SND_SOC_DAPM_MIXER("SPKR", WM8994_POWER_MANAGEMENT_3, 9, 0, | ||
1292 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | ||
1293 | |||
1294 | SND_SOC_DAPM_POST("Debug log", post_ev), | 1301 | SND_SOC_DAPM_POST("Debug log", post_ev), |
1295 | }; | 1302 | }; |
1296 | 1303 | ||
@@ -1509,8 +1516,10 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { | |||
1509 | { "AIF2DACDAT", NULL, "AIF1DACDAT" }, | 1516 | { "AIF2DACDAT", NULL, "AIF1DACDAT" }, |
1510 | { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, | 1517 | { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, |
1511 | { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, | 1518 | { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, |
1512 | { "MICBIAS", NULL, "CLK_SYS" }, | 1519 | { "MICBIAS1", NULL, "CLK_SYS" }, |
1513 | { "MICBIAS", NULL, "MICBIAS Supply" }, | 1520 | { "MICBIAS1", NULL, "MICBIAS Supply" }, |
1521 | { "MICBIAS2", NULL, "CLK_SYS" }, | ||
1522 | { "MICBIAS2", NULL, "MICBIAS Supply" }, | ||
1514 | }; | 1523 | }; |
1515 | 1524 | ||
1516 | static const struct snd_soc_dapm_route wm8994_intercon[] = { | 1525 | static const struct snd_soc_dapm_route wm8994_intercon[] = { |
@@ -1623,6 +1632,7 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1623 | int reg_offset, ret; | 1632 | int reg_offset, ret; |
1624 | struct fll_div fll; | 1633 | struct fll_div fll; |
1625 | u16 reg, aif1, aif2; | 1634 | u16 reg, aif1, aif2; |
1635 | unsigned long timeout; | ||
1626 | 1636 | ||
1627 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) | 1637 | aif1 = snd_soc_read(codec, WM8994_AIF1_CLOCKING_1) |
1628 | & WM8994_AIF1CLK_ENA; | 1638 | & WM8994_AIF1CLK_ENA; |
@@ -1704,6 +1714,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1704 | (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | | 1714 | (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) | |
1705 | (src - 1)); | 1715 | (src - 1)); |
1706 | 1716 | ||
1717 | /* Clear any pending completion from a previous failure */ | ||
1718 | try_wait_for_completion(&wm8994->fll_locked[id]); | ||
1719 | |||
1707 | /* Enable (with fractional mode if required) */ | 1720 | /* Enable (with fractional mode if required) */ |
1708 | if (freq_out) { | 1721 | if (freq_out) { |
1709 | if (fll.k) | 1722 | if (fll.k) |
@@ -1714,7 +1727,15 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1714 | WM8994_FLL1_ENA | WM8994_FLL1_FRAC, | 1727 | WM8994_FLL1_ENA | WM8994_FLL1_FRAC, |
1715 | reg); | 1728 | reg); |
1716 | 1729 | ||
1717 | 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 | } | ||
1718 | } | 1739 | } |
1719 | 1740 | ||
1720 | wm8994->fll[id].in = freq_in; | 1741 | wm8994->fll[id].in = freq_in; |
@@ -1732,6 +1753,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
1732 | return 0; | 1753 | return 0; |
1733 | } | 1754 | } |
1734 | 1755 | ||
1756 | static 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 | } | ||
1735 | 1764 | ||
1736 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | 1765 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; |
1737 | 1766 | ||
@@ -2271,6 +2300,33 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream, | |||
2271 | 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); |
2272 | } | 2301 | } |
2273 | 2302 | ||
2303 | static 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 | |||
2274 | static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) | 2330 | static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute) |
2275 | { | 2331 | { |
2276 | struct snd_soc_codec *codec = codec_dai->codec; | 2332 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -2337,6 +2393,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = { | |||
2337 | .set_sysclk = wm8994_set_dai_sysclk, | 2393 | .set_sysclk = wm8994_set_dai_sysclk, |
2338 | .set_fmt = wm8994_set_dai_fmt, | 2394 | .set_fmt = wm8994_set_dai_fmt, |
2339 | .hw_params = wm8994_hw_params, | 2395 | .hw_params = wm8994_hw_params, |
2396 | .shutdown = wm8994_aif_shutdown, | ||
2340 | .digital_mute = wm8994_aif_mute, | 2397 | .digital_mute = wm8994_aif_mute, |
2341 | .set_pll = wm8994_set_fll, | 2398 | .set_pll = wm8994_set_fll, |
2342 | .set_tristate = wm8994_set_tristate, | 2399 | .set_tristate = wm8994_set_tristate, |
@@ -2346,6 +2403,7 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = { | |||
2346 | .set_sysclk = wm8994_set_dai_sysclk, | 2403 | .set_sysclk = wm8994_set_dai_sysclk, |
2347 | .set_fmt = wm8994_set_dai_fmt, | 2404 | .set_fmt = wm8994_set_dai_fmt, |
2348 | .hw_params = wm8994_hw_params, | 2405 | .hw_params = wm8994_hw_params, |
2406 | .shutdown = wm8994_aif_shutdown, | ||
2349 | .digital_mute = wm8994_aif_mute, | 2407 | .digital_mute = wm8994_aif_mute, |
2350 | .set_pll = wm8994_set_fll, | 2408 | .set_pll = wm8994_set_fll, |
2351 | .set_tristate = wm8994_set_tristate, | 2409 | .set_tristate = wm8994_set_tristate, |
@@ -2763,7 +2821,7 @@ static void wm8958_default_micdet(u16 status, void *data) | |||
2763 | report = SND_JACK_MICROPHONE; | 2821 | report = SND_JACK_MICROPHONE; |
2764 | 2822 | ||
2765 | /* Everything else is buttons; just assign slots */ | 2823 | /* Everything else is buttons; just assign slots */ |
2766 | if (status & 0x1c0) | 2824 | if (status & 0x1c) |
2767 | report |= SND_JACK_BTN_0; | 2825 | report |= SND_JACK_BTN_0; |
2768 | 2826 | ||
2769 | done: | 2827 | done: |
@@ -2849,6 +2907,15 @@ out: | |||
2849 | return IRQ_HANDLED; | 2907 | return IRQ_HANDLED; |
2850 | } | 2908 | } |
2851 | 2909 | ||
2910 | static 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 | |||
2852 | static int wm8994_codec_probe(struct snd_soc_codec *codec) | 2919 | static int wm8994_codec_probe(struct snd_soc_codec *codec) |
2853 | { | 2920 | { |
2854 | struct wm8994 *control; | 2921 | struct wm8994 *control; |
@@ -2867,6 +2934,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2867 | wm8994->pdata = dev_get_platdata(codec->dev->parent); | 2934 | wm8994->pdata = dev_get_platdata(codec->dev->parent); |
2868 | wm8994->codec = codec; | 2935 | wm8994->codec = codec; |
2869 | 2936 | ||
2937 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | ||
2938 | init_completion(&wm8994->fll_locked[i]); | ||
2939 | |||
2870 | if (wm8994->pdata && wm8994->pdata->micdet_irq) | 2940 | if (wm8994->pdata && wm8994->pdata->micdet_irq) |
2871 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; | 2941 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; |
2872 | else if (wm8994->pdata && wm8994->pdata->irq_base) | 2942 | else if (wm8994->pdata && wm8994->pdata->irq_base) |
@@ -2905,6 +2975,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2905 | wm8994->hubs.dcs_codes = -5; | 2975 | wm8994->hubs.dcs_codes = -5; |
2906 | wm8994->hubs.hp_startup_mode = 1; | 2976 | wm8994->hubs.hp_startup_mode = 1; |
2907 | wm8994->hubs.dcs_readback_mode = 1; | 2977 | wm8994->hubs.dcs_readback_mode = 1; |
2978 | wm8994->hubs.series_startup = 1; | ||
2908 | break; | 2979 | break; |
2909 | default: | 2980 | default: |
2910 | wm8994->hubs.dcs_readback_mode = 1; | 2981 | wm8994->hubs.dcs_readback_mode = 1; |
@@ -2919,6 +2990,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2919 | break; | 2990 | break; |
2920 | } | 2991 | } |
2921 | 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 | |||
2922 | switch (control->type) { | 3002 | switch (control->type) { |
2923 | case WM8994: | 3003 | case WM8994: |
2924 | if (wm8994->micdet_irq) { | 3004 | if (wm8994->micdet_irq) { |
@@ -2975,6 +3055,16 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
2975 | } | 3055 | } |
2976 | } | 3056 | } |
2977 | 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 | |||
2978 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be | 3068 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be |
2979 | * configured on init - if a system wants to do this dynamically | 3069 | * configured on init - if a system wants to do this dynamically |
2980 | * at runtime we can deal with that then. | 3070 | * at runtime we can deal with that then. |
@@ -3050,10 +3140,18 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3050 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | 3140 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, |
3051 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | 3141 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); |
3052 | 3142 | ||
3053 | /* Unconditionally enable AIF1 ADC TDM mode; it only affects | 3143 | /* Unconditionally enable AIF1 ADC TDM mode on chips which can |
3054 | * behaviour on idle TDM clock cycles. */ | 3144 | * use this; it only affects behaviour on idle TDM clock |
3055 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | 3145 | * cycles. */ |
3056 | 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 | } | ||
3057 | 3155 | ||
3058 | wm8994_update_class_w(codec); | 3156 | wm8994_update_class_w(codec); |
3059 | 3157 | ||
@@ -3152,6 +3250,12 @@ err_irq: | |||
3152 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); | 3250 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); |
3153 | if (wm8994->micdet_irq) | 3251 | if (wm8994->micdet_irq) |
3154 | 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); | ||
3155 | err: | 3259 | err: |
3156 | kfree(wm8994); | 3260 | kfree(wm8994); |
3157 | return ret; | 3261 | return ret; |
@@ -3161,11 +3265,20 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3161 | { | 3265 | { |
3162 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3266 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3163 | struct wm8994 *control = codec->control_data; | 3267 | struct wm8994 *control = codec->control_data; |
3268 | int i; | ||
3164 | 3269 | ||
3165 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | 3270 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); |
3166 | 3271 | ||
3167 | pm_runtime_disable(codec->dev); | 3272 | pm_runtime_disable(codec->dev); |
3168 | 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 | |||
3169 | switch (control->type) { | 3282 | switch (control->type) { |
3170 | case WM8994: | 3283 | case WM8994: |
3171 | if (wm8994->micdet_irq) | 3284 | if (wm8994->micdet_irq) |