ASoC: wcd9310: Update wcd9310 compander configuration
Update the Compander register settings to remain the default
settings after the system bootup and optimize compander
configuration sequence.
Change-Id: Ib475f3bb84414546b4ead1d3f013dc173317e1b3
Signed-off-by: Kuirong Wang <kuirongw@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 6d3eb98..4c446e47 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -82,7 +82,6 @@
#define AIF3_PB 6
#define NUM_CODEC_DAIS 6
-#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
struct tabla_codec_dai_data {
u32 rate;
@@ -93,6 +92,9 @@
wait_queue_head_t dai_wait;
};
+#define TABLA_COMP_DIGITAL_GAIN_HP_OFFSET 3
+#define TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET 6
+
#define TABLA_MCLK_RATE_12288KHZ 12288000
#define TABLA_MCLK_RATE_9600KHZ 9600000
@@ -180,6 +182,16 @@
COMPANDER_FS_MAX,
};
+enum {
+ COMP_SHUTDWN_TIMEOUT_PCM_1 = 0,
+ COMP_SHUTDWN_TIMEOUT_PCM_240,
+ COMP_SHUTDWN_TIMEOUT_PCM_480,
+ COMP_SHUTDWN_TIMEOUT_PCM_960,
+ COMP_SHUTDWN_TIMEOUT_PCM_1440,
+ COMP_SHUTDWN_TIMEOUT_PCM_2880,
+ COMP_SHUTDWN_TIMEOUT_PCM_5760,
+};
+
/* Flags to track of PA and DAC state.
* PA and DAC should be tracked separately as AUXPGA loopback requires
* only PA to be turned on without DAC being on. */
@@ -195,6 +207,7 @@
u32 peak_det_timeout;
u32 rms_meter_div_fact;
u32 rms_meter_resamp_fact;
+ u32 shutdown_timeout;
};
/* Data used by MBHC */
@@ -354,7 +367,7 @@
static const u32 comp_shift[] = {
0,
- 2,
+ 1,
};
static const int comp_rx_path[] = {
@@ -367,28 +380,43 @@
COMPANDER_MAX,
};
-static const struct comp_sample_dependent_params comp_samp_params[] = {
+static const struct comp_sample_dependent_params
+ comp_samp_params[COMPANDER_FS_MAX] = {
{
- .peak_det_timeout = 0x2,
- .rms_meter_div_fact = 0x8 << 4,
- .rms_meter_resamp_fact = 0x21,
- },
- {
- .peak_det_timeout = 0x3,
+ .peak_det_timeout = 0x6,
.rms_meter_div_fact = 0x9 << 4,
- .rms_meter_resamp_fact = 0x28,
+ .rms_meter_resamp_fact = 0x06,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_240 << 3,
},
-
{
- .peak_det_timeout = 0x5,
+ .peak_det_timeout = 0x7,
+ .rms_meter_div_fact = 0xA << 4,
+ .rms_meter_resamp_fact = 0x0C,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_480 << 3,
+ },
+ {
+ .peak_det_timeout = 0x8,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x30,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_960 << 3,
+ },
+ {
+ .peak_det_timeout = 0x9,
.rms_meter_div_fact = 0xB << 4,
.rms_meter_resamp_fact = 0x28,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_1440 << 3,
},
-
{
- .peak_det_timeout = 0x5,
- .rms_meter_div_fact = 0xB << 4,
- .rms_meter_resamp_fact = 0x28,
+ .peak_det_timeout = 0xA,
+ .rms_meter_div_fact = 0xC << 4,
+ .rms_meter_resamp_fact = 0x50,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_2880 << 3,
+ },
+ {
+ .peak_det_timeout = 0xB,
+ .rms_meter_div_fact = 0xC << 4,
+ .rms_meter_resamp_fact = 0x50,
+ .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_5760 << 3,
},
};
@@ -682,7 +710,7 @@
static int tabla_compander_gain_offset(
struct snd_soc_codec *codec, u32 enable,
- unsigned int reg, int mask, int event)
+ unsigned int reg, int mask, int event, u32 comp)
{
int pa_mode = snd_soc_read(codec, reg) & mask;
int gain_offset = 0;
@@ -692,10 +720,21 @@
* if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
*/
- if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
- gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
- if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
- gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
+ if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
+ if (comp == COMPANDER_1)
+ gain_offset = TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
+ if (comp == COMPANDER_2)
+ gain_offset = TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
+ }
+ if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
+ if (comp == COMPANDER_1)
+ gain_offset = -TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
+ if (comp == COMPANDER_2)
+ gain_offset = -TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
+
+ }
+ pr_debug("%s: compander #%d gain_offset %d\n",
+ __func__, comp + 1, gain_offset);
return gain_offset;
}
@@ -718,38 +757,38 @@
if (compander == COMPANDER_1) {
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_HPH_L_GAIN, mask, event);
+ TABLA_A_RX_HPH_L_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_HPH_R_GAIN, mask, event);
+ TABLA_A_RX_HPH_R_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
} else if (compander == COMPANDER_2) {
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_1_GAIN, mask, event);
+ TABLA_A_RX_LINE_1_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_3_GAIN, mask, event);
+ TABLA_A_RX_LINE_3_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_2_GAIN, mask, event);
+ TABLA_A_RX_LINE_2_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
0xFF, gain - gain_offset);
gain_offset = tabla_compander_gain_offset(codec, enable,
- TABLA_A_RX_LINE_4_GAIN, mask, event);
+ TABLA_A_RX_LINE_4_GAIN, mask, event, compander);
snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
@@ -779,10 +818,11 @@
int comp = ((struct soc_multi_mixer_control *)
kcontrol->private_value)->max;
int value = ucontrol->value.integer.value[0];
-
+ pr_debug("%s: compander #%d enable %d\n",
+ __func__, comp + 1, value);
if (value == tabla->comp_enabled[comp]) {
pr_debug("%s: compander #%d enable %d no change\n",
- __func__, comp, value);
+ __func__, comp + 1, value);
return 0;
}
tabla->comp_enabled[comp] = value;
@@ -797,41 +837,51 @@
struct snd_soc_codec *codec = w->codec;
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
u32 rate = tabla->comp_fs[w->shift];
-
+ u32 status;
+ unsigned long timeout;
+ pr_debug("%s: compander #%d enable %d event %d\n",
+ __func__, w->shift + 1,
+ tabla->comp_enabled[w->shift], event);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (tabla->comp_enabled[w->shift] != 0) {
/* Enable both L/R compander clocks */
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_RX_B2_CTL,
- 0x03 << comp_shift[w->shift],
- 0x03 << comp_shift[w->shift]);
- /* Clar the HALT for the compander*/
+ 1 << comp_shift[w->shift],
+ 1 << comp_shift[w->shift]);
+ /* Clear the HALT for the compander*/
snd_soc_update_bits(codec,
TABLA_A_CDC_COMP1_B1_CTL +
w->shift * 8, 1 << 2, 0);
/* Toggle compander reset bits*/
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_OTHR_RESET_CTL,
- 0x03 << comp_shift[w->shift],
- 0x03 << comp_shift[w->shift]);
+ 1 << comp_shift[w->shift],
+ 1 << comp_shift[w->shift]);
snd_soc_update_bits(codec,
TABLA_A_CDC_CLK_OTHR_RESET_CTL,
- 0x03 << comp_shift[w->shift], 0);
+ 1 << comp_shift[w->shift], 0);
tabla_config_gain_compander(codec, w->shift, 1, event);
+ /* Compander enable -> 0x370/0x378*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x03);
/* Update the RMS meter resampling*/
snd_soc_update_bits(codec,
TABLA_A_CDC_COMP1_B3_CTL +
w->shift * 8, 0xFF, 0x01);
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0, 0x50);
/* Wait for 1ms*/
- usleep_range(1000, 1000);
+ usleep_range(5000, 5000);
}
break;
case SND_SOC_DAPM_POST_PMU:
/* Set sample rate dependent paramater*/
if (tabla->comp_enabled[w->shift] != 0) {
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
- w->shift * 8, 0x03, rate);
+ w->shift * 8, 0x07, rate);
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
w->shift * 8, 0x0F,
comp_samp_params[rate].peak_det_timeout);
@@ -841,26 +891,50 @@
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
w->shift * 8, 0xFF,
comp_samp_params[rate].rms_meter_resamp_fact);
- /* Compander enable -> 0x370/0x378*/
snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 0x03, 0x03);
+ w->shift * 8, 0x38,
+ comp_samp_params[rate].shutdown_timeout);
}
break;
case SND_SOC_DAPM_PRE_PMD:
- /* Halt the compander*/
- snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 1 << 2, 1 << 2);
+ if (tabla->comp_enabled[w->shift] != 0) {
+ status = snd_soc_read(codec,
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
+ w->shift * 8);
+ pr_debug("%s: compander #%d shutdown status %d in event %d\n",
+ __func__, w->shift + 1, status, event);
+ /* Halt the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 1 << 2);
+ }
break;
case SND_SOC_DAPM_POST_PMD:
- /* Restore the gain */
- tabla_config_gain_compander(codec, w->shift,
- tabla->comp_enabled[w->shift], event);
- /* Disable the compander*/
- snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
- w->shift * 8, 0x03, 0x00);
- /* Turn off the clock for compander in pair*/
- snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
- 0x03 << comp_shift[w->shift], 0);
+ if (tabla->comp_enabled[w->shift] != 0) {
+ /* Wait up to a second for shutdown complete */
+ timeout = jiffies + HZ;
+ do {
+ status = snd_soc_read(codec,
+ TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
+ w->shift * 8);
+ if (status == 0x3)
+ break;
+ usleep_range(5000, 5000);
+ } while (!(time_after(jiffies, timeout)));
+ /* Restore the gain */
+ tabla_config_gain_compander(codec, w->shift,
+ tabla->comp_enabled[w->shift],
+ event);
+ /* Disable the compander*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Turn off the clock for compander in pair*/
+ snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
+ 0x03 << comp_shift[w->shift], 0);
+ /* Clear the HALT for the compander*/
+ snd_soc_update_bits(codec,
+ TABLA_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 1 << 2, 0);
+ }
break;
}
return 0;
@@ -3652,6 +3726,10 @@
if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
return 1;
+ if (reg == TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS ||
+ reg == TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS)
+ return 1;
+
return 0;
}