ASoC: WCD9310: Add Active Noise Cancellation support
ANC is a feature which reduces noise on the near-end
by pushing anti-noise onto the audio stream heard
by the user. ANC mixes the anti-noise signal
inside of the WCD9310 codec.
Signed-off-by: Brad Rubin <brubin@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310-tables.c b/sound/soc/codecs/wcd9310-tables.c
index bc6bf4f..98a5139 100644
--- a/sound/soc/codecs/wcd9310-tables.c
+++ b/sound/soc/codecs/wcd9310-tables.c
@@ -247,6 +247,18 @@
[TABLA_A_CONFIG_MODE_TEST] = 1,
[TABLA_A_CONFIG_MODE_STATUS] = 1,
[TABLA_A_CONFIG_MODE_TUNER] = 1,
+ [TABLA_A_CDC_ANC1_CTL] = 1,
+ [TABLA_A_CDC_ANC1_SHIFT] = 1,
+ [TABLA_A_CDC_ANC1_FILT1_B1_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT1_B2_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT1_B3_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT1_B4_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT2_B1_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT2_B2_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT2_B3_CTL] = 1,
+ [TABLA_A_CDC_ANC1_SPARE] = 1,
+ [TABLA_A_CDC_ANC1_FILT3_CTL] = 1,
+ [TABLA_A_CDC_ANC1_FILT4_CTL] = 1,
[TABLA_A_CDC_TX1_VOL_CTL_TIMER] = 1,
[TABLA_A_CDC_TX2_VOL_CTL_TIMER] = 1,
[TABLA_A_CDC_TX3_VOL_CTL_TIMER] = 1,
@@ -367,6 +379,7 @@
[TABLA_A_CDC_RX5_VOL_CTL_B2_CTL] = 1,
[TABLA_A_CDC_RX6_VOL_CTL_B2_CTL] = 1,
[TABLA_A_CDC_RX7_VOL_CTL_B2_CTL] = 1,
+ [TABLA_A_CDC_CLK_ANC_RESET_CTL] = 1,
[TABLA_A_CDC_CLK_RX_RESET_CTL] = 1,
[TABLA_A_CDC_CLK_TX_RESET_B1_CTL] = 1,
[TABLA_A_CDC_CLK_TX_RESET_B2_CTL] = 1,
@@ -378,6 +391,7 @@
[TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL] = 1,
[TABLA_A_CDC_CLK_OTHR_CTL] = 1,
[TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL] = 1,
+ [TABLA_A_CDC_CLK_ANC_CLK_EN_CTL] = 1,
[TABLA_A_CDC_CLK_RX_B1_CTL] = 1,
[TABLA_A_CDC_CLK_RX_B2_CTL] = 1,
[TABLA_A_CDC_CLK_MCLK_CTL] = 1,
@@ -445,6 +459,8 @@
[TABLA_A_CDC_CONN_RX6_B2_CTL] = 1,
[TABLA_A_CDC_CONN_RX7_B1_CTL] = 1,
[TABLA_A_CDC_CONN_RX7_B2_CTL] = 1,
+ [TABLA_A_CDC_CONN_ANC_B1_CTL] = 1,
+ [TABLA_A_CDC_CONN_ANC_B2_CTL] = 1,
[TABLA_A_CDC_CONN_TX_B1_CTL] = 1,
[TABLA_A_CDC_CONN_TX_B2_CTL] = 1,
[TABLA_A_CDC_CONN_TX_B3_CTL] = 1,
@@ -746,6 +762,18 @@
[TABLA_A_CONFIG_MODE_TEST] = TABLA_A_CONFIG_MODE_TEST__POR,
[TABLA_A_CONFIG_MODE_STATUS] = TABLA_A_CONFIG_MODE_STATUS__POR,
[TABLA_A_CONFIG_MODE_TUNER] = TABLA_A_CONFIG_MODE_TUNER__POR,
+ [TABLA_A_CDC_ANC1_CTL] = TABLA_A_CDC_ANC1_CTL__POR,
+ [TABLA_A_CDC_ANC1_SHIFT] = TABLA_A_CDC_ANC1_SHIFT__POR,
+ [TABLA_A_CDC_ANC1_FILT1_B1_CTL] = TABLA_A_CDC_ANC1_FILT1_B1_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT1_B2_CTL] = TABLA_A_CDC_ANC1_FILT1_B2_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT1_B3_CTL] = TABLA_A_CDC_ANC1_FILT1_B3_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT1_B4_CTL] = TABLA_A_CDC_ANC1_FILT1_B4_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT2_B1_CTL] = TABLA_A_CDC_ANC1_FILT2_B1_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT2_B2_CTL] = TABLA_A_CDC_ANC1_FILT2_B2_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT2_B3_CTL] = TABLA_A_CDC_ANC1_FILT2_B3_CTL__POR,
+ [TABLA_A_CDC_ANC1_SPARE] = TABLA_A_CDC_ANC1_SPARE__POR,
+ [TABLA_A_CDC_ANC1_FILT3_CTL] = TABLA_A_CDC_ANC1_FILT3_CTL__POR,
+ [TABLA_A_CDC_ANC1_FILT4_CTL] = TABLA_A_CDC_ANC1_FILT4_CTL__POR,
[TABLA_A_CDC_TX1_VOL_CTL_TIMER] = TABLA_A_CDC_TX1_VOL_CTL_TIMER__POR,
[TABLA_A_CDC_TX2_VOL_CTL_TIMER] = TABLA_A_CDC_TX2_VOL_CTL_TIMER__POR,
[TABLA_A_CDC_TX3_VOL_CTL_TIMER] = TABLA_A_CDC_TX3_VOL_CTL_TIMER__POR,
@@ -867,6 +895,7 @@
[TABLA_A_CDC_RX6_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX6_VOL_CTL_B2_CTL__POR,
[TABLA_A_CDC_RX7_VOL_CTL_B2_CTL] = TABLA_A_CDC_RX7_VOL_CTL_B2_CTL__POR,
[TABLA_A_CDC_CLK_RX_RESET_CTL] = TABLA_A_CDC_CLK_RX_RESET_CTL__POR,
+ [TABLA_A_CDC_CLK_ANC_RESET_CTL] = TABLA_A_CDC_CLK_ANC_RESET_CTL__POR,
[TABLA_A_CDC_CLK_TX_RESET_B1_CTL] =
TABLA_A_CDC_CLK_TX_RESET_B1_CTL__POR,
[TABLA_A_CDC_CLK_TX_RESET_B2_CTL] =
@@ -882,6 +911,7 @@
[TABLA_A_CDC_CLK_OTHR_CTL] = TABLA_A_CDC_CLK_OTHR_CTL__POR,
[TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL] =
TABLA_A_CDC_CLK_RDAC_CLK_EN_CTL__POR,
+ [TABLA_A_CDC_CLK_ANC_CLK_EN_CTL] = TABLA_A_CDC_CLK_ANC_CLK_EN_CTL__POR,
[TABLA_A_CDC_CLK_RX_B1_CTL] = TABLA_A_CDC_CLK_RX_B1_CTL__POR,
[TABLA_A_CDC_CLK_RX_B2_CTL] = TABLA_A_CDC_CLK_RX_B2_CTL__POR,
[TABLA_A_CDC_CLK_MCLK_CTL] = TABLA_A_CDC_CLK_MCLK_CTL__POR,
@@ -956,6 +986,8 @@
[TABLA_A_CDC_CONN_RX6_B2_CTL] = TABLA_A_CDC_CONN_RX6_B2_CTL__POR,
[TABLA_A_CDC_CONN_RX7_B1_CTL] = TABLA_A_CDC_CONN_RX7_B1_CTL__POR,
[TABLA_A_CDC_CONN_RX7_B2_CTL] = TABLA_A_CDC_CONN_RX7_B2_CTL__POR,
+ [TABLA_A_CDC_CONN_ANC_B1_CTL] = TABLA_A_CDC_CONN_ANC_B1_CTL__POR,
+ [TABLA_A_CDC_CONN_ANC_B2_CTL] = TABLA_A_CDC_CONN_ANC_B2_CTL__POR,
[TABLA_A_CDC_CONN_TX_B1_CTL] = TABLA_A_CDC_CONN_TX_B1_CTL__POR,
[TABLA_A_CDC_CONN_TX_B2_CTL] = TABLA_A_CDC_CONN_TX_B2_CTL__POR,
[TABLA_A_CDC_CONN_TX_B3_CTL] = TABLA_A_CDC_CONN_TX_B3_CTL__POR,
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 53e6212..a5dcb19 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -11,6 +11,7 @@
*/
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
@@ -35,11 +36,12 @@
TABLA_BANDGAP_MBHC_MODE,
};
-struct tabla_priv { /* member undecided */
+struct tabla_priv {
struct snd_soc_codec *codec;
u32 ref_cnt;
u32 adc_count;
u32 dec_count;
+ u32 rx_count;
enum tabla_bandgap_type bandgap_type;
bool clock_active;
bool config_mode_active;
@@ -50,25 +52,19 @@
struct snd_soc_jack *headset_jack;
struct snd_soc_jack *button_jack;
+
+ u32 anc_writes_size;
+ u32 *anc_writes;
};
static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
- struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
pr_debug("%s %d\n", __func__, event);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- if ((tabla->bandgap_type != TABLA_BANDGAP_AUDIO_MODE) ||
- (!tabla->clock_active)) {
- pr_err("%s: Error, Tabla must have clocks enabled for "
- "charge pump\n", __func__);
- return -EINVAL;
- }
-
- snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x01);
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
0x01);
snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
@@ -85,7 +81,6 @@
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
0x00);
snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
- snd_soc_update_bits(codec, TABLA_A_CP_EN, 0x01, 0x00);
break;
}
return 0;
@@ -201,6 +196,15 @@
"ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
};
+static const char const *anc_mux_text[] = {
+ "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
+ "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
+};
+
+static const char const *anc1_fb_mux_text[] = {
+ "ZERO", "EAR_HPH_L", "EAR_LINE_1",
+};
+
static const char *iir1_inp1_text[] = {
"ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
"DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
@@ -209,9 +213,15 @@
static const struct soc_enum rx_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
+static const struct soc_enum rx_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
+
static const struct soc_enum rx2_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
+static const struct soc_enum rx2_mix1_inp2_chain_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
+
static const struct soc_enum rx3_mix1_inp1_chain_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
@@ -283,15 +293,30 @@
static const struct soc_enum dec10_mux_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
+static const struct soc_enum anc1_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
+
+static const struct soc_enum anc2_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
+
+static const struct soc_enum anc1_fb_mux_enum =
+ SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
+
static const struct soc_enum iir1_inp1_mux_enum =
SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
static const struct snd_kcontrol_new rx_mix1_inp1_mux =
SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
+static const struct snd_kcontrol_new rx_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
+
static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
+static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
+ SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
+
static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
@@ -352,6 +377,8 @@
static const struct snd_kcontrol_new dec7_mux =
SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
+static const struct snd_kcontrol_new anc1_mux =
+ SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
static const struct snd_kcontrol_new dec8_mux =
SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
@@ -364,27 +391,33 @@
static const struct snd_kcontrol_new iir1_inp1_mux =
SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
-static const struct snd_kcontrol_new dac1_control =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0);
+static const struct snd_kcontrol_new anc2_mux =
+ SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
-static const struct snd_kcontrol_new hphl_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0);
+static const struct snd_kcontrol_new anc1_fb_mux =
+ SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
-static const struct snd_kcontrol_new hphr_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new lineout1_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new lineout2_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new lineout3_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
-
-static const struct snd_kcontrol_new lineout4_switch =
- SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
-
+static const struct snd_kcontrol_new dac1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
+};
+static const struct snd_kcontrol_new hphl_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
+};
+static const struct snd_kcontrol_new hphr_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_R_DAC_CTL, 6, 1, 0)
+};
+static const struct snd_kcontrol_new lineout1_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_1_DAC_CTL, 6, 1, 0)
+};
+static const struct snd_kcontrol_new lineout2_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_2_DAC_CTL, 6, 1, 0)
+};
+static const struct snd_kcontrol_new lineout3_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0)
+};
+static const struct snd_kcontrol_new lineout4_switch[] = {
+ SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0)
+};
static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
int enable)
@@ -563,13 +596,77 @@
return 0;
}
+static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ const char *filename;
+ const struct firmware *fw;
+ int i;
+ int ret;
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+ u16 reg;
+ u8 mask, val, old_val;
+
+ pr_debug("%s %d\n", __func__, event);
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ filename = "wcd9310_anc.bin";
+
+ ret = request_firmware(&fw, filename, codec->dev);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
+ ret);
+ return -ENODEV;
+ }
+
+ if (fw->size < TABLA_PACKED_REG_SIZE) {
+ dev_err(codec->dev, "Not enough data\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ /* First number is the number of register writes */
+ tabla->anc_writes_size = (u32)(*fw->data);
+
+ if (tabla->anc_writes_size >
+ ((fw->size/TABLA_PACKED_REG_SIZE) - 1)) {
+ dev_err(codec->dev, "Invalid register format\n");
+ release_firmware(fw);
+ return -ENOMEM;
+ }
+
+ tabla->anc_writes = (u32 *)(fw->data + TABLA_PACKED_REG_SIZE);
+
+ for (i = 0; i < tabla->anc_writes_size; i++) {
+ TABLA_CODEC_UNPACK_ENTRY(tabla->anc_writes[i], reg,
+ mask, val);
+ old_val = snd_soc_read(codec, reg);
+ snd_soc_write(codec, reg, (old_val & ~mask) | val);
+ }
+ release_firmware(fw);
+ tabla->anc_writes = NULL;
+
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
+ snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
+ break;
+ }
+ return 0;
+}
+
+
static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
u16 micb_cfilt_reg, micb_int_reg;
- char *internal_text = "Internal";
u8 cfilt_sel_val = 0;
+ char *internal1_text = "Internal1";
+ char *internal2_text = "Internal2";
+ char *internal3_text = "Internal3";
pr_debug("%s %d\n", __func__, event);
switch (w->reg) {
@@ -603,12 +700,23 @@
snd_soc_update_bits(codec, w->reg, 0x60, cfilt_sel_val);
snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
- if (strnstr(w->name, internal_text, 20))
+
+ if (strnstr(w->name, internal1_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
+ else if (strnstr(w->name, internal3_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
+
break;
case SND_SOC_DAPM_POST_PMD:
- if (strnstr(w->name, internal_text, 20))
+ if (strnstr(w->name, internal1_text, 30))
snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
+ else if (strnstr(w->name, internal2_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
+ else if (strnstr(w->name, internal3_text, 30))
+ snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
+
snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
break;
}
@@ -679,6 +787,18 @@
return 0;
}
+static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ usleep_range(1000, 1000);
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
/*RX stuff */
SND_SOC_DAPM_OUTPUT("EAR"),
@@ -689,36 +809,21 @@
SND_SOC_DAPM_PGA("EAR PA Input", TABLA_A_CDC_CLSG_CTL, 2, 0, NULL, 0),
- SND_SOC_DAPM_SWITCH("DAC1", TABLA_A_RX_EAR_EN, 6, 0, &dac1_control),
- SND_SOC_DAPM_PGA_E("RX1 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
- tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_PGA("RX BIAS", TABLA_A_RX_COM_BIAS, 7, 0, NULL, 0),
- SND_SOC_DAPM_MUX_E("RX1 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0,
- &rx_mix1_inp1_mux, tabla_codec_reset_interpolator,
- SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0,
- TABLA_A_CDC_RX1_B6_CTL, 5, 0),
+ SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
+ ARRAY_SIZE(dac1_switch)),
- /* RX 2 path */
- SND_SOC_DAPM_PGA_E("RX2 CP", SND_SOC_NOPM, 0, 0, NULL, 0,
- tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
- SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_MUX_E("RX2 MIX1 INP1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0,
- &rx2_mix1_inp1_mux, tabla_codec_reset_interpolator,
- SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0,
- TABLA_A_CDC_RX2_B6_CTL, 5, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
/* Headphone */
SND_SOC_DAPM_OUTPUT("HEADPHONE"),
SND_SOC_DAPM_PGA("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0),
- SND_SOC_DAPM_SWITCH("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
- &hphl_switch),
+ SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
+ hphl_switch, ARRAY_SIZE(hphl_switch)),
SND_SOC_DAPM_PGA("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0),
- SND_SOC_DAPM_SWITCH("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
- &hphr_switch),
+ SND_SOC_DAPM_MIXER("HPHR DAC", TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
+ hphr_switch, ARRAY_SIZE(hphr_switch)),
/* Speaker */
SND_SOC_DAPM_OUTPUT("LINEOUT"),
@@ -736,24 +841,39 @@
tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_SWITCH("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
- &lineout1_switch),
- SND_SOC_DAPM_SWITCH("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
- &lineout2_switch),
- SND_SOC_DAPM_SWITCH("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
- &lineout3_switch),
- SND_SOC_DAPM_SWITCH("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
- &lineout4_switch),
+ SND_SOC_DAPM_MIXER("LINEOUT1 DAC", TABLA_A_RX_LINE_1_DAC_CTL, 7, 0,
+ lineout1_switch, ARRAY_SIZE(lineout1_switch)),
+ SND_SOC_DAPM_MIXER("LINEOUT2 DAC", TABLA_A_RX_LINE_2_DAC_CTL, 7, 0,
+ lineout2_switch, ARRAY_SIZE(lineout2_switch)),
+ SND_SOC_DAPM_MIXER("LINEOUT3 DAC", TABLA_A_RX_LINE_3_DAC_CTL, 7, 0,
+ lineout3_switch, ARRAY_SIZE(lineout3_switch)),
+ SND_SOC_DAPM_MIXER("LINEOUT4 DAC", TABLA_A_RX_LINE_4_DAC_CTL, 7, 0,
+ lineout4_switch, ARRAY_SIZE(lineout4_switch)),
- SND_SOC_DAPM_PGA_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, 0,
- tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_PGA_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL, 0,
- tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_PGA_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL, 0,
- tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
- SND_SOC_DAPM_PGA_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL, 0,
- tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
+ 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
+ SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
+
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx_mix1_inp2_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp1_mux),
+ SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
+ &rx2_mix1_inp2_mux),
SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
&rx3_mix1_inp1_mux),
SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
@@ -771,12 +891,23 @@
SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
&rx6_mix1_inp2_mux),
+ SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
+ tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
+ SND_SOC_DAPM_PRE_PMD),
+
/* TX */
+
+ SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
+ tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
+
SND_SOC_DAPM_INPUT("AMIC1"),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal", TABLA_A_MICB_1_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
@@ -845,17 +976,35 @@
&dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
+ SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
+
+ SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
+ tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
+ SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
+
SND_SOC_DAPM_INPUT("AMIC2"),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal", TABLA_A_MICB_2_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
- SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal", TABLA_A_MICB_3_CTL, 7, 0,
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
+ tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
@@ -894,8 +1043,6 @@
static const struct snd_soc_dapm_route audio_map[] = {
/* SLIMBUS Connections */
- {"RX BIAS", NULL, "SLIM RX1"},
- {"RX BIAS", NULL, "SLIM RX2"},
{"SLIM TX1", NULL, "SLIM TX1 MUX"},
{"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
@@ -929,20 +1076,36 @@
{"EAR", NULL, "EAR PA"},
{"EAR PA", NULL, "EAR PA Input"},
{"EAR PA Input", NULL, "DAC1"},
- {"DAC1", "Switch", "RX1 CP"},
- {"RX1 CP", NULL, "RX1 MIX1 INP1"},
- {"RX1 MIX1 INP1", "RX1", "RX BIAS"},
+ {"DAC1", NULL, "CP"},
+
+ {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
+ {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
+ {"ANC", NULL, "ANC1 FB MUX"},
/* Headset (RX MIX1 and RX MIX2) */
{"HEADPHONE", NULL, "HPHL"},
- {"HPHL", NULL, "HPHL DAC"},
- {"HPHL DAC", "Switch", "RX1 MIX1 INP1"},
-
{"HEADPHONE", NULL, "HPHR"},
+
+ {"HPHL", NULL, "HPHL DAC"},
{"HPHR", NULL, "HPHR DAC"},
- {"HPHR DAC", "Switch", "RX2 CP"},
- {"RX2 CP", NULL, "RX2 MIX1 INP1"},
- {"RX2 MIX1 INP1", "RX2", "RX BIAS"},
+
+ {"HPHL DAC", NULL, "CP"},
+ {"HPHR DAC", NULL, "CP"},
+
+ {"ANC", NULL, "ANC1 MUX"},
+ {"ANC", NULL, "ANC2 MUX"},
+ {"ANC1 MUX", "ADC1", "ADC1"},
+ {"ANC1 MUX", "ADC2", "ADC2"},
+ {"ANC1 MUX", "ADC3", "ADC3"},
+ {"ANC1 MUX", "ADC4", "ADC4"},
+ {"ANC2 MUX", "ADC1", "ADC1"},
+ {"ANC2 MUX", "ADC2", "ADC2"},
+ {"ANC2 MUX", "ADC3", "ADC3"},
+ {"ANC2 MUX", "ADC4", "ADC4"},
+
+ {"DAC1", "Switch", "RX1 CHAIN"},
+ {"HPHL DAC", "Switch", "RX1 CHAIN"},
+ {"HPHR DAC", "Switch", "RX2 CHAIN"},
{"LINEOUT", NULL, "LINEOUT1"},
{"LINEOUT", NULL, "LINEOUT2"},
@@ -954,11 +1117,19 @@
{"LINEOUT3", NULL, "LINEOUT3 DAC"},
{"LINEOUT4", NULL, "LINEOUT4 DAC"},
+ {"RX1 CHAIN", NULL, "RX1 MIX1"},
+ {"RX2 CHAIN", NULL, "RX2 MIX1"},
+ {"RX1 CHAIN", NULL, "ANC"},
+ {"RX2 CHAIN", NULL, "ANC"},
{"LINEOUT1 DAC", "Switch", "RX3 MIX1"},
{"LINEOUT2 DAC", "Switch", "RX4 MIX1"},
{"LINEOUT3 DAC", "Switch", "RX5 MIX1"},
{"LINEOUT4 DAC", "Switch", "RX6 MIX1"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
+ {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
+ {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
{"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
{"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
@@ -968,22 +1139,32 @@
{"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
{"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
- {"RX3 MIX1 INP1", "RX1", "RX BIAS"},
- {"RX3 MIX1 INP1", "RX2", "RX BIAS"},
- {"RX3 MIX1 INP2", "RX1", "RX BIAS"},
- {"RX3 MIX1 INP2", "RX2", "RX BIAS"},
- {"RX4 MIX1 INP1", "RX1", "RX BIAS"},
- {"RX4 MIX1 INP1", "RX2", "RX BIAS"},
- {"RX4 MIX1 INP2", "RX1", "RX BIAS"},
- {"RX4 MIX1 INP2", "RX2", "RX BIAS"},
- {"RX5 MIX1 INP1", "RX1", "RX BIAS"},
- {"RX5 MIX1 INP1", "RX2", "RX BIAS"},
- {"RX5 MIX1 INP2", "RX1", "RX BIAS"},
- {"RX5 MIX1 INP2", "RX2", "RX BIAS"},
- {"RX6 MIX1 INP1", "RX1", "RX BIAS"},
- {"RX6 MIX1 INP1", "RX2", "RX BIAS"},
- {"RX6 MIX1 INP2", "RX1", "RX BIAS"},
- {"RX6 MIX1 INP2", "RX2", "RX BIAS"},
+ {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP1", "IIR1", "IIR1"},
+ {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX1 MIX1 INP2", "IIR1", "IIR1"},
+ {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
+ {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
+ {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
+ {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
/* Decimator Inputs */
{"DEC1 MUX", "DMIC1", "DMIC1"},
@@ -1009,10 +1190,20 @@
{"ADC5", NULL, "AMIC5"},
{"ADC6", NULL, "AMIC6"},
- /* Sidetone (IIR1) */
- {"RX1 MIX1 INP1", "IIR1", "IIR1"},
{"IIR1", NULL, "IIR1 INP1 MUX"},
{"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
+
+ {"MIC BIAS1 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS1 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS1 External", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS2 Internal3", NULL, "LDO_H"},
+ {"MIC BIAS2 External", NULL, "LDO_H"},
+ {"MIC BIAS3 Internal1", NULL, "LDO_H"},
+ {"MIC BIAS3 Internal2", NULL, "LDO_H"},
+ {"MIC BIAS3 External", NULL, "LDO_H"},
+ {"MIC BIAS4 External", NULL, "LDO_H"},
};
static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
@@ -1064,7 +1255,7 @@
pr_debug("reading from cache\n");
ret = snd_soc_cache_read(codec, reg, &val);
if (ret >= 0) {
- pr_debug("register %d, value %d\n", reg, val);
+ pr_debug("register %x, value %x\n", reg, val);
return val;
} else
dev_err(codec->dev, "Cache read from %x failed: %d\n",
@@ -1253,11 +1444,13 @@
tabla->ref_cnt++;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- /* Enable LDO */
snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
0xA0);
- snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
- usleep_range(1000, 1000);
+ } else {
+ tabla->rx_count++;
+ if (tabla->rx_count == 1)
+ snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
+ 0x80);
}
if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
@@ -1281,8 +1474,11 @@
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
/* Disable LDO */
- snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x00);
- usleep_range(1000, 1000);
+ } else {
+ tabla->rx_count--;
+ if (!tabla->rx_count)
+ snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
+ 0x00);
}
if (!tabla->ref_cnt) {