Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13e4ea85 authored by Bhalchandra Gajare's avatar Bhalchandra Gajare
Browse files

ASoC: wcd9xxx: Use common functionality to change micbias voltage



Currently helicon codec driver hardcodes the micbias voltage to 1.8
volts and hence does not support micbias voltage other than 1.8 volts.
Add support for the helicon codec driver to use the existing common
drivers to be able to support micbias voltages other than 1.8 volts.

CRs-fixed: 537966, 554536
Change-Id: I3475ea744b3b2518eaa2c4153551af1a4d95afc8
Signed-off-by: default avatarBhalchandra Gajare <gajare@codeaurora.org>
parent f4248170
Loading
Loading
Loading
Loading
+69 −16
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
	struct msm8x10_wcd_regulator *vreg,
	const char *vreg_name, bool ondemand);
static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
	struct msm8x10_wcd_micbias_setting *micbias);
	struct wcd9xxx_micbias_setting *micbias);
static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
	struct device *dev);

@@ -625,12 +625,23 @@ static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
}

static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
	struct msm8x10_wcd_micbias_setting *micbias)
	struct wcd9xxx_micbias_setting *micbias)
{
	int ret = 0;
	char prop_name[CODEC_DT_MAX_PROP_SIZE];
	u32 prop_val;

	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
		 "qcom,cdc-micbias-ldoh-v");
	ret = of_property_read_u32(dev->of_node, prop_name,
				   &prop_val);
	if (ret) {
		dev_err(dev, "Looking up %s property in node %s failed",
			prop_name, dev->of_node->full_name);
		return -ENODEV;
	}
	micbias->ldoh_v = (u8) prop_val;

	snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
		 "qcom,cdc-micbias-cfilt-mv");
	ret = of_property_read_u32(dev->of_node, prop_name,
@@ -2531,7 +2542,7 @@ static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {

	/* Disable internal biasing path which can cause leakage */
	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),

	/* Enable pulldown to reduce leakage */
	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
	MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
@@ -3061,6 +3072,41 @@ static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
	.hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
};

static int msm8x10_wcd_handle_pdata(struct snd_soc_codec *codec,
	struct msm8x10_wcd_pdata *pdata)
{
	int k1, rc = 0;
	struct msm8x10_wcd_priv *msm8x10_wcd_priv;

	msm8x10_wcd_priv = snd_soc_codec_get_drvdata(codec);

	/* Make sure settings are correct */
	if (pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V ||
	    pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT1_SEL) {
		rc = -EINVAL;
		goto done;
	}

	/* figure out k value */
	k1 = wcd9xxx_resmgr_get_k_val(&msm8x10_wcd_priv->resmgr,
				 pdata->micbias.cfilt1_mv);
	if (IS_ERR_VALUE(k1)) {
		rc = -EINVAL;
		goto done;
	}

	/* Set voltage level */
	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_VAL,
			    0xFC, (k1 << 2));

	/* update micbias capless mode */
	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
			    pdata->micbias.bias1_cap_mode << 4);

done:
	return rc;
}

