diff options
-rwxr-xr-x | include/uapi/linux/mfd/wcd9xxx/Kbuild | 1 | ||||
-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-x | sound/soc/codecs/wcd9335.c | 23 | ||||
-rw-r--r-- | sound/soc/codecs/wcd9xxx-common-v2.c | 152 | ||||
-rw-r--r-- | sound/soc/codecs/wcd9xxx-common-v2.h | 10 |
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, |