ASoC: WCD9304: Add the compander support to wcd9304
The compander system is intended to increase the dynamic
range of an input signal. But for the wcd9304 codec,
this feature is to use companding in a novel way in the DAC
converter path to increase the signal noise ratio.
The change is to add the compander support to wcd9304
codec. The dynamic compander enable/disable during stream
playback is not supported.
Change-Id: If912302ee9d48dde1318e894a982cba591908d8f
Signed-off-by: Kuirong Wang <kuirongw@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9304-tables.c b/sound/soc/codecs/wcd9304-tables.c
index 83c0c1d..7ec0152 100644
--- a/sound/soc/codecs/wcd9304-tables.c
+++ b/sound/soc/codecs/wcd9304-tables.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -235,8 +235,24 @@
[SITAR_A_CDC_RX1_B4_CTL] = SITAR_A_CDC_RX1_B4_CTL__POR,
[SITAR_A_CDC_RX1_B5_CTL] = SITAR_A_CDC_RX1_B5_CTL__POR,
[SITAR_A_CDC_RX1_B6_CTL] = SITAR_A_CDC_RX1_B6_CTL__POR,
+ [SITAR_A_CDC_RX2_B1_CTL] = SITAR_A_CDC_RX2_B1_CTL__POR,
+ [SITAR_A_CDC_RX2_B2_CTL] = SITAR_A_CDC_RX2_B2_CTL__POR,
+ [SITAR_A_CDC_RX2_B3_CTL] = SITAR_A_CDC_RX2_B3_CTL__POR,
+ [SITAR_A_CDC_RX2_B4_CTL] = SITAR_A_CDC_RX2_B4_CTL__POR,
+ [SITAR_A_CDC_RX2_B5_CTL] = SITAR_A_CDC_RX2_B5_CTL__POR,
+ [SITAR_A_CDC_RX2_B6_CTL] = SITAR_A_CDC_RX2_B6_CTL__POR,
+ [SITAR_A_CDC_RX3_B1_CTL] = SITAR_A_CDC_RX3_B1_CTL__POR,
+ [SITAR_A_CDC_RX3_B2_CTL] = SITAR_A_CDC_RX3_B2_CTL__POR,
+ [SITAR_A_CDC_RX3_B3_CTL] = SITAR_A_CDC_RX3_B3_CTL__POR,
+ [SITAR_A_CDC_RX3_B4_CTL] = SITAR_A_CDC_RX3_B4_CTL__POR,
+ [SITAR_A_CDC_RX3_B5_CTL] = SITAR_A_CDC_RX3_B5_CTL__POR,
+ [SITAR_A_CDC_RX3_B6_CTL] = SITAR_A_CDC_RX3_B6_CTL__POR,
[SITAR_A_CDC_RX1_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B1_CTL__POR,
[SITAR_A_CDC_RX1_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX1_VOL_CTL_B2_CTL__POR,
+ [SITAR_A_CDC_RX2_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX2_VOL_CTL_B1_CTL__POR,
+ [SITAR_A_CDC_RX2_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX2_VOL_CTL_B2_CTL__POR,
+ [SITAR_A_CDC_RX3_VOL_CTL_B1_CTL] = SITAR_A_CDC_RX3_VOL_CTL_B1_CTL__POR,
+ [SITAR_A_CDC_RX3_VOL_CTL_B2_CTL] = SITAR_A_CDC_RX3_VOL_CTL_B2_CTL__POR,
[SITAR_A_CDC_CLK_ANC_RESET_CTL] = SITAR_A_CDC_CLK_ANC_RESET_CTL__POR,
[SITAR_A_CDC_CLK_RX_RESET_CTL] = SITAR_A_CDC_CLK_RX_RESET_CTL__POR,
[SITAR_A_CDC_CLK_TX_RESET_B1_CTL] =
@@ -322,6 +338,15 @@
[SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS] =
SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS__POR,
[SITAR_A_CDC_COMP1_FS_CFG] = SITAR_A_CDC_COMP1_FS_CFG__POR,
+ [SITAR_A_CDC_COMP2_B1_CTL] = SITAR_A_CDC_COMP2_B1_CTL__POR,
+ [SITAR_A_CDC_COMP2_B2_CTL] = SITAR_A_CDC_COMP2_B2_CTL__POR,
+ [SITAR_A_CDC_COMP2_B3_CTL] = SITAR_A_CDC_COMP2_B3_CTL__POR,
+ [SITAR_A_CDC_COMP2_B4_CTL] = SITAR_A_CDC_COMP2_B4_CTL__POR,
+ [SITAR_A_CDC_COMP2_B5_CTL] = SITAR_A_CDC_COMP2_B5_CTL__POR,
+ [SITAR_A_CDC_COMP2_B6_CTL] = SITAR_A_CDC_COMP2_B6_CTL__POR,
+ [SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS] =
+ SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS__POR,
+ [SITAR_A_CDC_COMP2_FS_CFG] = SITAR_A_CDC_COMP2_FS_CFG__POR,
[SITAR_A_CDC_CONN_RX1_B1_CTL] = SITAR_A_CDC_CONN_RX1_B1_CTL__POR,
[SITAR_A_CDC_CONN_RX1_B2_CTL] = SITAR_A_CDC_CONN_RX1_B2_CTL__POR,
[SITAR_A_CDC_CONN_RX1_B3_CTL] = SITAR_A_CDC_CONN_RX1_B3_CTL__POR,
diff --git a/sound/soc/codecs/wcd9304.c b/sound/soc/codecs/wcd9304.c
index f5f4e23..616f8d5 100644
--- a/sound/soc/codecs/wcd9304.c
+++ b/sound/soc/codecs/wcd9304.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -81,6 +81,11 @@
#define SITAR_OCP_ATTEMPT 1
+#define COMP_DIGITAL_DB_GAIN_APPLY(a, b) \
+ (((a) <= 0) ? ((a) - b) : (a))
+/* The wait time value comes from codec HW specification */
+#define COMP_BRINGUP_WAIT_TIME 3000
+
#define SITAR_MCLK_RATE_12288KHZ 12288000
#define SITAR_MCLK_RATE_9600KHZ 9600000
@@ -148,6 +153,22 @@
BAND_MAX,
};
+enum {
+ COMPANDER_1 = 0,
+ COMPANDER_2,
+ COMPANDER_MAX,
+};
+
+enum {
+ COMPANDER_FS_8KHZ = 0,
+ COMPANDER_FS_16KHZ,
+ COMPANDER_FS_32KHZ,
+ COMPANDER_FS_48KHZ,
+ COMPANDER_FS_96KHZ,
+ COMPANDER_FS_192KHZ,
+ COMPANDER_FS_MAX,
+};
+
/* 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. */
@@ -158,6 +179,33 @@
SITAR_HPHR_DAC_OFF_ACK
};
+struct comp_sample_dependent_params {
+ u32 peak_det_timeout;
+ u32 rms_meter_div_fact;
+ u32 rms_meter_resamp_fact;
+};
+
+struct comp_dgtl_gain_offset {
+ u8 whole_db_gain;
+ u8 half_db_gain;
+};
+
+static const struct comp_dgtl_gain_offset comp_dgtl_gain[] = {
+ {0, 0},
+ {1, 1},
+ {3, 0},
+ {4, 1},
+ {6, 0},
+ {7, 1},
+ {9, 0},
+ {10, 1},
+ {12, 0},
+ {13, 1},
+ {15, 0},
+ {16, 1},
+ {18, 0},
+};
+
/* Data used by MBHC */
struct mbhc_internal_cal_data {
u16 dce_z;
@@ -273,6 +321,11 @@
/* num of slim ports required */
struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
+ /*compander*/
+ int comp_enabled[COMPANDER_MAX];
+ u32 comp_fs[COMPANDER_MAX];
+ u8 comp_gain_offset[NUM_INTERPOLATORS];
+
/* Currently, only used for mbhc purpose, to protect
* concurrent execution of mbhc threaded irq handlers and
* kill race between DAPM and MBHC.But can serve as a
@@ -295,6 +348,47 @@
struct sitar_priv *debug_sitar_priv;
#endif
+static const int comp_rx_path[] = {
+ COMPANDER_2,
+ COMPANDER_1,
+ COMPANDER_1,
+ COMPANDER_MAX,
+};
+
+static const struct comp_sample_dependent_params
+ comp_samp_params[COMPANDER_FS_MAX] = {
+ {
+ .peak_det_timeout = 0x6,
+ .rms_meter_div_fact = 0x9 << 4,
+ .rms_meter_resamp_fact = 0x06,
+ },
+ {
+ .peak_det_timeout = 0x7,
+ .rms_meter_div_fact = 0xA << 4,
+ .rms_meter_resamp_fact = 0x0C,
+ },
+ {
+ .peak_det_timeout = 0x8,
+ .rms_meter_div_fact = 0xB << 4,
+ .rms_meter_resamp_fact = 0x30,
+ },
+ {
+ .peak_det_timeout = 0x9,
+ .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,
+ },
+ {
+ .peak_det_timeout = 0xB,
+ .rms_meter_div_fact = 0xC << 4,
+ .rms_meter_resamp_fact = 0x50,
+ },
+};
+
static int sitar_get_anc_slot(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -539,6 +633,268 @@
return 0;
}
+static int sitar_compander_gain_offset(
+ struct snd_soc_codec *codec, u32 enable,
+ unsigned int pa_reg, unsigned int vol_reg,
+ int mask, int event,
+ struct comp_dgtl_gain_offset *gain_offset,
+ int index)
+{
+ unsigned int pa_gain = snd_soc_read(codec, pa_reg);
+ unsigned int digital_vol = snd_soc_read(codec, vol_reg);
+ int pa_mode = pa_gain & mask;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ pr_debug("%s: pa_gain(0x%x=0x%x)digital_vol(0x%x=0x%x)event(0x%x) index(%d)\n",
+ __func__, pa_reg, pa_gain, vol_reg, digital_vol, event, index);
+ if (((pa_gain & 0xF) + 1) > ARRAY_SIZE(comp_dgtl_gain) ||
+ (index >= ARRAY_SIZE(sitar->comp_gain_offset))) {
+ pr_err("%s: Out of array boundary\n", __func__);
+ return -EINVAL;
+ }
+
+ if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
+ gain_offset->whole_db_gain = COMP_DIGITAL_DB_GAIN_APPLY(
+ (digital_vol - comp_dgtl_gain[pa_gain & 0xF].whole_db_gain),
+ comp_dgtl_gain[pa_gain & 0xF].half_db_gain);
+ pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
+ __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
+ gain_offset->whole_db_gain);
+ gain_offset->half_db_gain =
+ comp_dgtl_gain[pa_gain & 0xF].half_db_gain;
+ sitar->comp_gain_offset[index] = digital_vol -
+ gain_offset->whole_db_gain ;
+ }
+ if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
+ gain_offset->whole_db_gain = digital_vol +
+ sitar->comp_gain_offset[index];
+ pr_debug("%s: listed whole_db_gain:0x%x, adjusted whole_db_gain:0x%x\n",
+ __func__, comp_dgtl_gain[pa_gain & 0xF].whole_db_gain,
+ gain_offset->whole_db_gain);
+ gain_offset->half_db_gain = 0;
+ }
+
+ pr_debug("%s: half_db_gain(%d)whole_db_gain(0x%x)comp_gain_offset[%d](%d)\n",
+ __func__, gain_offset->half_db_gain,
+ gain_offset->whole_db_gain, index,
+ sitar->comp_gain_offset[index]);
+ return 0;
+}
+
+static int sitar_config_gain_compander(
+ struct snd_soc_codec *codec,
+ u32 compander, u32 enable, int event)
+{
+ int value = 0;
+ int mask = 1 << 4;
+ struct comp_dgtl_gain_offset gain_offset = {0, 0};
+ if (compander >= COMPANDER_MAX) {
+ pr_err("%s: Error, invalid compander channel\n", __func__);
+ return -EINVAL;
+ }
+
+ if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
+ value = 1 << 4;
+
+ if (compander == COMPANDER_1) {
+ sitar_compander_gain_offset(codec, enable,
+ SITAR_A_RX_HPH_L_GAIN,
+ SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
+ mask, event, &gain_offset, 1);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_GAIN, mask, value);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
+ 0xFF, gain_offset.whole_db_gain);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX2_B6_CTL,
+ 0x02, gain_offset.half_db_gain);
+ sitar_compander_gain_offset(codec, enable,
+ SITAR_A_RX_HPH_R_GAIN,
+ SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
+ mask, event, &gain_offset, 2);
+ snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_GAIN, mask, value);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
+ 0xFF, gain_offset.whole_db_gain);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX3_B6_CTL,
+ 0x02, gain_offset.half_db_gain);
+ } else if (compander == COMPANDER_2) {
+ sitar_compander_gain_offset(codec, enable,
+ SITAR_A_RX_LINE_1_GAIN,
+ SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
+ mask, event, &gain_offset, 0);
+ snd_soc_update_bits(codec, SITAR_A_RX_LINE_1_GAIN, mask, value);
+ snd_soc_update_bits(codec, SITAR_A_RX_LINE_2_GAIN, mask, value);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
+ 0xFF, gain_offset.whole_db_gain);
+ snd_soc_update_bits(codec, SITAR_A_CDC_RX1_B6_CTL,
+ 0x02, gain_offset.half_db_gain);
+ }
+ return 0;
+}
+
+static int sitar_get_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = sitar->comp_enabled[comp];
+
+ return 0;
+}
+
+static int sitar_set_compander(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ int comp = ((struct soc_multi_mixer_control *)
+ kcontrol->private_value)->shift;
+ int value = ucontrol->value.integer.value[0];
+
+ pr_debug("%s: compander #%d enable %d\n",
+ __func__, comp + 1, value);
+ if (value == sitar->comp_enabled[comp]) {
+ pr_debug("%s: compander #%d enable %d no change\n",
+ __func__, comp + 1, value);
+ return 0;
+ }
+ sitar->comp_enabled[comp] = value;
+ return 0;
+}
+
+static int sitar_config_compander(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ u32 rate = sitar->comp_fs[w->shift];
+ u32 value;
+
+ pr_debug("%s: compander #%d enable %d event %d widget name %s\n",
+ __func__, w->shift + 1,
+ sitar->comp_enabled[w->shift], event , w->name);
+ if (sitar->comp_enabled[w->shift] == 0)
+ goto rtn;
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ /* Update compander sample rate */
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_FS_CFG +
+ w->shift * 8, 0x07, rate);
+ /* Enable compander clock */
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_RX_B2_CTL,
+ 1 << w->shift,
+ 1 << w->shift);
+ /* Toggle compander reset bits */
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL,
+ 1 << w->shift,
+ 1 << w->shift);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL,
+ 1 << w->shift, 0);
+ sitar_config_gain_compander(codec, w->shift, 1, event);
+ /* Compander enable -> 0x370/0x378 */
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x03);
+ /* Update the RMS meter resampling */
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF, 0x01);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0, 0x50);
+ usleep_range(COMP_BRINGUP_WAIT_TIME, COMP_BRINGUP_WAIT_TIME);
+ break;
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLSG_CTL,
+ 0x11, 0x00);
+ if (w->shift == COMPANDER_1)
+ value = 0x22;
+ else
+ value = 0x11;
+ snd_soc_write(codec,
+ SITAR_A_CDC_CONN_CLSG_CTL, value);
+
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0x0F,
+ comp_samp_params[rate].peak_det_timeout);
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B2_CTL +
+ w->shift * 8, 0xF0,
+ comp_samp_params[rate].rms_meter_div_fact);
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B3_CTL +
+ w->shift * 8, 0xFF,
+ comp_samp_params[rate].rms_meter_resamp_fact);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec, SITAR_A_CDC_COMP1_B1_CTL +
+ w->shift * 8, 0x03, 0x00);
+ /* Toggle compander reset bits */
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL,
+ 1 << w->shift,
+ 1 << w->shift);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_OTHR_RESET_CTL,
+ 1 << w->shift, 0);
+ /* Disable compander clock */
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLK_RX_B2_CTL,
+ 1 << w->shift,
+ 0);
+ /* Restore the gain */
+ sitar_config_gain_compander(codec, w->shift,
+ sitar->comp_enabled[w->shift],
+ event);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CLSG_CTL,
+ 0x11, 0x11);
+ snd_soc_write(codec,
+ SITAR_A_CDC_CONN_CLSG_CTL, 0x14);
+ break;
+ }
+rtn:
+ return 0;
+}
+
+static int sitar_codec_dem_input_selection(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol,
+ int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
+ pr_debug("%s: compander#1->enable(%d) compander#2->enable(%d) reg(0x%x = 0x%x) event(%d)\n",
+ __func__, sitar->comp_enabled[COMPANDER_1],
+ sitar->comp_enabled[COMPANDER_2],
+ SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
+ snd_soc_read(codec, SITAR_A_CDC_RX1_B6_CTL + w->shift * 8),
+ event);
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (sitar->comp_enabled[COMPANDER_1] ||
+ sitar->comp_enabled[COMPANDER_2])
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_RX1_B6_CTL +
+ w->shift * 8,
+ 1 << 5, 0);
+ else
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_RX1_B6_CTL +
+ w->shift * 8,
+ 1 << 5, 0x20);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_RX1_B6_CTL + w->shift * 8,
+ 1 << 5, 0);
+ break;
+ }
+ return 0;
+}
+
static const char * const sitar_ear_pa_gain_text[] = {"POS_6_DB",
"POS_2_DB", "NEG_2P5_DB", "NEG_12_DB"};
@@ -652,6 +1008,10 @@
sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
+ SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
+ sitar_get_compander, sitar_set_compander),
+ SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
+ sitar_get_compander, sitar_set_compander),
};
static const char *rx_mix1_text[] = {
@@ -1267,9 +1627,14 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
u16 lineout_gain_reg;
- pr_debug("%s %d %s\n", __func__, event, w->name);
+ pr_debug("%s %d %s comp2 enable %d\n", __func__, event, w->name,
+ sitar->comp_enabled[COMPANDER_2]);
+
+ if (sitar->comp_enabled[COMPANDER_2])
+ goto rtn;
switch (w->shift) {
case 0:
@@ -1311,6 +1676,7 @@
snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
break;
}
+rtn:
return 0;
}
@@ -2010,16 +2376,22 @@
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
+ struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s %s %d\n", __func__, w->name, event);
+ pr_debug("%s %s %d comp#1 enable %d\n", __func__,
+ w->name, event, sitar->comp_enabled[COMPANDER_1]);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (w->reg == SITAR_A_RX_HPH_L_DAC_CTL) {
- snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
- 0x30, 0x20);
- snd_soc_update_bits(codec, SITAR_A_CDC_CONN_CLSG_CTL,
- 0x0C, 0x08);
+ if (!sitar->comp_enabled[COMPANDER_1]) {
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x30, 0x20);
+ snd_soc_update_bits(codec,
+ SITAR_A_CDC_CONN_CLSG_CTL,
+ 0x0C, 0x08);
+ }
}
snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
break;
@@ -2338,9 +2710,15 @@
SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
&rx_dac4_mux),
- SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
- SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER_E("RX1 CHAIN", SND_SOC_NOPM, 0, 0, NULL,
+ 0, sitar_codec_dem_input_selection,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX2 CHAIN", SND_SOC_NOPM, 1, 0, NULL,
+ 0, sitar_codec_dem_input_selection,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_MIXER_E("RX3 CHAIN", SND_SOC_NOPM, 2, 0, NULL,
+ 0, sitar_codec_dem_input_selection,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
&rx_mix1_inp1_mux),
@@ -2463,6 +2841,13 @@
sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, COMPANDER_1, 0,
+ sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, COMPANDER_2, 0,
+ sitar_config_compander, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
/* Sidetone */
SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
@@ -2592,6 +2977,10 @@
{"SLIM RX3", NULL, "SLIM RX3 MUX"},
{"SLIM RX4", NULL, "SLIM RX4 MUX"},
+ {"RX1 MIX1", NULL, "COMP2_CLK"},
+ {"RX2 MIX1", NULL, "COMP1_CLK"},
+ {"RX3 MIX1", NULL, "COMP1_CLK"},
+
/* Slimbus port 5 is non functional in Sitar 1.0 */
{"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
{"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
@@ -2733,6 +3122,10 @@
if (reg == SITAR_A_CDC_RX1_VOL_CTL_B2_CTL + (8 * i))
return 1;
}
+
+ if ((reg == SITAR_A_CDC_COMP1_SHUT_DOWN_STATUS) ||
+ (reg == SITAR_A_CDC_COMP2_SHUT_DOWN_STATUS))
+ return 1;
return 0;
}
@@ -3191,6 +3584,7 @@
struct snd_soc_codec *codec = dai->codec;
struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
u8 path, shift;
+ u32 compander_fs;
u16 tx_fs_reg, rx_fs_reg;
u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
@@ -3200,18 +3594,32 @@
case 8000:
tx_fs_rate = 0x00;
rx_fs_rate = 0x00;
+ compander_fs = COMPANDER_FS_8KHZ;
break;
case 16000:
tx_fs_rate = 0x01;
rx_fs_rate = 0x20;
+ compander_fs = COMPANDER_FS_16KHZ;
break;
case 32000:
tx_fs_rate = 0x02;
rx_fs_rate = 0x40;
+ compander_fs = COMPANDER_FS_32KHZ;
break;
case 48000:
tx_fs_rate = 0x03;
rx_fs_rate = 0x60;
+ compander_fs = COMPANDER_FS_48KHZ;
+ break;
+ case 96000:
+ tx_fs_rate = 0x04;
+ rx_fs_rate = 0x80;
+ compander_fs = COMPANDER_FS_96KHZ;
+ break;
+ case 192000:
+ tx_fs_rate = 0x05;
+ rx_fs_rate = 0xa0;
+ compander_fs = COMPANDER_FS_192KHZ;
break;
default:
pr_err("%s: Invalid sampling rate %d\n", __func__,
@@ -3285,6 +3693,9 @@
+ (BITS_PER_REG*(path-1));
snd_soc_update_bits(codec, rx_fs_reg,
0xE0, rx_fs_rate);
+ if (comp_rx_path[shift] < COMPANDER_MAX)
+ sitar->comp_fs[comp_rx_path[shift]]
+ = compander_fs;
}
}
if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
@@ -5484,6 +5895,11 @@
if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
sitar_i2c_codec_init_reg(codec);
+ for (i = 0; i < COMPANDER_MAX; i++) {
+ sitar->comp_enabled[i] = 0;
+ sitar->comp_fs[i] = COMPANDER_FS_48KHZ;
+ }
+
ret = sitar_handle_pdata(sitar);
if (IS_ERR_VALUE(ret)) {
pr_err("%s: bad pdata\n", __func__);