[Rebase from R2]audio: sst: sn95031: Enable PLL and VAUDA before changing volume...
authorOmair Mohammed Abdullah <omair.m.abdullah@intel.com>
Tue, 10 Jan 2012 10:59:32 +0000 (16:29 +0530)
committerbuildbot <buildbot@intel.com>
Fri, 13 Jan 2012 09:39:38 +0000 (01:39 -0800)
BZ: 19775

old_BZ:18716

Due to a problem with the codec, any writes made to the *VOLCTRL registers are
not reflected until the VAUDA and clocks are turned on.

Implemented a volume control function which turns on the PLLs and the VAUDA
before changing the VOLCTRL registers. It then restores the previous state back.

While VOLCTRL registers were getting updated eventually when some actual
playback started, the values read back before playback were wrong. This fixes
that issue. Volume can now be set and read using amixer for tuning purposes.

Change-Id: I88ef9db97ce04fb52a45f70053c71a45e1f1a2a6
Old-Change-Id: I935491ad146b230e8da4c26c1fb95c32c055c569
Signed-off-by: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
Reviewed-on: http://android.intel.com:8080/31707
Reviewed-by: M, Arulselvan <arulselvan.m@intel.com>
Tested-by: M, Arulselvan <arulselvan.m@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
include/sound/intel_sst.h
sound/pci/sst/intel_sst.c
sound/soc/codecs/sn95031.c

index 72e0066..82be67f 100644 (file)
@@ -33,6 +33,7 @@
 #include <sound/jack.h>
 
 #define SST_CARD_NAMES "intel_mid_card"
+#define SST_PLL_DELAY 2000
 
 #define MFLD_MAX_HW_CH 4
 /* control list Pmic & Lpe */
@@ -148,4 +149,5 @@ enum intel_sst_pll_mode {
 int register_sst_card(struct intel_sst_card_ops *card);
 void unregister_sst_card(struct intel_sst_card_ops *card);
 int intel_sst_set_pll(unsigned int enable, enum intel_sst_pll_mode mode);
+int intel_sst_get_pll(void);
 #endif /* __INTEL_SST_H__ */
index 3d875e0..1a79083 100644 (file)
@@ -530,6 +530,12 @@ EXPORT_SYMBOL(intel_sst_set_pll);
  * taking the system through D3hot and restoring it back to D0 and so there is
  * no need to duplicate that here.
  */
+int intel_sst_get_pll(void)
+{
+       return sst_drv_ctx->pll_mode;
+}
+EXPORT_SYMBOL(intel_sst_get_pll);
+
 static int intel_sst_runtime_suspend(struct device *dev)
 {
        union config_status_reg csr;
index 48bece7..ade0007 100644 (file)
@@ -339,6 +339,59 @@ static int sn95031_enable_pnw_clk(struct snd_soc_dapm_widget *w,
        return 0;
 }
 
+/* Callback to set volume for *VOLCTRL regs. Needs to be implemented separately
+ * since clock and VAUDA need to be on before value can be written to the regs
+ */
+static int sn95031_set_vol_2r(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int reg = mc->reg;
+       unsigned int reg2 = mc->rreg;
+       unsigned int shift = mc->shift;
+       int max = mc->max;
+       unsigned int mask = (1 << fls(max)) - 1;
+       unsigned int invert = mc->invert;
+       int err;
+       unsigned int val, val2, val_mask;
+       int sst_pll_mode_saved;
+
+       val_mask = mask << shift;
+       val = (ucontrol->value.integer.value[0] & mask);
+       val2 = (ucontrol->value.integer.value[1] & mask);
+
+       if (invert) {
+               val = max - val;
+               val2 = max - val2;
+       }
+
+       val = val << shift;
+       val2 = val2 << shift;
+
+       pr_debug("enabling PLL and VAUDA to change volume\n");
+       mutex_lock(&codec->mutex);
+       sst_pll_mode_saved = intel_sst_get_pll();
+       intel_sst_set_pll(true, SST_PLL_MSIC);
+       udelay(SST_PLL_DELAY);
+       snd_soc_dapm_force_enable_pin(&codec->dapm, "VirtBias");
+       snd_soc_dapm_sync(&codec->dapm);
+
+       err = snd_soc_update_bits(codec, reg, val_mask, val);
+       if (err < 0)
+               goto restore_state;
+
+       err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+restore_state:
+       snd_soc_dapm_disable_pin(&codec->dapm, "VirtBias");
+       snd_soc_dapm_sync(&codec->dapm);
+       if ((sst_pll_mode_saved & SST_PLL_MSIC) == 0)
+               intel_sst_set_pll(false, SST_PLL_MSIC);
+       mutex_unlock(&codec->mutex);
+       return err;
+}
+
 /* mux controls */
 static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" };
 
@@ -510,13 +563,17 @@ static const struct snd_kcontrol_new sn95031_snd_controls[] = {
        SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2,
                        2, 3, 0, mic_tlv),
        /* Add digital volume and mute controls for Headphone/Headset*/
-       SOC_DOUBLE_R_TLV("Headphone Playback Volume", SN95031_HSLVOLCTRL,
-                               SN95031_HSRVOLCTRL, 0, 71, 1, out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", SN95031_HSLVOLCTRL,
+                               SN95031_HSRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
        SOC_DOUBLE_R("Headphone Playback Switch", SN95031_HSLVOLCTRL,
                                SN95031_HSRVOLCTRL, 7, 1, 0),
        /* Add digital volume and mute controls for Speaker*/
-       SOC_DOUBLE_R_TLV("Speaker Playback Volume", SN95031_IHFLVOLCTRL,
-                               SN95031_IHFRVOLCTRL, 0, 71, 1, out_tlv),
+       SOC_DOUBLE_R_EXT_TLV("Speaker Playback Volume", SN95031_IHFLVOLCTRL,
+                               SN95031_IHFRVOLCTRL, 0, 71, 1,
+                               snd_soc_get_volsw_2r, sn95031_set_vol_2r,
+                               out_tlv),
        SOC_DOUBLE_R("Speaker Playback Switch", SN95031_IHFLVOLCTRL,
                                SN95031_IHFRVOLCTRL, 7, 1, 0),
 
@@ -571,6 +628,8 @@ static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = {
        SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0),
        SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0),
        SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0),
+       /* Dummy widget to trigger VAUDA on/off */
+       SND_SOC_DAPM_MICBIAS("VirtBias", SND_SOC_NOPM, 0, 0),
 
        SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0,
                                sn95031_dmic12_event,