Merge branch 'stable-4.6' of git://git.infradead.org/users/pcmoore/audit
[cascardo/linux.git] / sound / soc / codecs / nau8825.c
index c1b87c5..1c87299 100644 (file)
@@ -84,6 +84,7 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = {
 
 static const struct reg_default nau8825_reg_defaults[] = {
        { NAU8825_REG_ENA_CTRL, 0x00ff },
+       { NAU8825_REG_IIC_ADDR_SET, 0x0 },
        { NAU8825_REG_CLK_DIVIDER, 0x0050 },
        { NAU8825_REG_FLL1, 0x0 },
        { NAU8825_REG_FLL2, 0x3126 },
@@ -158,8 +159,7 @@ static const struct reg_default nau8825_reg_defaults[] = {
 static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case NAU8825_REG_ENA_CTRL:
-       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_ENA_CTRL ... NAU8825_REG_FLL_VCO_RSV:
        case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
        case NAU8825_REG_INTERRUPT_MASK ... NAU8825_REG_KEYDET_CTRL:
        case NAU8825_REG_VDET_THRESHOLD_1 ... NAU8825_REG_DACR_CTRL:
@@ -184,8 +184,7 @@ static bool nau8825_readable_reg(struct device *dev, unsigned int reg)
 static bool nau8825_writeable_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case NAU8825_REG_RESET ... NAU8825_REG_ENA_CTRL:
-       case NAU8825_REG_CLK_DIVIDER ... NAU8825_REG_FLL_VCO_RSV:
+       case NAU8825_REG_RESET ... NAU8825_REG_FLL_VCO_RSV:
        case NAU8825_REG_HSD_CTRL ... NAU8825_REG_JACK_DET_CTRL:
        case NAU8825_REG_INTERRUPT_MASK:
        case NAU8825_REG_INT_CLR_KEY_STATUS ... NAU8825_REG_KEYDET_CTRL:
@@ -227,10 +226,42 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg)
 static int nau8825_pump_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                /* Prevent startup click by letting charge pump to ramp up */
                msleep(10);
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+                       NAU8825_JAMNODCLOW, NAU8825_JAMNODCLOW);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP,
+                       NAU8825_JAMNODCLOW, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+       struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec);
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Disables the TESTDAC to let DAC signal pass through. */
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+                       NAU8825_BIAS_TESTDAC_EN, 0);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+                       NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
                break;
        default:
                return -EINVAL;
@@ -316,10 +347,10 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
        SND_SOC_DAPM_ADC("SAR", NULL, NAU8825_REG_SAR_CTRL,
                NAU8825_SAR_ADC_EN_SFT, 0),
 
