diff options
Diffstat (limited to 'sound/soc/codecs/wm8994.c')
-rw-r--r-- | sound/soc/codecs/wm8994.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index e84a1177f350..a87046a96f2a 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -1677,6 +1677,26 @@ static struct { | |||
1677 | 1677 | ||
1678 | static int wm8994_readable(unsigned int reg) | 1678 | static int wm8994_readable(unsigned int reg) |
1679 | { | 1679 | { |
1680 | switch (reg) { | ||
1681 | case WM8994_GPIO_1: | ||
1682 | case WM8994_GPIO_2: | ||
1683 | case WM8994_GPIO_3: | ||
1684 | case WM8994_GPIO_4: | ||
1685 | case WM8994_GPIO_5: | ||
1686 | case WM8994_GPIO_6: | ||
1687 | case WM8994_GPIO_7: | ||
1688 | case WM8994_GPIO_8: | ||
1689 | case WM8994_GPIO_9: | ||
1690 | case WM8994_GPIO_10: | ||
1691 | case WM8994_GPIO_11: | ||
1692 | case WM8994_INTERRUPT_STATUS_1: | ||
1693 | case WM8994_INTERRUPT_STATUS_2: | ||
1694 | case WM8994_INTERRUPT_RAW_STATUS_2: | ||
1695 | return 1; | ||
1696 | default: | ||
1697 | break; | ||
1698 | } | ||
1699 | |||
1680 | if (reg >= ARRAY_SIZE(access_masks)) | 1700 | if (reg >= ARRAY_SIZE(access_masks)) |
1681 | return 0; | 1701 | return 0; |
1682 | return access_masks[reg].readable != 0; | 1702 | return access_masks[reg].readable != 0; |
@@ -2341,6 +2361,20 @@ SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, | |||
2341 | 0, 1, 0), | 2361 | 0, 1, 0), |
2342 | }; | 2362 | }; |
2343 | 2363 | ||
2364 | static const struct snd_kcontrol_new aif1adc2l_mix[] = { | ||
2365 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2366 | 1, 1, 0), | ||
2367 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2368 | 0, 1, 0), | ||
2369 | }; | ||
2370 | |||
2371 | static const struct snd_kcontrol_new aif1adc2r_mix[] = { | ||
2372 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2373 | 1, 1, 0), | ||
2374 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2375 | 0, 1, 0), | ||
2376 | }; | ||
2377 | |||
2344 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { | 2378 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { |
2345 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | 2379 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, |
2346 | 5, 1, 0), | 2380 | 5, 1, 0), |
@@ -2472,6 +2506,7 @@ static const struct snd_kcontrol_new aif3adc_mux = | |||
2472 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { | 2506 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { |
2473 | SND_SOC_DAPM_INPUT("DMIC1DAT"), | 2507 | SND_SOC_DAPM_INPUT("DMIC1DAT"), |
2474 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 2508 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
2509 | SND_SOC_DAPM_INPUT("Clock"), | ||
2475 | 2510 | ||
2476 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | 2511 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, |
2477 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 2512 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -2506,6 +2541,11 @@ SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0, | |||
2506 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, | 2541 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, |
2507 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), | 2542 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), |
2508 | 2543 | ||
2544 | SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0, | ||
2545 | aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)), | ||
2546 | SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0, | ||
2547 | aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)), | ||
2548 | |||
2509 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, | 2549 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, |
2510 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), | 2550 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), |
2511 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, | 2551 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, |
@@ -2668,6 +2708,14 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
2668 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, | 2708 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, |
2669 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, | 2709 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, |
2670 | 2710 | ||
2711 | { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" }, | ||
2712 | { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" }, | ||
2713 | { "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2714 | |||
2715 | { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" }, | ||
2716 | { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" }, | ||
2717 | { "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2718 | |||
2671 | /* Pin level routing for AIF3 */ | 2719 | /* Pin level routing for AIF3 */ |
2672 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, | 2720 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, |
2673 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, | 2721 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, |
@@ -2946,11 +2994,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, | |||
2946 | return 0; | 2994 | return 0; |
2947 | } | 2995 | } |
2948 | 2996 | ||
2997 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | ||
2998 | |||
2949 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | 2999 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, |
2950 | int clk_id, unsigned int freq, int dir) | 3000 | int clk_id, unsigned int freq, int dir) |
2951 | { | 3001 | { |
2952 | struct snd_soc_codec *codec = dai->codec; | 3002 | struct snd_soc_codec *codec = dai->codec; |
2953 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3003 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3004 | int i; | ||
2954 | 3005 | ||
2955 | switch (dai->id) { | 3006 | switch (dai->id) { |
2956 | case 1: | 3007 | case 1: |
@@ -2988,6 +3039,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2988 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); | 3039 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); |
2989 | break; | 3040 | break; |
2990 | 3041 | ||
3042 | case WM8994_SYSCLK_OPCLK: | ||
3043 | /* Special case - a division (times 10) is given and | ||
3044 | * no effect on main clocking. | ||
3045 | */ | ||
3046 | if (freq) { | ||
3047 | for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) | ||
3048 | if (opclk_divs[i] == freq) | ||
3049 | break; | ||
3050 | if (i == ARRAY_SIZE(opclk_divs)) | ||
3051 | return -EINVAL; | ||
3052 | snd_soc_update_bits(codec, WM8994_CLOCKING_2, | ||
3053 | WM8994_OPCLK_DIV_MASK, i); | ||
3054 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3055 | WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); | ||
3056 | } else { | ||
3057 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3058 | WM8994_OPCLK_ENA, 0); | ||
3059 | } | ||
3060 | |||
2991 | default: | 3061 | default: |
2992 | return -EINVAL; | 3062 | return -EINVAL; |
2993 | } | 3063 | } |
@@ -4004,6 +4074,11 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
4004 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | 4074 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, |
4005 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | 4075 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); |
4006 | 4076 | ||
4077 | /* Unconditionally enable AIF1 ADC TDM mode; it only affects | ||
4078 | * behaviour on idle TDM clock cycles. */ | ||
4079 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | ||
4080 | WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); | ||
4081 | |||
4007 | wm8994_update_class_w(codec); | 4082 | wm8994_update_class_w(codec); |
4008 | 4083 | ||
4009 | ret = snd_soc_register_codec(codec); | 4084 | ret = snd_soc_register_codec(codec); |