static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
{
	struct msm8x10_wcd_priv *msm8x10_wcd_priv;
@@ -3097,12 +3143,18 @@ static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
	INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
			delayed_hs_detect_fn);

	pdata = dev_get_platdata(msm8x10_wcd->dev);
	if (!pdata) {
		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
			__func__);
	}

	/* codec resmgr module init */
	msm8x10_wcd = codec->control_data;
	core_res = &msm8x10_wcd->wcd9xxx_res;
	ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
				codec, core_res, NULL, NULL,
				WCD9XXX_CDC_TYPE_HELICON);
				codec, core_res, NULL, &pdata->micbias,
				NULL, WCD9XXX_CDC_TYPE_HELICON);
	if (ret) {
		dev_err(codec->dev,
				"%s: wcd9xxx init failed %d\n",
@@ -3114,16 +3166,6 @@ static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
	msm8x10_wcd_codec_init_reg(codec);
	msm8x10_wcd_update_reg_defaults(codec);

	pdata = dev_get_platdata(msm8x10_wcd->dev);
	if (!pdata) {
		dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
			__func__);
	}

	/* update micbias capless mode */
	snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
			    pdata->micbias.bias1_cap_mode << 4);

	msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
				wcd8x10_wcd_codec_find_regulator(
				codec->control_data,
@@ -3140,10 +3182,16 @@ static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
				codec, NULL, &mbhc_cb, &cdc_intr_ids,
				HELICON_MCLK_CLK_9P6MHZ, true);
	if (ret) {
		pr_err("%s: Failed to initialize mbhc\n", __func__);
		dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
			__func__);
		goto exit_probe;
	}

	/* Handle the Pdata */
	ret = msm8x10_wcd_handle_pdata(codec, pdata);
	if (IS_ERR_VALUE(ret))
		dev_err(msm8x10_wcd->dev, "%s: Bad Pdata\n", __func__);

	registered_codec = codec;
	adsp_state_notifier =
	    subsys_notif_register_notifier("adsp",
@@ -3448,6 +3496,11 @@ static int msm8x10_wcd_i2c_probe(struct i2c_client *client,
		dev_dbg(&client->dev, "%s:Platform data from device tree\n",
			__func__);
		pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
		if (!pdata) {
			dev_err(&client->dev, "%s: Failed to parse pdata from device tree\n",
				__func__);
			goto rtn;
		}
		client->dev.platform_data = pdata;
	} else {
		dev_dbg(&client->dev, "%s:Platform data from board file\n",
+2 −23
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <sound/jack.h>
#include "wcd9xxx-mbhc.h"
#include "wcd9xxx-resmgr.h"
#include <linux/mfd/wcd9xxx/pdata.h>

#define MSM8X10_WCD_NUM_REGISTERS	0x600
#define MSM8X10_WCD_MAX_REGISTER	(MSM8X10_WCD_NUM_REGISTERS-1)
@@ -113,28 +114,6 @@ enum {
	MSM8X10_WCD_NUM_IRQS,
};

/*
 * Each micbias can be assigned to one of three cfilters
 * Vbatt_min >= .15V + ldoh_v
 * ldoh_v >= .15v + cfiltx_mv
 * If ldoh_v = 1.95 160 mv < cfiltx_mv < 1800 mv
 * If ldoh_v = 2.35 200 mv < cfiltx_mv < 2200 mv
 * If ldoh_v = 2.75 240 mv < cfiltx_mv < 2600 mv
 * If ldoh_v = 2.85 250 mv < cfiltx_mv < 2700 mv
 */
struct msm8x10_wcd_micbias_setting {
	u8 ldoh_v;
	u32 cfilt1_mv; /* in mv */
	/*
	 * Different WCD9xxx series codecs may not
	 * have 4 mic biases. If a codec has fewer
	 * mic biases, some of these properties will
	 * not be used.
	 */
	u8 bias1_cfilt_sel;
	u8 bias1_cap_mode;
};

struct msm8x10_wcd_ocp_setting {
	unsigned int	use_pdata:1; /* 0 - use sys default as recommended */
	unsigned int	num_attempts:4; /* up to 15 attempts */
@@ -158,7 +137,7 @@ struct msm8x10_wcd_pdata {
	int num_irqs;
	int reset_gpio;
	void *msm8x10_wcd_ahb_base_vaddr;
	struct msm8x10_wcd_micbias_setting micbias;
	struct wcd9xxx_micbias_setting micbias;
	struct msm8x10_wcd_ocp_setting ocp;
	struct msm8x10_wcd_regulator regulator[MAX_REGULATOR];
	u32 mclk_rate;
+2 −1
Original line number Diff line number Diff line
@@ -5709,7 +5709,8 @@ static int tapan_codec_probe(struct snd_soc_codec *codec)
	core_res = &wcd9xxx->core_res;
	pdata = dev_get_platdata(codec->dev->parent);
	ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
				  &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
				  &pdata->micbias, &tapan_reg_address,
				  WCD9XXX_CDC_TYPE_TAPAN);
	if (ret) {
		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
		return ret;
+2 −1
Original line number Diff line number Diff line
@@ -6766,7 +6766,8 @@ static int taiko_codec_probe(struct snd_soc_codec *codec)
	core_res = &wcd9xxx->core_res;
	pdata = dev_get_platdata(codec->dev->parent);
	ret = wcd9xxx_resmgr_init(&taiko->resmgr, codec, core_res, pdata,
				  &taiko_reg_address, WCD9XXX_CDC_TYPE_TAIKO);
				  &pdata->micbias, &taiko_reg_address,
				  WCD9XXX_CDC_TYPE_TAIKO);
	if (ret) {
		pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
		goto err_init;
+15 −33
Original line number Diff line number Diff line
@@ -263,11 +263,6 @@ static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
static int __wcd9xxx_resmgr_get_k_val(struct wcd9xxx_mbhc *mbhc,
		unsigned int cfilt_mv)
{
	if (mbhc->mbhc_cb &&
			mbhc->mbhc_cb->get_cdc_type() ==
					WCD9XXX_CDC_TYPE_HELICON)
		return 0x18;

	return wcd9xxx_resmgr_get_k_val(mbhc->resmgr, cfilt_mv);
}

@@ -592,41 +587,30 @@ static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
					struct mbhc_micbias_regs *micbias_regs)
{
	unsigned int cfilt;
	struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;

	if (mbhc->mbhc_cb &&
			mbhc->mbhc_cb->get_cdc_type() ==
					WCD9XXX_CDC_TYPE_HELICON) {
		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
		mbhc->mbhc_data.micb_mv = 1800;
		return;
	}
	struct wcd9xxx_micbias_setting *micbias_pdata =
		mbhc->resmgr->micbias_pdata;

	switch (mbhc->mbhc_cfg->micbias) {
	case MBHC_MICBIAS1:
		cfilt = pdata->micbias.bias1_cfilt_sel;
		cfilt = micbias_pdata->bias1_cfilt_sel;
		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
		micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
		micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
		break;
	case MBHC_MICBIAS2:
		cfilt = pdata->micbias.bias2_cfilt_sel;
		cfilt = micbias_pdata->bias2_cfilt_sel;
		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_2_MBHC;
		micbias_regs->int_rbias = WCD9XXX_A_MICB_2_INT_RBIAS;
		micbias_regs->ctl_reg = WCD9XXX_A_MICB_2_CTL;
		break;
	case MBHC_MICBIAS3:
		cfilt = pdata->micbias.bias3_cfilt_sel;
		cfilt = micbias_pdata->bias3_cfilt_sel;
		micbias_regs->mbhc_reg = WCD9XXX_A_MICB_3_MBHC;
		micbias_regs->int_rbias = WCD9XXX_A_MICB_3_INT_RBIAS;
		micbias_regs->ctl_reg = WCD9XXX_A_MICB_3_CTL;
		break;
	case MBHC_MICBIAS4:
		cfilt = pdata->micbias.bias4_cfilt_sel;
		cfilt = micbias_pdata->bias4_cfilt_sel;
		micbias_regs->mbhc_reg = mbhc->resmgr->reg_addr->micb_4_mbhc;
		micbias_regs->int_rbias =
		    mbhc->resmgr->reg_addr->micb_4_int_rbias;
@@ -644,20 +628,17 @@ static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
	case WCD9XXX_CFILT1_SEL:
		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
		mbhc->mbhc_data.micb_mv =
		    mbhc->resmgr->pdata->micbias.cfilt1_mv;
		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt1_mv;
		break;
	case WCD9XXX_CFILT2_SEL:
		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
		mbhc->mbhc_data.micb_mv =
		    mbhc->resmgr->pdata->micbias.cfilt2_mv;
		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt2_mv;
		break;
	case WCD9XXX_CFILT3_SEL:
		micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
		micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
		mbhc->mbhc_data.micb_mv =
		    mbhc->resmgr->pdata->micbias.cfilt3_mv;
		mbhc->mbhc_data.micb_mv = micbias_pdata->cfilt3_mv;
		break;
	}
}
@@ -4115,20 +4096,21 @@ static int wcd9xxx_event_to_cfilt(const enum wcd9xxx_notify_event event)
static int wcd9xxx_get_mbhc_cfilt_sel(struct wcd9xxx_mbhc *mbhc)
{
	int cfilt;
	const struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
	const struct wcd9xxx_micbias_setting *mb_pdata =
		mbhc->resmgr->micbias_pdata;

	switch (mbhc->mbhc_cfg->micbias) {
	case MBHC_MICBIAS1:
		cfilt = pdata->micbias.bias1_cfilt_sel;
		cfilt = mb_pdata->bias1_cfilt_sel;
		break;
	case MBHC_MICBIAS2:
		cfilt = pdata->micbias.bias2_cfilt_sel;
		cfilt = mb_pdata->bias2_cfilt_sel;
		break;
	case MBHC_MICBIAS3:
		cfilt = pdata->micbias.bias3_cfilt_sel;
		cfilt = mb_pdata->bias3_cfilt_sel;
		break;
	case MBHC_MICBIAS4:
		cfilt = pdata->micbias.bias4_cfilt_sel;
		cfilt = mb_pdata->bias4_cfilt_sel;
		break;
	default:
		cfilt = MBHC_MICBIAS_INVALID;
Loading