summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xinclude/uapi/linux/mfd/wcd9xxx/Kbuild1
-rw-r--r--[-rwxr-xr-x]include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h (renamed from include/linux/mfd/wcd9xxx/wcd9xxx_registers.h)9
-rwxr-xr-xsound/soc/codecs/wcd9335.c23
-rw-r--r--sound/soc/codecs/wcd9xxx-common-v2.c152
-rw-r--r--sound/soc/codecs/wcd9xxx-common-v2.h10
5 files changed, 193 insertions, 2 deletions
diff --git a/include/uapi/linux/mfd/wcd9xxx/Kbuild b/include/uapi/linux/mfd/wcd9xxx/Kbuild
index da9fe03b0bed..8e55965bbe7e 100755
--- a/include/uapi/linux/mfd/wcd9xxx/Kbuild
+++ b/include/uapi/linux/mfd/wcd9xxx/Kbuild
@@ -1 +1,2 @@
+header-y += wcd9xxx_registers.h
header-y += wcd9320_registers.h
diff --git a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h
index 1dac14bd8427..8a3f41afee8e 100755..100644
--- a/include/linux/mfd/wcd9xxx/wcd9xxx_registers.h
+++ b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h
@@ -341,4 +341,13 @@
#define WCD9XXX_CDC_RX2_RX_PATH_CTL (0xB69)
#define WCD9XXX_CDC_CLK_RST_CTRL_MCLK_CONTROL (0xD41)
#define WCD9XXX_CLASSH_CTRL_CCL_1 (0x69C)
+
+/* RX Gain control registers of codecs from and above WCD9335 */
+#define WCD9XXX_CDC_RX1_RX_VOL_CTL (0xB59)
+#define WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL (0xB5C)
+#define WCD9XXX_CDC_RX1_RX_PATH_SEC1 (0xB5E)
+#define WCD9XXX_CDC_RX2_RX_VOL_CTL (0xB6D)
+#define WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL (0xB70)
+#define WCD9XXX_CDC_RX2_RX_PATH_SEC1 (0xB72)
+
#endif
diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c
index 6d75693e5c4d..4c3ca7d1d03f 100755
--- a/sound/soc/codecs/wcd9335.c
+++ b/sound/soc/codecs/wcd9335.c
@@ -355,6 +355,7 @@ enum {
ANC_MIC_AMIC4,
ANC_MIC_AMIC5,
ANC_MIC_AMIC6,
+ CLASSH_CONFIG,
};
enum {
@@ -4461,6 +4462,7 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
int hph_mode = tasha->hph_mode;
u8 dem_inp;
int ret = 0;
+ uint32_t impedl = 0, impedr = 0;
dev_dbg(codec->dev, "%s wname: %s event: %d hph_mode: %d\n", __func__,
w->name, event, hph_mode);
@@ -4494,6 +4496,16 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
snd_soc_update_bits(codec,
WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x10);
+ ret = wcd_mbhc_get_impedance(&tasha->mbhc,
+ &impedl, &impedr);
+ if (!ret) {
+ wcd_clsh_imped_config(codec, impedl, false);
+ set_bit(CLASSH_CONFIG, &tasha->status_mask);
+ } else
+ dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
+ __func__, ret);
+
+
break;
case SND_SOC_DAPM_POST_PMU:
/* 1000us required as per HW requirement */
@@ -4523,6 +4535,15 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
WCD_CLSH_STATE_HPHL,
((hph_mode == CLS_H_LOHIFI) ?
CLS_H_HIFI : hph_mode));
+
+ if (test_bit(CLASSH_CONFIG, &tasha->status_mask)) {
+ wcd_clsh_imped_config(codec, impedl, true);
+ clear_bit(CLASSH_CONFIG, &tasha->status_mask);
+ } else
+ dev_dbg(codec->dev, "%s: Failed to get mbhc impedance %d\n",
+ __func__, ret);
+
+
break;
};
@@ -11888,7 +11909,7 @@ static const struct tasha_reg_mask_val tasha_codec_reg_init_val_2_0[] = {
{WCD9335_RCO_CTRL_2, 0x0F, 0x08},
{WCD9335_RX_BIAS_FLYB_MID_RST, 0xF0, 0x10},
{WCD9335_FLYBACK_CTRL_1, 0x20, 0x20},
- {WCD9335_HPH_OCP_CTL, 0xFF, 0x5A},
+ {WCD9335_HPH_OCP_CTL, 0xFF, 0x7A},
{WCD9335_HPH_L_TEST, 0x01, 0x01},
{WCD9335_HPH_R_TEST, 0x01, 0x01},
{WCD9335_CDC_BOOST0_BOOST_CFG1, 0x3F, 0x12},
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c
index 5d4ac1f99de0..8da04e5cbd08 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.c
+++ b/sound/soc/codecs/wcd9xxx-common-v2.c
@@ -21,6 +21,7 @@
#include "wcd9xxx-common-v2.h"
#define WCD_USLEEP_RANGE 50
+#define MAX_IMPED_PARAMS 6
enum {
DAC_GAIN_0DB = 0,
@@ -49,10 +50,161 @@ enum {
DELTA_I_50MA,
};
+struct wcd_imped_val {
+ u32 imped_val;
+ u8 index;
+};
+
+static const struct wcd_reg_mask_val imped_table[][MAX_IMPED_PARAMS] = {
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf5},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf5},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf5},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf5},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf7},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x0},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xf9},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x0},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfa},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfb},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfc},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfd},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xfe},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xfe},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x01},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xfe},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xfe},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x01},
+ },
+ {
+ {WCD9XXX_CDC_RX1_RX_VOL_CTL, 0xff, 0xff},
+ {WCD9XXX_CDC_RX1_RX_VOL_MIX_CTL, 0xff, 0xff},
+ {WCD9XXX_CDC_RX1_RX_PATH_SEC1, 0x01, 0x00},
+ {WCD9XXX_CDC_RX2_RX_VOL_CTL, 0xff, 0xff},
+ {WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL, 0xff, 0xff},
+ {WCD9XXX_CDC_RX2_RX_PATH_SEC1, 0x01, 0x00},
+ },
+};
+
+static const struct wcd_imped_val imped_index[] = {
+ {4, 0},
+ {5, 1},
+ {6, 2},
+ {7, 3},
+ {8, 4},
+ {9, 5},
+ {10, 6},
+ {11, 7},
+ {12, 8},
+ {13, 9},
+};
+
static void (*clsh_state_fp[NUM_CLSH_STATES_V2])(struct snd_soc_codec *,
struct wcd_clsh_cdc_data *,
u8 req_state, bool en, int mode);
+static int get_impedance_index(int imped)
+{
+ int i = 0;
+
+ if (imped < imped_index[i].imped_val) {
+ pr_debug("%s, detected impedance is less than 4 Ohm\n",
+ __func__);
+ i = 0;
+ goto ret;
+ }
+ if (imped >= imped_index[ARRAY_SIZE(imped_index) - 1].imped_val) {
+ pr_debug("%s, detected impedance is greater than 12 Ohm\n",
+ __func__);
+ i = ARRAY_SIZE(imped_index) - 1;
+ goto ret;
+ }
+ for (i = 0; i < ARRAY_SIZE(imped_index) - 1; i++) {
+ if (imped >= imped_index[i].imped_val &&
+ imped < imped_index[i + 1].imped_val)
+ break;
+ }
+ret:
+ pr_debug("%s: selected impedance index = %d\n",
+ __func__, imped_index[i].index);
+ return imped_index[i].index;
+}
+
+/*
+ * Function: wcd_clsh_imped_config
+ * Params: codec, imped, reset
+ * Description:
+ * This function updates HPHL and HPHR gain settings
+ * according to the impedance value.
+ */
+void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped, bool reset)
+{
+ int i;
+ int index = 0;
+
+ /* reset = 1, which means request is to reset the register values */
+ if (reset) {
+ for (i = 0; i < MAX_IMPED_PARAMS; i++)
+ snd_soc_update_bits(codec, imped_table[index][i].reg,
+ imped_table[index][i].mask, 0);
+ return;
+ }
+ index = get_impedance_index(imped);
+ if (index >= (ARRAY_SIZE(imped_index) - 1)) {
+ pr_debug("%s, impedance not in range = %d\n", __func__, imped);
+ return;
+ }
+ for (i = 0; i < MAX_IMPED_PARAMS; i++)
+ snd_soc_update_bits(codec, imped_table[index][i].reg,
+ imped_table[index][i].mask,
+ imped_table[index][i].val);
+}
+EXPORT_SYMBOL(wcd_clsh_imped_config);
+
static bool is_native_44_1_active(struct snd_soc_codec *codec)
{
bool native_active = false;
diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h
index 2ad91189d3cb..d3c52e73a7da 100644
--- a/sound/soc/codecs/wcd9xxx-common-v2.h
+++ b/sound/soc/codecs/wcd9xxx-common-v2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, 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
@@ -136,6 +136,12 @@ struct vbat_monitor_reg {
u32 writes[MAX_VBAT_MONITOR_WRITES];
} __packed;
+struct wcd_reg_mask_val {
+ u16 reg;
+ u8 mask;
+ u8 val;
+};
+
extern void wcd_clsh_fsm(struct snd_soc_codec *codec,
struct wcd_clsh_cdc_data *cdc_clsh_d,
u8 clsh_event, u8 req_state,
@@ -143,6 +149,8 @@ extern void wcd_clsh_fsm(struct snd_soc_codec *codec,
extern void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh);
extern int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh);
+extern void wcd_clsh_imped_config(struct snd_soc_codec *codec, int imped,
+ bool reset);
enum {
RESERVED = 0,