-       SND_SOC_DAPM_DAC("ADACL", NULL, NAU8825_REG_RDAC, 12, 0),
-       SND_SOC_DAPM_DAC("ADACR", NULL, NAU8825_REG_RDAC, 13, 0),
-       SND_SOC_DAPM_SUPPLY("ADACL Clock", NAU8825_REG_RDAC, 8, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("ADACR Clock", NAU8825_REG_RDAC, 9, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACL", 2, NAU8825_REG_RDAC, 12, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACR", 2, NAU8825_REG_RDAC, 13, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACL Clock", 3, NAU8825_REG_RDAC, 8, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("ADACR Clock", 3, NAU8825_REG_RDAC, 9, 0, NULL, 0),
 
        SND_SOC_DAPM_DAC("DDACR", NULL, NAU8825_REG_ENA_CTRL,
                NAU8825_ENABLE_DACR_SFT, 0),
@@ -330,29 +361,48 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = {
        SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacl_mux),
        SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &nau8825_dacr_mux),
 
-       SND_SOC_DAPM_PGA("HP amp L", NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("HP amp R", NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
-       SND_SOC_DAPM_SUPPLY("HP amp power", NAU8825_REG_CLASSG_CTRL, 0, 0, NULL,
-               0),
+       SND_SOC_DAPM_PGA_S("HP amp L", 0,
+               NAU8825_REG_CLASSG_CTRL, 1, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_S("HP amp R", 0,
+               NAU8825_REG_CLASSG_CTRL, 2, 0, NULL, 0),
 
-       SND_SOC_DAPM_SUPPLY("Charge Pump", NAU8825_REG_CHARGE_PUMP, 5, 0,
-               nau8825_pump_event, SND_SOC_DAPM_POST_PMU),
+       SND_SOC_DAPM_PGA_S("Charge Pump", 1, NAU8825_REG_CHARGE_PUMP, 5, 0,
+               nau8825_pump_event, SND_SOC_DAPM_POST_PMU |
+               SND_SOC_DAPM_PRE_PMD),
 
-       SND_SOC_DAPM_PGA("Output Driver R Stage 1",
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 1", 4,
                NAU8825_REG_POWER_UP_CONTROL, 5, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver L Stage 1",
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 1", 4,
                NAU8825_REG_POWER_UP_CONTROL, 4, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver R Stage 2",
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 2", 5,
                NAU8825_REG_POWER_UP_CONTROL, 3, 0, NULL, 0),
-       SND_SOC_DAPM_PGA("Output Driver L Stage 2",
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 2", 5,
                NAU8825_REG_POWER_UP_CONTROL, 2, 0, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 1,
+       SND_SOC_DAPM_PGA_S("Output Driver R Stage 3", 6,
                NAU8825_REG_POWER_UP_CONTROL, 1, 0, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 1,
+       SND_SOC_DAPM_PGA_S("Output Driver L Stage 3", 6,
                NAU8825_REG_POWER_UP_CONTROL, 0, 0, NULL, 0),
 
-       SND_SOC_DAPM_PGA_S("Output DACL", 2, NAU8825_REG_CHARGE_PUMP, 8, 1, NULL, 0),
-       SND_SOC_DAPM_PGA_S("Output DACR", 2, NAU8825_REG_CHARGE_PUMP, 9, 1, NULL, 0),
+       SND_SOC_DAPM_PGA_S("Output DACL", 7,
+               NAU8825_REG_CHARGE_PUMP, 8, 1, nau8825_output_dac_event,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_S("Output DACR", 7,
+               NAU8825_REG_CHARGE_PUMP, 9, 1, nau8825_output_dac_event,
+               SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       /* HPOL/R are ungrounded by disabling 16 Ohm pull-downs on playback */
+       SND_SOC_DAPM_PGA_S("HPOL Pulldown", 8,
+               NAU8825_REG_HSD_CTRL, 0, 1, NULL, 0),
+       SND_SOC_DAPM_PGA_S("HPOR Pulldown", 8,
+               NAU8825_REG_HSD_CTRL, 1, 1, NULL, 0),
+
+       /* High current HPOL/R boost driver */
+       SND_SOC_DAPM_PGA_S("HP Boost Driver", 9,
+               NAU8825_REG_BOOST, 9, 1, NULL, 0),
+
+       /* Class G operation control*/
+       SND_SOC_DAPM_PGA_S("Class G", 10,
+               NAU8825_REG_CLASSG_CTRL, 0, 0, NULL, 0),
 
        SND_SOC_DAPM_OUTPUT("HPOL"),
        SND_SOC_DAPM_OUTPUT("HPOR"),
@@ -375,24 +425,27 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = {
        {"DACR Mux", "DACR", "DDACR"},
        {"HP amp L", NULL, "DACL Mux"},
        {"HP amp R", NULL, "DACR Mux"},
-       {"HP amp L", NULL, "HP amp power"},
-       {"HP amp R", NULL, "HP amp power"},
-       {"ADACL", NULL, "HP amp L"},
-       {"ADACR", NULL, "HP amp R"},
-       {"ADACL", NULL, "ADACL Clock"},
-       {"ADACR", NULL, "ADACR Clock"},
-       {"Output Driver L Stage 1", NULL, "ADACL"},
-       {"Output Driver R Stage 1", NULL, "ADACR"},
+       {"Charge Pump", NULL, "HP amp L"},
+       {"Charge Pump", NULL, "HP amp R"},
+       {"ADACL", NULL, "Charge Pump"},
+       {"ADACR", NULL, "Charge Pump"},
+       {"ADACL Clock", NULL, "ADACL"},
+       {"ADACR Clock", NULL, "ADACR"},
+       {"Output Driver L Stage 1", NULL, "ADACL Clock"},
+       {"Output Driver R Stage 1", NULL, "ADACR Clock"},
        {"Output Driver L Stage 2", NULL, "Output Driver L Stage 1"},
        {"Output Driver R Stage 2", NULL, "Output Driver R Stage 1"},
        {"Output Driver L Stage 3", NULL, "Output Driver L Stage 2"},
        {"Output Driver R Stage 3", NULL, "Output Driver R Stage 2"},
        {"Output DACL", NULL, "Output Driver L Stage 3"},
        {"Output DACR", NULL, "Output Driver R Stage 3"},
-       {"HPOL", NULL, "Output DACL"},
-       {"HPOR", NULL, "Output DACR"},
-       {"HPOL", NULL, "Charge Pump"},
-       {"HPOR", NULL, "Charge Pump"},
+       {"HPOL Pulldown", NULL, "Output DACL"},
+       {"HPOR Pulldown", NULL, "Output DACR"},
+       {"HP Boost Driver", NULL, "HPOL Pulldown"},
+       {"HP Boost Driver", NULL, "HPOR Pulldown"},
+       {"Class G", NULL, "HP Boost Driver"},
+       {"HPOL", NULL, "Class G"},
+       {"HPOR", NULL, "Class G"},
 };
 
 static int nau8825_hw_params(struct snd_pcm_substream *substream,
@@ -659,11 +712,10 @@ static int nau8825_jack_insert(struct nau8825 *nau8825)
                break;
        }
 
-       if (type & SND_JACK_HEADPHONE) {
-               /* Unground HPL/R */
-               regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0x3, 0);
-       }
-
+       /* Leaving HPOL/R grounded after jack insert by default. They will be
+        * ungrounded as part of the widget power up sequence at the beginning
+        * of playback to reduce pop.
+        */
        return type;
 }
 
@@ -768,6 +820,8 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
 {
        struct regmap *regmap = nau8825->regmap;
 
+       /* Latch IIC LSB value */
+       regmap_write(regmap, NAU8825_REG_IIC_ADDR_SET, 0x0001);
        /* Enable Bias/Vmid */
        regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
                NAU8825_BIAS_VMID, NAU8825_BIAS_VMID);
@@ -780,10 +834,10 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                nau8825->vref_impedance << NAU8825_BIAS_VMID_SEL_SFT);
        /* Disable Boost Driver, Automatic Short circuit protection enable */
        regmap_update_bits(regmap, NAU8825_REG_BOOST,
-               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
-               NAU8825_SHORT_SHUTDOWN_EN,
-               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_G_DIS |
-               NAU8825_SHORT_SHUTDOWN_EN);
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+               NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN,
+               NAU8825_PRECHARGE_DIS | NAU8825_HP_BOOST_DIS |
+               NAU8825_HP_BOOST_G_DIS | NAU8825_SHORT_SHUTDOWN_EN);
 
        regmap_update_bits(regmap, NAU8825_REG_GPIO12_CTRL,
                NAU8825_JKDET_OUTPUT_EN,
@@ -822,6 +876,35 @@ static void nau8825_init_regs(struct nau8825 *nau8825)
                NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128);
        regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
                NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128);
+       /* Disable DACR/L power */
+       regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP,
+               NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL,
+               NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL);
+       /* Enable TESTDAC. This sets the analog DAC inputs to a '0' input
+        * signal to avoid any glitches due to power up transients in both
+        * the analog and digital DAC circuit.
+        */
+       regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ,
+               NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN);
+       /* CICCLP off */
+       regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1,
+               NAU8825_DAC_CLIP_OFF, NAU8825_DAC_CLIP_OFF);
+
+       /* Class AB bias current to 2x, DAC Capacitor enable MSB/LSB */
+       regmap_update_bits(regmap, NAU8825_REG_ANALOG_CONTROL_2,
+               NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+               NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB,
+               NAU8825_HP_NON_CLASSG_CURRENT_2xADJ |
+               NAU8825_DAC_CAPACITOR_MSB | NAU8825_DAC_CAPACITOR_LSB);
+       /* Class G timer 64ms */
+       regmap_update_bits(regmap, NAU8825_REG_CLASSG_CTRL,
+               NAU8825_CLASSG_TIMER_MASK,
+               0x20 << NAU8825_CLASSG_TIMER_SFT);
+       /* DAC clock delay 2ns, VREF */
+       regmap_update_bits(regmap, NAU8825_REG_RDAC,
+               NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK,
+               (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) |
+               (0x3 << NAU8825_RDAC_VREF_SFT));
 }
 
 static const struct regmap_config nau8825_regmap_config = {