aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8962.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/wm8962.c')
-rw-r--r--sound/soc/codecs/wm8962.c187
1 files changed, 184 insertions, 3 deletions
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index d2c315fa1b9b..3676b38838d8 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -63,6 +63,8 @@ struct wm8962_priv {
63 int fll_fref; 63 int fll_fref;
64 int fll_fout; 64 int fll_fout;
65 65
66 u16 dsp2_ena;
67
66 struct delayed_work mic_work; 68 struct delayed_work mic_work;
67 struct snd_soc_jack *jack; 69 struct snd_soc_jack *jack;
68 70
@@ -837,7 +839,7 @@ static const struct wm8962_reg_access {
837 [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */ 839 [40] = { 0x00FF, 0x01FF, 0x0000 }, /* R40 - SPKOUTL volume */
838 [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */ 840 [41] = { 0x00FF, 0x01FF, 0x0000 }, /* R41 - SPKOUTR volume */
839 841
840 [47] = { 0x000F, 0x0000, 0x0000 }, /* R47 - Thermal Shutdown Status */ 842 [47] = { 0x000F, 0x0000, 0xFFFF }, /* R47 - Thermal Shutdown Status */
841 [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */ 843 [48] = { 0x7EC7, 0x7E07, 0xFFFF }, /* R48 - Additional Control (4) */
842 [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */ 844 [49] = { 0x00D3, 0x00D7, 0xFFFF }, /* R49 - Class D Control 1 */
843 [51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */ 845 [51] = { 0x0047, 0x0047, 0x0000 }, /* R51 - Class D Control 2 */
@@ -965,7 +967,7 @@ static const struct wm8962_reg_access {
965 [584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */ 967 [584] = { 0x002D, 0x002D, 0x0000 }, /* R584 - IRQ Debounce */
966 [586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */ 968 [586] = { 0xC000, 0xC000, 0x0000 }, /* R586 - MICINT Source Pol */
967 [768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */ 969 [768] = { 0x0001, 0x0001, 0x0000 }, /* R768 - DSP2 Power Management */
968 [1037] = { 0x0000, 0x003F, 0x0000 }, /* R1037 - DSP2_ExecControl */ 970 [1037] = { 0x0000, 0x003F, 0xFFFF }, /* R1037 - DSP2_ExecControl */
969 [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */ 971 [4096] = { 0x3FFF, 0x3FFF, 0x0000 }, /* R4096 - Write Sequencer 0 */
970 [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */ 972 [4097] = { 0x00FF, 0x00FF, 0x0000 }, /* R4097 - Write Sequencer 1 */
971 [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */ 973 [4098] = { 0x070F, 0x070F, 0x0000 }, /* R4098 - Write Sequencer 2 */
@@ -1986,6 +1988,122 @@ static const unsigned int classd_tlv[] = {
1986}; 1988};
1987static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); 1989static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
1988 1990
1991static int wm8962_dsp2_write_config(struct snd_soc_codec *codec)
1992{
1993 return 0;
1994}
1995
1996static int wm8962_dsp2_set_enable(struct snd_soc_codec *codec, u16 val)
1997{
1998 u16 adcl = snd_soc_read(codec, WM8962_LEFT_ADC_VOLUME);
1999 u16 adcr = snd_soc_read(codec, WM8962_RIGHT_ADC_VOLUME);
2000 u16 dac = snd_soc_read(codec, WM8962_ADC_DAC_CONTROL_1);
2001
2002 /* Mute the ADCs and DACs */
2003 snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, 0);
2004 snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, WM8962_ADC_VU);
2005 snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
2006 WM8962_DAC_MUTE, WM8962_DAC_MUTE);
2007
2008 snd_soc_write(codec, WM8962_SOUNDSTAGE_ENABLES_0, val);
2009
2010 /* Restore the ADCs and DACs */
2011 snd_soc_write(codec, WM8962_LEFT_ADC_VOLUME, adcl);
2012 snd_soc_write(codec, WM8962_RIGHT_ADC_VOLUME, adcr);
2013 snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1,
2014 WM8962_DAC_MUTE, dac);
2015
2016 return 0;
2017}
2018
2019static int wm8962_dsp2_start(struct snd_soc_codec *codec)
2020{
2021 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
2022
2023 wm8962_dsp2_write_config(codec);
2024
2025 snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_RUNR);
2026
2027 wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
2028
2029 return 0;
2030}
2031
2032static int wm8962_dsp2_stop(struct snd_soc_codec *codec)
2033{
2034 wm8962_dsp2_set_enable(codec, 0);
2035
2036 snd_soc_write(codec, WM8962_DSP2_EXECCONTROL, WM8962_DSP2_STOP);
2037
2038 return 0;
2039}
2040
2041#define WM8962_DSP2_ENABLE(xname, xshift) \
2042{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
2043 .info = wm8962_dsp2_ena_info, \
2044 .get = wm8962_dsp2_ena_get, .put = wm8962_dsp2_ena_put, \
2045 .private_value = xshift }
2046
2047static int wm8962_dsp2_ena_info(struct snd_kcontrol *kcontrol,
2048 struct snd_ctl_elem_info *uinfo)
2049{
2050 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2051
2052 uinfo->count = 1;
2053 uinfo->value.integer.min = 0;
2054 uinfo->value.integer.max = 1;
2055
2056 return 0;
2057}
2058
2059static int wm8962_dsp2_ena_get(struct snd_kcontrol *kcontrol,
2060 struct snd_ctl_elem_value *ucontrol)
2061{
2062 int shift = kcontrol->private_value;
2063 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2064 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
2065
2066 ucontrol->value.integer.value[0] = !!(wm8962->dsp2_ena & 1 << shift);
2067
2068 return 0;
2069}
2070
2071static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
2072 struct snd_ctl_elem_value *ucontrol)
2073{
2074 int shift = kcontrol->private_value;
2075 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
2076 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
2077 int old = wm8962->dsp2_ena;
2078 int ret = 0;
2079 int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) &
2080 WM8962_DSP2_ENA;
2081
2082 mutex_lock(&codec->mutex);
2083
2084 if (ucontrol->value.integer.value[0])
2085 wm8962->dsp2_ena |= 1 << shift;
2086 else
2087 wm8962->dsp2_ena &= ~(1 << shift);
2088
2089 if (wm8962->dsp2_ena == old)
2090 goto out;
2091
2092 ret = 1;
2093
2094 if (dsp2_running) {
2095 if (wm8962->dsp2_ena)
2096 wm8962_dsp2_set_enable(codec, wm8962->dsp2_ena);
2097 else
2098 wm8962_dsp2_stop(codec);
2099 }
2100
2101out:
2102 mutex_unlock(&codec->mutex);
2103
2104 return ret;
2105}
2106
1989/* The VU bits for the headphones are in a different register to the mute 2107/* The VU bits for the headphones are in a different register to the mute
1990 * bits and only take effect on the PGA if it is actually powered. 2108 * bits and only take effect on the PGA if it is actually powered.
1991 */ 2109 */
@@ -2049,6 +2167,14 @@ static const char *cap_hpf_mode_text[] = {
2049static const struct soc_enum cap_hpf_mode = 2167static const struct soc_enum cap_hpf_mode =
2050 SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text); 2168 SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text);
2051 2169
2170
2171static const char *cap_lhpf_mode_text[] = {
2172 "LPF", "HPF"
2173};
2174
2175static const struct soc_enum cap_lhpf_mode =
2176 SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text);
2177
2052static const struct snd_kcontrol_new wm8962_snd_controls[] = { 2178static const struct snd_kcontrol_new wm8962_snd_controls[] = {
2053SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1), 2179SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1),
2054 2180
@@ -2077,6 +2203,8 @@ SOC_DOUBLE_R("Capture ZC Switch", WM8962_LEFT_INPUT_VOLUME,
2077SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1), 2203SOC_SINGLE("Capture HPF Switch", WM8962_ADC_DAC_CONTROL_1, 0, 1, 1),
2078SOC_ENUM("Capture HPF Mode", cap_hpf_mode), 2204SOC_ENUM("Capture HPF Mode", cap_hpf_mode),
2079SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0), 2205SOC_SINGLE("Capture HPF Cutoff", WM8962_ADC_DAC_CONTROL_2, 7, 7, 0),
2206SOC_SINGLE("Capture LHPF Switch", WM8962_LHPF1, 0, 1, 0),
2207SOC_ENUM("Capture LHPF Mode", cap_lhpf_mode),
2080 2208
2081SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1, 2209SOC_DOUBLE_R_TLV("Sidetone Volume", WM8962_DAC_DSP_MIXING_1,
2082 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv), 2210 WM8962_DAC_DSP_MIXING_2, 4, 12, 0, st_tlv),
@@ -2134,6 +2262,11 @@ SOC_DOUBLE_R_TLV("EQ4 Volume", WM8962_EQ3, WM8962_EQ23,
2134 WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv), 2262 WM8962_EQL_B4_GAIN_SHIFT, 31, 0, eq_tlv),
2135SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23, 2263SOC_DOUBLE_R_TLV("EQ5 Volume", WM8962_EQ3, WM8962_EQ23,
2136 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv), 2264 WM8962_EQL_B5_GAIN_SHIFT, 31, 0, eq_tlv),
2265
2266WM8962_DSP2_ENABLE("VSS Switch", WM8962_VSS_ENA_SHIFT),
2267WM8962_DSP2_ENABLE("HPF1 Switch", WM8962_HPF1_ENA_SHIFT),
2268WM8962_DSP2_ENABLE("HPF2 Switch", WM8962_HPF2_ENA_SHIFT),
2269WM8962_DSP2_ENABLE("HD Bass Switch", WM8962_HDBASS_ENA_SHIFT),
2137}; 2270};
2138 2271
2139static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = { 2272static const struct snd_kcontrol_new wm8962_spk_mono_controls[] = {
@@ -2395,6 +2528,31 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
2395 } 2528 }
2396} 2529}
2397 2530
2531static int dsp2_event(struct snd_soc_dapm_widget *w,
2532 struct snd_kcontrol *kcontrol, int event)
2533{
2534 struct snd_soc_codec *codec = w->codec;
2535 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
2536
2537 switch (event) {
2538 case SND_SOC_DAPM_POST_PMU:
2539 if (wm8962->dsp2_ena)
2540 wm8962_dsp2_start(codec);
2541 break;
2542
2543 case SND_SOC_DAPM_PRE_PMD:
2544 if (wm8962->dsp2_ena)
2545 wm8962_dsp2_stop(codec);
2546 break;
2547
2548 default:
2549 BUG();
2550 return -EINVAL;
2551 }
2552
2553 return 0;
2554}
2555
2398static const char *st_text[] = { "None", "Right", "Left" }; 2556static const char *st_text[] = { "None", "Right", "Left" };
2399 2557
2400static const struct soc_enum str_enum = 2558static const struct soc_enum str_enum =
@@ -2517,6 +2675,9 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
2517SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event, 2675SND_SOC_DAPM_SUPPLY("Charge Pump", WM8962_CHARGE_PUMP_1, 0, 0, cp_event,
2518 SND_SOC_DAPM_POST_PMU), 2676 SND_SOC_DAPM_POST_PMU),
2519SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0), 2677SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
2678SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
2679 WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
2680 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
2520 2681
2521SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0, 2682SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
2522 inpgal, ARRAY_SIZE(inpgal)), 2683 inpgal, ARRAY_SIZE(inpgal)),
@@ -2612,11 +2773,13 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
2612 { "ADCL", NULL, "TOCLK" }, 2773 { "ADCL", NULL, "TOCLK" },
2613 { "ADCL", NULL, "MIXINL" }, 2774 { "ADCL", NULL, "MIXINL" },
2614 { "ADCL", NULL, "DMIC" }, 2775 { "ADCL", NULL, "DMIC" },
2776 { "ADCL", NULL, "DSP2" },
2615 2777
2616 { "ADCR", NULL, "SYSCLK" }, 2778 { "ADCR", NULL, "SYSCLK" },
2617 { "ADCR", NULL, "TOCLK" }, 2779 { "ADCR", NULL, "TOCLK" },
2618 { "ADCR", NULL, "MIXINR" }, 2780 { "ADCR", NULL, "MIXINR" },
2619 { "ADCR", NULL, "DMIC" }, 2781 { "ADCR", NULL, "DMIC" },
2782 { "ADCR", NULL, "DSP2" },
2620 2783
2621 { "STL", "Left", "ADCL" }, 2784 { "STL", "Left", "ADCL" },
2622 { "STL", "Right", "ADCR" }, 2785 { "STL", "Right", "ADCR" },
@@ -2628,11 +2791,13 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
2628 { "DACL", NULL, "TOCLK" }, 2791 { "DACL", NULL, "TOCLK" },
2629 { "DACL", NULL, "Beep" }, 2792 { "DACL", NULL, "Beep" },
2630 { "DACL", NULL, "STL" }, 2793 { "DACL", NULL, "STL" },
2794 { "DACL", NULL, "DSP2" },
2631 2795
2632 { "DACR", NULL, "SYSCLK" }, 2796 { "DACR", NULL, "SYSCLK" },
2633 { "DACR", NULL, "TOCLK" }, 2797 { "DACR", NULL, "TOCLK" },
2634 { "DACR", NULL, "Beep" }, 2798 { "DACR", NULL, "Beep" },
2635 { "DACR", NULL, "STR" }, 2799 { "DACR", NULL, "STR" },
2800 { "DACR", NULL, "DSP2" },
2636 2801
2637 { "HPMIXL", "IN4L Switch", "IN4L" }, 2802 { "HPMIXL", "IN4L Switch", "IN4L" },
2638 { "HPMIXL", "IN4R Switch", "IN4R" }, 2803 { "HPMIXL", "IN4R Switch", "IN4R" },
@@ -3403,12 +3568,16 @@ static irqreturn_t wm8962_irq(int irq, void *data)
3403 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); 3568 struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
3404 int mask; 3569 int mask;
3405 int active; 3570 int active;
3571 int reg;
3406 3572
3407 mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK); 3573 mask = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2_MASK);
3408 3574
3409 active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); 3575 active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2);
3410 active &= ~mask; 3576 active &= ~mask;
3411 3577
3578 if (!active)
3579 return IRQ_NONE;
3580
3412 /* Acknowledge the interrupts */ 3581 /* Acknowledge the interrupts */
3413 snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); 3582 snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active);
3414 3583
@@ -3420,9 +3589,21 @@ static irqreturn_t wm8962_irq(int irq, void *data)
3420 if (active & WM8962_FIFOS_ERR_EINT) 3589 if (active & WM8962_FIFOS_ERR_EINT)
3421 dev_err(codec->dev, "FIFO error\n"); 3590 dev_err(codec->dev, "FIFO error\n");
3422 3591
3423 if (active & WM8962_TEMP_SHUT_EINT) 3592 if (active & WM8962_TEMP_SHUT_EINT) {
3424 dev_crit(codec->dev, "Thermal shutdown\n"); 3593 dev_crit(codec->dev, "Thermal shutdown\n");
3425 3594
3595 reg = snd_soc_read(codec, WM8962_THERMAL_SHUTDOWN_STATUS);
3596
3597 if (reg & WM8962_TEMP_ERR_HP)
3598 dev_crit(codec->dev, "Headphone thermal error\n");
3599 if (reg & WM8962_TEMP_WARN_HP)
3600 dev_crit(codec->dev, "Headphone thermal warning\n");
3601 if (reg & WM8962_TEMP_ERR_SPK)
3602 dev_crit(codec->dev, "Speaker thermal error\n");
3603 if (reg & WM8962_TEMP_WARN_SPK)
3604 dev_crit(codec->dev, "Speaker thermal warning\n");
3605 }
3606
3426 if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) { 3607 if (active & (WM8962_MICSCD_EINT | WM8962_MICD_EINT)) {
3427 dev_dbg(codec->dev, "Microphone event detected\n"); 3608 dev_dbg(codec->dev, "Microphone event detected\n");
3428 3609