diff options
author | Mark Brown <broonie@linaro.org> | 2013-06-17 12:20:32 -0400 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2013-06-17 12:20:32 -0400 |
commit | 5464389755b78e235c999c2dcf58718d23326d46 (patch) | |
tree | a21c3bb7c2fdc087a3c30735ebfc481fc5798a0e | |
parent | f57019aa0a796251e671882004dd58d2cc55f8f1 (diff) | |
parent | 2da1c4bf765cb32024e5db6fa75dab92916fa3b1 (diff) |
Merge remote-tracking branch 'asoc/topic/wm8994' into asoc-next
-rw-r--r-- | include/linux/mfd/wm8994/pdata.h | 5 | ||||
-rw-r--r-- | include/linux/mfd/wm8994/registers.h | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 188 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.h | 3 |
4 files changed, 161 insertions, 43 deletions
diff --git a/include/linux/mfd/wm8994/pdata.h b/include/linux/mfd/wm8994/pdata.h index 68e776594889..b5046f6313a9 100644 --- a/include/linux/mfd/wm8994/pdata.h +++ b/include/linux/mfd/wm8994/pdata.h | |||
@@ -182,6 +182,11 @@ struct wm8994_pdata { | |||
182 | */ | 182 | */ |
183 | int micdet_delay; | 183 | int micdet_delay; |
184 | 184 | ||
185 | /* Delay between microphone detect completing and reporting on | ||
186 | * insert (specified in ms) | ||
187 | */ | ||
188 | int mic_id_delay; | ||
189 | |||
185 | /* IRQ for microphone detection if brought out directly as a | 190 | /* IRQ for microphone detection if brought out directly as a |
186 | * signal. | 191 | * signal. |
187 | */ | 192 | */ |
diff --git a/include/linux/mfd/wm8994/registers.h b/include/linux/mfd/wm8994/registers.h index 053548961c15..db8cef3d5321 100644 --- a/include/linux/mfd/wm8994/registers.h +++ b/include/linux/mfd/wm8994/registers.h | |||
@@ -2668,6 +2668,10 @@ | |||
2668 | /* | 2668 | /* |
2669 | * R772 (0x304) - AIF1ADC LRCLK | 2669 | * R772 (0x304) - AIF1ADC LRCLK |
2670 | */ | 2670 | */ |
2671 | #define WM8958_AIF1_LRCLK_INV 0x1000 /* AIF1_LRCLK_INV */ | ||
2672 | #define WM8958_AIF1_LRCLK_INV_MASK 0x1000 /* AIF1_LRCLK_INV */ | ||
2673 | #define WM8958_AIF1_LRCLK_INV_SHIFT 12 /* AIF1_LRCLK_INV */ | ||
2674 | #define WM8958_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */ | ||
2671 | #define WM8994_AIF1ADC_LRCLK_DIR 0x0800 /* AIF1ADC_LRCLK_DIR */ | 2675 | #define WM8994_AIF1ADC_LRCLK_DIR 0x0800 /* AIF1ADC_LRCLK_DIR */ |
2672 | #define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800 /* AIF1ADC_LRCLK_DIR */ | 2676 | #define WM8994_AIF1ADC_LRCLK_DIR_MASK 0x0800 /* AIF1ADC_LRCLK_DIR */ |
2673 | #define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11 /* AIF1ADC_LRCLK_DIR */ | 2677 | #define WM8994_AIF1ADC_LRCLK_DIR_SHIFT 11 /* AIF1ADC_LRCLK_DIR */ |
@@ -2679,6 +2683,10 @@ | |||
2679 | /* | 2683 | /* |
2680 | * R773 (0x305) - AIF1DAC LRCLK | 2684 | * R773 (0x305) - AIF1DAC LRCLK |
2681 | */ | 2685 | */ |
2686 | #define WM8958_AIF1_LRCLK_INV 0x1000 /* AIF1_LRCLK_INV */ | ||
2687 | #define WM8958_AIF1_LRCLK_INV_MASK 0x1000 /* AIF1_LRCLK_INV */ | ||
2688 | #define WM8958_AIF1_LRCLK_INV_SHIFT 12 /* AIF1_LRCLK_INV */ | ||
2689 | #define WM8958_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */ | ||
2682 | #define WM8994_AIF1DAC_LRCLK_DIR 0x0800 /* AIF1DAC_LRCLK_DIR */ | 2690 | #define WM8994_AIF1DAC_LRCLK_DIR 0x0800 /* AIF1DAC_LRCLK_DIR */ |
2683 | #define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800 /* AIF1DAC_LRCLK_DIR */ | 2691 | #define WM8994_AIF1DAC_LRCLK_DIR_MASK 0x0800 /* AIF1DAC_LRCLK_DIR */ |
2684 | #define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11 /* AIF1DAC_LRCLK_DIR */ | 2692 | #define WM8994_AIF1DAC_LRCLK_DIR_SHIFT 11 /* AIF1DAC_LRCLK_DIR */ |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 29e95f93d482..25580b5a853f 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/gcd.h> | ||
19 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <linux/pm_runtime.h> | 22 | #include <linux/pm_runtime.h> |
@@ -1498,6 +1499,24 @@ static const char *aif1dac_text[] = { | |||
1498 | "AIF1DACDAT", "AIF3DACDAT", | 1499 | "AIF1DACDAT", "AIF3DACDAT", |
1499 | }; | 1500 | }; |
1500 | 1501 | ||
1502 | static const char *loopback_text[] = { | ||
1503 | "None", "ADCDAT", | ||
1504 | }; | ||
1505 | |||
1506 | static const struct soc_enum aif1_loopback_enum = | ||
1507 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, | ||
1508 | loopback_text); | ||
1509 | |||
1510 | static const struct snd_kcontrol_new aif1_loopback = | ||
1511 | SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); | ||
1512 | |||
1513 | static const struct soc_enum aif2_loopback_enum = | ||
1514 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, | ||
1515 | loopback_text); | ||
1516 | |||
1517 | static const struct snd_kcontrol_new aif2_loopback = | ||
1518 | SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); | ||
1519 | |||
1501 | static const struct soc_enum aif1dac_enum = | 1520 | static const struct soc_enum aif1dac_enum = |
1502 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); | 1521 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); |
1503 | 1522 | ||
@@ -1744,6 +1763,9 @@ SND_SOC_DAPM_ADC("DMIC1R", NULL, WM8994_POWER_MANAGEMENT_4, 2, 0), | |||
1744 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), | 1763 | SND_SOC_DAPM_ADC("ADCL", NULL, SND_SOC_NOPM, 1, 0), |
1745 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), | 1764 | SND_SOC_DAPM_ADC("ADCR", NULL, SND_SOC_NOPM, 0, 0), |
1746 | 1765 | ||
1766 | SND_SOC_DAPM_MUX("AIF1 Loopback", SND_SOC_NOPM, 0, 0, &aif1_loopback), | ||
1767 | SND_SOC_DAPM_MUX("AIF2 Loopback", SND_SOC_NOPM, 0, 0, &aif2_loopback), | ||
1768 | |||
1747 | SND_SOC_DAPM_POST("Debug log", post_ev), | 1769 | SND_SOC_DAPM_POST("Debug log", post_ev), |
1748 | }; | 1770 | }; |
1749 | 1771 | ||
@@ -1875,9 +1897,9 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1875 | { "AIF1DAC2L", NULL, "AIF1DAC Mux" }, | 1897 | { "AIF1DAC2L", NULL, "AIF1DAC Mux" }, |
1876 | { "AIF1DAC2R", NULL, "AIF1DAC Mux" }, | 1898 | { "AIF1DAC2R", NULL, "AIF1DAC Mux" }, |
1877 | 1899 | ||
1878 | { "AIF1DAC Mux", "AIF1DACDAT", "AIF1DACDAT" }, | 1900 | { "AIF1DAC Mux", "AIF1DACDAT", "AIF1 Loopback" }, |
1879 | { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, | 1901 | { "AIF1DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, |
1880 | { "AIF2DAC Mux", "AIF2DACDAT", "AIF2DACDAT" }, | 1902 | { "AIF2DAC Mux", "AIF2DACDAT", "AIF2 Loopback" }, |
1881 | { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, | 1903 | { "AIF2DAC Mux", "AIF3DACDAT", "AIF3DACDAT" }, |
1882 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, | 1904 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCL" }, |
1883 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, | 1905 | { "AIF2ADC Mux", "AIF2ADCDAT", "AIF2ADCR" }, |
@@ -1928,6 +1950,12 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1928 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, | 1950 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACL" }, |
1929 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, | 1951 | { "AIF3ADCDAT", "AIF2DACDAT", "AIF2DACR" }, |
1930 | 1952 | ||
1953 | /* Loopback */ | ||
1954 | { "AIF1 Loopback", "ADCDAT", "AIF1ADCDAT" }, | ||
1955 | { "AIF1 Loopback", "None", "AIF1DACDAT" }, | ||
1956 | { "AIF2 Loopback", "ADCDAT", "AIF2ADCDAT" }, | ||
1957 | { "AIF2 Loopback", "None", "AIF2DACDAT" }, | ||
1958 | |||
1931 | /* Sidetone */ | 1959 | /* Sidetone */ |
1932 | { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, | 1960 | { "Left Sidetone", "ADC/DMIC1", "ADCL Mux" }, |
1933 | { "Left Sidetone", "DMIC2", "DMIC2L" }, | 1961 | { "Left Sidetone", "DMIC2", "DMIC2L" }, |
@@ -2010,15 +2038,16 @@ struct fll_div { | |||
2010 | u16 outdiv; | 2038 | u16 outdiv; |
2011 | u16 n; | 2039 | u16 n; |
2012 | u16 k; | 2040 | u16 k; |
2041 | u16 lambda; | ||
2013 | u16 clk_ref_div; | 2042 | u16 clk_ref_div; |
2014 | u16 fll_fratio; | 2043 | u16 fll_fratio; |
2015 | }; | 2044 | }; |
2016 | 2045 | ||
2017 | static int wm8994_get_fll_config(struct fll_div *fll, | 2046 | static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll, |
2018 | int freq_in, int freq_out) | 2047 | int freq_in, int freq_out) |
2019 | { | 2048 | { |
2020 | u64 Kpart; | 2049 | u64 Kpart; |
2021 | unsigned int K, Ndiv, Nmod; | 2050 | unsigned int K, Ndiv, Nmod, gcd_fll; |
2022 | 2051 | ||
2023 | pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); | 2052 | pr_debug("FLL input=%dHz, output=%dHz\n", freq_in, freq_out); |
2024 | 2053 | ||
@@ -2067,20 +2096,32 @@ static int wm8994_get_fll_config(struct fll_div *fll, | |||
2067 | Nmod = freq_out % freq_in; | 2096 | Nmod = freq_out % freq_in; |
2068 | pr_debug("Nmod=%d\n", Nmod); | 2097 | pr_debug("Nmod=%d\n", Nmod); |
2069 | 2098 | ||
2070 | /* Calculate fractional part - scale up so we can round. */ | 2099 | switch (control->type) { |
2071 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | 2100 | case WM8994: |
2101 | /* Calculate fractional part - scale up so we can round. */ | ||
2102 | Kpart = FIXED_FLL_SIZE * (long long)Nmod; | ||
2103 | |||
2104 | do_div(Kpart, freq_in); | ||
2105 | |||
2106 | K = Kpart & 0xFFFFFFFF; | ||
2072 | 2107 | ||
2073 | do_div(Kpart, freq_in); | 2108 | if ((K % 10) >= 5) |
2109 | K += 5; | ||
2074 | 2110 | ||
2075 | K = Kpart & 0xFFFFFFFF; | 2111 | /* Move down to proper range now rounding is done */ |
2112 | fll->k = K / 10; | ||
2113 | fll->lambda = 0; | ||
2076 | 2114 | ||
2077 | if ((K % 10) >= 5) | 2115 | pr_debug("N=%x K=%x\n", fll->n, fll->k); |
2078 | K += 5; | 2116 | break; |
2079 | 2117 | ||
2080 | /* Move down to proper range now rounding is done */ | 2118 | default: |
2081 | fll->k = K / 10; | 2119 | gcd_fll = gcd(freq_out, freq_in); |
2082 | 2120 | ||
2083 | pr_debug("N=%x K=%x\n", fll->n, fll->k); | 2121 | fll->k = (freq_out - (freq_in * fll->n)) / gcd_fll; |
2122 | fll->lambda = freq_in / gcd_fll; | ||
2123 | |||
2124 | } | ||
2084 | 2125 | ||
2085 | return 0; | 2126 | return 0; |
2086 | } | 2127 | } |
@@ -2144,9 +2185,9 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
2144 | * analysis bugs spewing warnings. | 2185 | * analysis bugs spewing warnings. |
2145 | */ | 2186 | */ |
2146 | if (freq_out) | 2187 | if (freq_out) |
2147 | ret = wm8994_get_fll_config(&fll, freq_in, freq_out); | 2188 | ret = wm8994_get_fll_config(control, &fll, freq_in, freq_out); |
2148 | else | 2189 | else |
2149 | ret = wm8994_get_fll_config(&fll, wm8994->fll[id].in, | 2190 | ret = wm8994_get_fll_config(control, &fll, wm8994->fll[id].in, |
2150 | wm8994->fll[id].out); | 2191 | wm8994->fll[id].out); |
2151 | if (ret < 0) | 2192 | if (ret < 0) |
2152 | return ret; | 2193 | return ret; |
@@ -2191,6 +2232,17 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src, | |||
2191 | WM8994_FLL1_N_MASK, | 2232 | WM8994_FLL1_N_MASK, |
2192 | fll.n << WM8994_FLL1_N_SHIFT); | 2233 | fll.n << WM8994_FLL1_N_SHIFT); |
2193 | 2234 | ||
2235 | if (fll.lambda) { | ||
2236 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_1 + reg_offset, | ||
2237 | WM8958_FLL1_LAMBDA_MASK, | ||
2238 | fll.lambda); | ||
2239 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset, | ||
2240 | WM8958_FLL1_EFS_ENA, WM8958_FLL1_EFS_ENA); | ||
2241 | } else { | ||
2242 | snd_soc_update_bits(codec, WM8958_FLL1_EFS_2 + reg_offset, | ||
2243 | WM8958_FLL1_EFS_ENA, 0); | ||
2244 | } | ||
2245 | |||
2194 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, | 2246 | snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset, |
2195 | WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | | 2247 | WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP | |
2196 | WM8994_FLL1_REFCLK_DIV_MASK | | 2248 | WM8994_FLL1_REFCLK_DIV_MASK | |
@@ -2555,17 +2607,24 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
2555 | struct wm8994 *control = wm8994->wm8994; | 2607 | struct wm8994 *control = wm8994->wm8994; |
2556 | int ms_reg; | 2608 | int ms_reg; |
2557 | int aif1_reg; | 2609 | int aif1_reg; |
2610 | int dac_reg; | ||
2611 | int adc_reg; | ||
2558 | int ms = 0; | 2612 | int ms = 0; |
2559 | int aif1 = 0; | 2613 | int aif1 = 0; |
2614 | int lrclk = 0; | ||
2560 | 2615 | ||
2561 | switch (dai->id) { | 2616 | switch (dai->id) { |
2562 | case 1: | 2617 | case 1: |
2563 | ms_reg = WM8994_AIF1_MASTER_SLAVE; | 2618 | ms_reg = WM8994_AIF1_MASTER_SLAVE; |
2564 | aif1_reg = WM8994_AIF1_CONTROL_1; | 2619 | aif1_reg = WM8994_AIF1_CONTROL_1; |
2620 | dac_reg = WM8994_AIF1DAC_LRCLK; | ||
2621 | adc_reg = WM8994_AIF1ADC_LRCLK; | ||
2565 | break; | 2622 | break; |
2566 | case 2: | 2623 | case 2: |
2567 | ms_reg = WM8994_AIF2_MASTER_SLAVE; | 2624 | ms_reg = WM8994_AIF2_MASTER_SLAVE; |
2568 | aif1_reg = WM8994_AIF2_CONTROL_1; | 2625 | aif1_reg = WM8994_AIF2_CONTROL_1; |
2626 | dac_reg = WM8994_AIF1DAC_LRCLK; | ||
2627 | adc_reg = WM8994_AIF1ADC_LRCLK; | ||
2569 | break; | 2628 | break; |
2570 | default: | 2629 | default: |
2571 | return -EINVAL; | 2630 | return -EINVAL; |
@@ -2584,6 +2643,7 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
2584 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 2643 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
2585 | case SND_SOC_DAIFMT_DSP_B: | 2644 | case SND_SOC_DAIFMT_DSP_B: |
2586 | aif1 |= WM8994_AIF1_LRCLK_INV; | 2645 | aif1 |= WM8994_AIF1_LRCLK_INV; |
2646 | lrclk |= WM8958_AIF1_LRCLK_INV; | ||
2587 | case SND_SOC_DAIFMT_DSP_A: | 2647 | case SND_SOC_DAIFMT_DSP_A: |
2588 | aif1 |= 0x18; | 2648 | aif1 |= 0x18; |
2589 | break; | 2649 | break; |
@@ -2622,12 +2682,14 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
2622 | break; | 2682 | break; |
2623 | case SND_SOC_DAIFMT_IB_IF: | 2683 | case SND_SOC_DAIFMT_IB_IF: |
2624 | aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; | 2684 | aif1 |= WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV; |
2685 | lrclk |= WM8958_AIF1_LRCLK_INV; | ||
2625 | break; | 2686 | break; |
2626 | case SND_SOC_DAIFMT_IB_NF: | 2687 | case SND_SOC_DAIFMT_IB_NF: |
2627 | aif1 |= WM8994_AIF1_BCLK_INV; | 2688 | aif1 |= WM8994_AIF1_BCLK_INV; |
2628 | break; | 2689 | break; |
2629 | case SND_SOC_DAIFMT_NB_IF: | 2690 | case SND_SOC_DAIFMT_NB_IF: |
2630 | aif1 |= WM8994_AIF1_LRCLK_INV; | 2691 | aif1 |= WM8994_AIF1_LRCLK_INV; |
2692 | lrclk |= WM8958_AIF1_LRCLK_INV; | ||
2631 | break; | 2693 | break; |
2632 | default: | 2694 | default: |
2633 | return -EINVAL; | 2695 | return -EINVAL; |
@@ -2658,6 +2720,10 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
2658 | aif1); | 2720 | aif1); |
2659 | snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR, | 2721 | snd_soc_update_bits(codec, ms_reg, WM8994_AIF1_MSTR, |
2660 | ms); | 2722 | ms); |
2723 | snd_soc_update_bits(codec, dac_reg, | ||
2724 | WM8958_AIF1_LRCLK_INV, lrclk); | ||
2725 | snd_soc_update_bits(codec, adc_reg, | ||
2726 | WM8958_AIF1_LRCLK_INV, lrclk); | ||
2661 | 2727 | ||
2662 | return 0; | 2728 | return 0; |
2663 | } | 2729 | } |
@@ -3096,24 +3162,7 @@ static int wm8994_codec_suspend(struct snd_soc_codec *codec) | |||
3096 | static int wm8994_codec_resume(struct snd_soc_codec *codec) | 3162 | static int wm8994_codec_resume(struct snd_soc_codec *codec) |
3097 | { | 3163 | { |
3098 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3164 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3099 | struct wm8994 *control = wm8994->wm8994; | ||
3100 | int i, ret; | 3165 | int i, ret; |
3101 | unsigned int val, mask; | ||
3102 | |||
3103 | if (control->revision < 4) { | ||
3104 | /* force a HW read */ | ||
3105 | ret = regmap_read(control->regmap, | ||
3106 | WM8994_POWER_MANAGEMENT_5, &val); | ||
3107 | |||
3108 | /* modify the cache only */ | ||
3109 | codec->cache_only = 1; | ||
3110 | mask = WM8994_DAC1R_ENA | WM8994_DAC1L_ENA | | ||
3111 | WM8994_DAC2R_ENA | WM8994_DAC2L_ENA; | ||
3112 | val &= mask; | ||
3113 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, | ||
3114 | mask, val); | ||
3115 | codec->cache_only = 0; | ||
3116 | } | ||
3117 | 3166 | ||
3118 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { | 3167 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { |
3119 | if (!wm8994->fll_suspend[i].out) | 3168 | if (!wm8994->fll_suspend[i].out) |
@@ -3495,6 +3544,31 @@ static void wm8958_button_det(struct snd_soc_codec *codec, u16 status) | |||
3495 | wm8994->btn_mask); | 3544 | wm8994->btn_mask); |
3496 | } | 3545 | } |
3497 | 3546 | ||
3547 | static void wm8958_open_circuit_work(struct work_struct *work) | ||
3548 | { | ||
3549 | struct wm8994_priv *wm8994 = container_of(work, | ||
3550 | struct wm8994_priv, | ||
3551 | open_circuit_work.work); | ||
3552 | struct device *dev = wm8994->wm8994->dev; | ||
3553 | |||
3554 | wm1811_micd_stop(wm8994->hubs.codec); | ||
3555 | |||
3556 | mutex_lock(&wm8994->accdet_lock); | ||
3557 | |||
3558 | dev_dbg(dev, "Reporting open circuit\n"); | ||
3559 | |||
3560 | wm8994->jack_mic = false; | ||
3561 | wm8994->mic_detecting = true; | ||
3562 | |||
3563 | wm8958_micd_set_rate(wm8994->hubs.codec); | ||
3564 | |||
3565 | snd_soc_jack_report(wm8994->micdet[0].jack, 0, | ||
3566 | wm8994->btn_mask | | ||
3567 | SND_JACK_HEADSET); | ||
3568 | |||
3569 | mutex_unlock(&wm8994->accdet_lock); | ||
3570 | } | ||
3571 | |||
3498 | static void wm8958_mic_id(void *data, u16 status) | 3572 | static void wm8958_mic_id(void *data, u16 status) |
3499 | { | 3573 | { |
3500 | struct snd_soc_codec *codec = data; | 3574 | struct snd_soc_codec *codec = data; |
@@ -3504,16 +3578,9 @@ static void wm8958_mic_id(void *data, u16 status) | |||
3504 | if (!(status & WM8958_MICD_STS)) { | 3578 | if (!(status & WM8958_MICD_STS)) { |
3505 | /* If nothing present then clear our statuses */ | 3579 | /* If nothing present then clear our statuses */ |
3506 | dev_dbg(codec->dev, "Detected open circuit\n"); | 3580 | dev_dbg(codec->dev, "Detected open circuit\n"); |
3507 | wm8994->jack_mic = false; | ||
3508 | wm8994->mic_detecting = true; | ||
3509 | |||
3510 | wm1811_micd_stop(codec); | ||
3511 | |||
3512 | wm8958_micd_set_rate(codec); | ||
3513 | 3581 | ||
3514 | snd_soc_jack_report(wm8994->micdet[0].jack, 0, | 3582 | schedule_delayed_work(&wm8994->open_circuit_work, |
3515 | wm8994->btn_mask | | 3583 | msecs_to_jiffies(2500)); |
3516 | SND_JACK_HEADSET); | ||
3517 | return; | 3584 | return; |
3518 | } | 3585 | } |
3519 | 3586 | ||
@@ -3598,6 +3665,8 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data) | |||
3598 | 3665 | ||
3599 | pm_runtime_get_sync(codec->dev); | 3666 | pm_runtime_get_sync(codec->dev); |
3600 | 3667 | ||
3668 | cancel_delayed_work_sync(&wm8994->mic_complete_work); | ||
3669 | |||
3601 | mutex_lock(&wm8994->accdet_lock); | 3670 | mutex_lock(&wm8994->accdet_lock); |
3602 | 3671 | ||
3603 | reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); | 3672 | reg = snd_soc_read(codec, WM1811_JACKDET_CTRL); |
@@ -3780,11 +3849,33 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
3780 | } | 3849 | } |
3781 | EXPORT_SYMBOL_GPL(wm8958_mic_detect); | 3850 | EXPORT_SYMBOL_GPL(wm8958_mic_detect); |
3782 | 3851 | ||
3852 | static void wm8958_mic_work(struct work_struct *work) | ||
3853 | { | ||
3854 | struct wm8994_priv *wm8994 = container_of(work, | ||
3855 | struct wm8994_priv, | ||
3856 | mic_complete_work.work); | ||
3857 | struct snd_soc_codec *codec = wm8994->hubs.codec; | ||
3858 | |||
3859 | dev_crit(codec->dev, "MIC WORK %x\n", wm8994->mic_status); | ||
3860 | |||
3861 | pm_runtime_get_sync(codec->dev); | ||
3862 | |||
3863 | mutex_lock(&wm8994->accdet_lock); | ||
3864 | |||
3865 | wm8994->mic_id_cb(wm8994->mic_id_cb_data, wm8994->mic_status); | ||
3866 | |||
3867 | mutex_unlock(&wm8994->accdet_lock); | ||
3868 | |||
3869 | pm_runtime_put(codec->dev); | ||
3870 | |||
3871 | dev_crit(codec->dev, "MIC WORK %x DONE\n", wm8994->mic_status); | ||
3872 | } | ||
3873 | |||
3783 | static irqreturn_t wm8958_mic_irq(int irq, void *data) | 3874 | static irqreturn_t wm8958_mic_irq(int irq, void *data) |
3784 | { | 3875 | { |
3785 | struct wm8994_priv *wm8994 = data; | 3876 | struct wm8994_priv *wm8994 = data; |
3786 | struct snd_soc_codec *codec = wm8994->hubs.codec; | 3877 | struct snd_soc_codec *codec = wm8994->hubs.codec; |
3787 | int reg, count, ret; | 3878 | int reg, count, ret, id_delay; |
3788 | 3879 | ||
3789 | /* | 3880 | /* |
3790 | * Jack detection may have detected a removal simulataneously | 3881 | * Jack detection may have detected a removal simulataneously |
@@ -3794,6 +3885,9 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3794 | if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) | 3885 | if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA)) |
3795 | return IRQ_HANDLED; | 3886 | return IRQ_HANDLED; |
3796 | 3887 | ||
3888 | cancel_delayed_work_sync(&wm8994->mic_complete_work); | ||
3889 | cancel_delayed_work_sync(&wm8994->open_circuit_work); | ||
3890 | |||
3797 | pm_runtime_get_sync(codec->dev); | 3891 | pm_runtime_get_sync(codec->dev); |
3798 | 3892 | ||
3799 | /* We may occasionally read a detection without an impedence | 3893 | /* We may occasionally read a detection without an impedence |
@@ -3846,8 +3940,12 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data) | |||
3846 | goto out; | 3940 | goto out; |
3847 | } | 3941 | } |
3848 | 3942 | ||
3943 | wm8994->mic_status = reg; | ||
3944 | id_delay = wm8994->wm8994->pdata.mic_id_delay; | ||
3945 | |||
3849 | if (wm8994->mic_detecting) | 3946 | if (wm8994->mic_detecting) |
3850 | wm8994->mic_id_cb(wm8994->mic_id_cb_data, reg); | 3947 | schedule_delayed_work(&wm8994->mic_complete_work, |
3948 | msecs_to_jiffies(id_delay)); | ||
3851 | else | 3949 | else |
3852 | wm8958_button_det(codec, reg); | 3950 | wm8958_button_det(codec, reg); |
3853 | 3951 | ||
@@ -3899,6 +3997,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3899 | mutex_init(&wm8994->accdet_lock); | 3997 | mutex_init(&wm8994->accdet_lock); |
3900 | INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, | 3998 | INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap, |
3901 | wm1811_jackdet_bootstrap); | 3999 | wm1811_jackdet_bootstrap); |
4000 | INIT_DELAYED_WORK(&wm8994->open_circuit_work, | ||
4001 | wm8958_open_circuit_work); | ||
3902 | 4002 | ||
3903 | switch (control->type) { | 4003 | switch (control->type) { |
3904 | case WM8994: | 4004 | case WM8994: |
@@ -3911,6 +4011,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3911 | break; | 4011 | break; |
3912 | } | 4012 | } |
3913 | 4013 | ||
4014 | INIT_DELAYED_WORK(&wm8994->mic_complete_work, wm8958_mic_work); | ||
4015 | |||
3914 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | 4016 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) |
3915 | init_completion(&wm8994->fll_locked[i]); | 4017 | init_completion(&wm8994->fll_locked[i]); |
3916 | 4018 | ||
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 55ddf4d57d9b..6536f8d45ac6 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -134,6 +134,9 @@ struct wm8994_priv { | |||
134 | struct mutex accdet_lock; | 134 | struct mutex accdet_lock; |
135 | struct wm8994_micdet micdet[2]; | 135 | struct wm8994_micdet micdet[2]; |
136 | struct delayed_work mic_work; | 136 | struct delayed_work mic_work; |
137 | struct delayed_work open_circuit_work; | ||
138 | struct delayed_work mic_complete_work; | ||
139 | u16 mic_status; | ||
137 | bool mic_detecting; | 140 | bool mic_detecting; |
138 | bool jack_mic; | 141 | bool jack_mic; |
139 | int btn_mask; | 142 | int btn_mask; |