Unverified Commit 4f16b635 authored by Srinivas Kandagatla's avatar Srinivas Kandagatla Committed by Mark Brown
Browse files

ASoC: codecs: wcd: add common helper for wcd codecs



All the Qualcomm WCD codecs have most of its code duplicated across all
these 3/4 drivers. This is an attempt to remove those duplicate
parts by adding a common helper library for these codecs.

To start with move all the micbias parsing and voltage settings these
are identical in WCD934x, WCD937x, WCD938x and WCD939x codec driver.

Signed-off-by: default avatarSrinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Reviewed-by: default avatarDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Link: https://patch.msgid.link/20250909121954.225833-8-srinivas.kandagatla@oss.qualcomm.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 45a3295a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -2233,6 +2233,9 @@ config SND_SOC_UDA1380
config SND_SOC_WCD_CLASSH
	tristate

config SND_SOC_WCD_COMMON
	tristate

config SND_SOC_WCD9335
	tristate "WCD9335 Codec"
	depends on SLIMBUS
@@ -2254,6 +2257,7 @@ config SND_SOC_WCD934X
	select REGMAP_IRQ
	select REGMAP_SLIMBUS
	select SND_SOC_WCD_CLASSH
	select SND_SOC_WCD_COMMON
	select SND_SOC_WCD_MBHC
	depends on MFD_WCD934X || COMPILE_TEST
	help
@@ -2265,6 +2269,7 @@ config SND_SOC_WCD937X
	tristate
	depends on SOUNDWIRE || !SOUNDWIRE
	select SND_SOC_WCD_CLASSH
	select SND_SOC_WCD_COMMON

config SND_SOC_WCD937X_SDW
	tristate "WCD9370/WCD9375 Codec - SDW"
@@ -2284,6 +2289,7 @@ config SND_SOC_WCD938X
	tristate
	depends on SOUNDWIRE || !SOUNDWIRE
	select SND_SOC_WCD_CLASSH
	select SND_SOC_WCD_COMMON
	select MULTIPLEXER

config SND_SOC_WCD938X_SDW
@@ -2303,6 +2309,7 @@ config SND_SOC_WCD939X
	depends on SOUNDWIRE || !SOUNDWIRE
	depends on TYPEC || !TYPEC
	select SND_SOC_WCD_CLASSH
	select SND_SOC_WCD_COMMON

config SND_SOC_WCD939X_SDW
	tristate "WCD9390/WCD9395 Codec - SDW"
+2 −0
Original line number Diff line number Diff line
@@ -339,6 +339,7 @@ snd-soc-uda1334-y := uda1334.o
snd-soc-uda1342-y := uda1342.o
snd-soc-uda1380-y := uda1380.o
snd-soc-wcd-classh-y := wcd-clsh-v2.o
snd-soc-wcd-common-y := wcd-common.o
snd-soc-wcd-mbhc-y := wcd-mbhc-v2.o
snd-soc-wcd9335-y := wcd9335.o
snd-soc-wcd934x-y := wcd934x.o
@@ -761,6 +762,7 @@ obj-$(CONFIG_SND_SOC_UDA1334) += snd-soc-uda1334.o
obj-$(CONFIG_SND_SOC_UDA1342)	+= snd-soc-uda1342.o
obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WCD_CLASSH)	+= snd-soc-wcd-classh.o
obj-$(CONFIG_SND_SOC_WCD_COMMON)	+= snd-soc-wcd-common.o
obj-$(CONFIG_SND_SOC_WCD_MBHC)	+= snd-soc-wcd-mbhc.o
obj-$(CONFIG_SND_SOC_WCD9335)	+= snd-soc-wcd9335.o
obj-$(CONFIG_SND_SOC_WCD934X)	+= snd-soc-wcd934x.o
+70 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.

#include <linux/export.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/printk.h>

#include "wcd-common.h"

#define WCD_MIN_MICBIAS_MV	1000
#define WCD_DEF_MICBIAS_MV	1800
#define WCD_MAX_MICBIAS_MV	2850

int wcd_get_micb_vout_ctl_val(struct device *dev, u32 micb_mv)
{
	/* min micbias voltage is 1V and maximum is 2.85V */
	if (micb_mv < WCD_MIN_MICBIAS_MV || micb_mv > WCD_MAX_MICBIAS_MV) {
		dev_err(dev, "Unsupported micbias voltage (%u mV)\n", micb_mv);
		return -EINVAL;
	}

	return (micb_mv - WCD_MIN_MICBIAS_MV) / 50;
}
EXPORT_SYMBOL_GPL(wcd_get_micb_vout_ctl_val);

static int wcd_get_micbias_val(struct device *dev, int micb_num, u32 *micb_mv)
{
	char micbias[64];
	int mv;

	sprintf(micbias, "qcom,micbias%d-microvolt", micb_num);

	if (of_property_read_u32(dev->of_node, micbias, &mv)) {
		dev_err(dev, "%s value not found, using default\n", micbias);
		mv = WCD_DEF_MICBIAS_MV;
	} else {
		/* convert it to milli volts */
		mv = mv/1000;
	}
	if (micb_mv)
		*micb_mv = mv;

	mv = wcd_get_micb_vout_ctl_val(dev, mv);
	if (mv < 0) {
		dev_err(dev, "Unsupported %s voltage (%d mV), falling back to default (%d mV)\n",
				micbias, mv, WCD_DEF_MICBIAS_MV);
		return wcd_get_micb_vout_ctl_val(dev, WCD_DEF_MICBIAS_MV);
	}

	return mv;
}

int wcd_dt_parse_micbias_info(struct wcd_common *common)
{
	int i;

	for (i = 0; i < common->max_bias; i++) {
		common->micb_vout[i] = wcd_get_micbias_val(common->dev, i + 1, &common->micb_mv[i]);
		if (common->micb_vout[i] < 0)
			return -EINVAL;
	}

	return 0;
}
EXPORT_SYMBOL_GPL(wcd_dt_parse_micbias_info);
MODULE_DESCRIPTION("Common Qualcomm WCD Codec helpers driver");
MODULE_LICENSE("GPL");
+27 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2025, Qualcomm Technologies, Inc. and/or its subsidiaries.
 */

#ifndef __WCD_COMMON_H__
#define __WCD_COMMON_H__

struct device;
struct sdw_slave;
struct sdw_bus_params;
struct irq_domain;
enum sdw_slave_status;

#define WCD_MAX_MICBIAS		4

struct wcd_common {
	struct device *dev;
	int max_bias;
	u32 micb_mv[WCD_MAX_MICBIAS];
	u32 micb_vout[WCD_MAX_MICBIAS];
};

int wcd_get_micb_vout_ctl_val(struct device *dev, u32 micb_mv);
int wcd_dt_parse_micbias_info(struct wcd_common *common);

#endif /* __WCD_COMMON_H__  */
+23 −59
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "wcd-clsh-v2.h"
#include "wcd-common.h"
#include "wcd-mbhc-v2.h"

#include <dt-bindings/sound/qcom,wcd934x.h>
@@ -116,9 +117,6 @@
#define WCD934X_DEC_PWR_LVL_DF		0x00
#define WCD934X_DEC_PWR_LVL_HYBRID WCD934X_DEC_PWR_LVL_DF

#define WCD934X_DEF_MICBIAS_MV	1800
#define WCD934X_MAX_MICBIAS_MV	2850

#define WCD_IIR_FILTER_SIZE	(sizeof(u32) * BAND_MAX)

#define WCD_IIR_FILTER_CTL(xname, iidx, bidx) \
@@ -530,6 +528,7 @@ struct wcd934x_codec {
	struct slim_device *sdev;
	struct slim_device *sidev;
	struct wcd_clsh_ctrl *clsh_ctrl;
	struct wcd_common common;
	struct snd_soc_component *component;
	struct wcd934x_slim_ch rx_chs[WCD934X_RX_MAX];
	struct wcd934x_slim_ch tx_chs[WCD934X_TX_MAX];
@@ -555,7 +554,6 @@ struct wcd934x_codec {
	struct mutex micb_lock;
	u32 micb_ref[WCD934X_MAX_MICBIAS];
	u32 pullup_ref[WCD934X_MAX_MICBIAS];
	u32 micb2_mv;
};

#define to_wcd934x_codec(_hw) container_of(_hw, struct wcd934x_codec, hw)
@@ -2168,55 +2166,24 @@ static struct clk *wcd934x_register_mclk_output(struct wcd934x_codec *wcd)
	return NULL;
}

static int wcd934x_get_micbias_val(struct device *dev, const char *micbias,
				   u32 *micb_mv)
{
	int mv;

	if (of_property_read_u32(dev->parent->of_node, micbias, &mv)) {
		dev_err(dev, "%s value not found, using default\n", micbias);
		mv = WCD934X_DEF_MICBIAS_MV;
	} else {
		/* convert it to milli volts */
		mv = mv/1000;
	}

	if (mv < 1000 || mv > 2850) {
		dev_err(dev, "%s value not in valid range, using default\n",
			micbias);
		mv = WCD934X_DEF_MICBIAS_MV;
	}

	if (micb_mv)
		*micb_mv = mv;

	return (mv - 1000) / 50;
}

static int wcd934x_init_dmic(struct snd_soc_component *comp)
{
	int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4;
	struct wcd934x_codec *wcd = dev_get_drvdata(comp->dev);
	u32 def_dmic_rate, dmic_clk_drv;
	int ret;

	vout_ctl_1 = wcd934x_get_micbias_val(comp->dev,
					     "qcom,micbias1-microvolt", NULL);
	vout_ctl_2 = wcd934x_get_micbias_val(comp->dev,
					     "qcom,micbias2-microvolt",
					     &wcd->micb2_mv);
	vout_ctl_3 = wcd934x_get_micbias_val(comp->dev,
					     "qcom,micbias3-microvolt", NULL);
	vout_ctl_4 = wcd934x_get_micbias_val(comp->dev,
					     "qcom,micbias4-microvolt", NULL);
	ret = wcd_dt_parse_mbhc_data(comp->dev, &wcd->mbhc_cfg);
	if (ret)
		return ret;

	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB1,
				      WCD934X_MICB_VAL_MASK, vout_ctl_1);
				      WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[0]);
	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB2,
				      WCD934X_MICB_VAL_MASK, vout_ctl_2);
				      WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[1]);
	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB3,
				      WCD934X_MICB_VAL_MASK, vout_ctl_3);
				      WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[2]);
	snd_soc_component_update_bits(comp, WCD934X_ANA_MICB4,
				      WCD934X_MICB_VAL_MASK, vout_ctl_4);
				      WCD934X_MICB_VAL_MASK, wcd->common.micb_vout[3]);

	if (wcd->rate == WCD934X_MCLK_CLK_9P6MHZ)
		def_dmic_rate = WCD9XXX_DMIC_SAMPLE_RATE_4P8MHZ;
@@ -2517,15 +2484,6 @@ static void wcd934x_mbhc_micb_ramp_control(struct snd_soc_component *component,
	}
}

static int wcd934x_get_micb_vout_ctl_val(u32 micb_mv)
{
	/* min micbias voltage is 1V and maximum is 2.85V */
	if (micb_mv < 1000 || micb_mv > 2850)
		return -EINVAL;

	return (micb_mv - 1000) / 50;
}

static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
					    int req_volt, int micb_num)
{
@@ -2562,7 +2520,7 @@ static int wcd934x_mbhc_micb_adjust_voltage(struct snd_soc_component *component,
	cur_vout_ctl = snd_soc_component_read_field(component, micb_reg,
						    WCD934X_MICB_VAL_MASK);

	req_vout_ctl = wcd934x_get_micb_vout_ctl_val(req_volt);
	req_vout_ctl = wcd_get_micb_vout_ctl_val(component->dev, req_volt);
	if (req_vout_ctl < 0) {
		ret = -EINVAL;
		goto exit;
@@ -2610,10 +2568,10 @@ static int wcd934x_mbhc_micb_ctrl_threshold_mic(struct snd_soc_component *compon
	 * voltage needed to detect threshold microphone, then do
	 * not change the micbias, just return.
	 */
	if (wcd934x->micb2_mv >= WCD_MBHC_THR_HS_MICB_MV)
	if (wcd934x->common.micb_mv[1] >= WCD_MBHC_THR_HS_MICB_MV)
		return 0;

	micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd934x->micb2_mv;
	micb_mv = req_en ? WCD_MBHC_THR_HS_MICB_MV : wcd934x->common.micb_mv[1];

	rc = wcd934x_mbhc_micb_adjust_voltage(component, micb_mv, MIC_BIAS_2);

@@ -3036,7 +2994,7 @@ static void wcd934x_mbhc_deinit(struct snd_soc_component *component)
static int wcd934x_comp_probe(struct snd_soc_component *component)
{
	struct wcd934x_codec *wcd = dev_get_drvdata(component->dev);
	int i;
	int i, ret;

	snd_soc_component_init_regmap(component, wcd->regmap);
	wcd->component = component;
@@ -3054,7 +3012,12 @@ static int wcd934x_comp_probe(struct snd_soc_component *component)
	for (i = 0; i < NUM_CODEC_DAIS; i++)
		INIT_LIST_HEAD(&wcd->dai[i].slim_ch_list);

	wcd934x_init_dmic(component);

	ret = wcd934x_init_dmic(component);
	if (ret) {
		dev_err(component->dev, "Failed to Initialize micbias\n");
		return ret;
	}

	if (wcd934x_mbhc_init(component))
		dev_err(component->dev, "Failed to Initialize MBHC\n");
@@ -5860,14 +5823,13 @@ static int wcd934x_codec_parse_data(struct wcd934x_codec *wcd)
	cfg->anc_micbias = MIC_BIAS_2;
	cfg->v_hs_max = WCD_MBHC_HS_V_MAX;
	cfg->num_btn = WCD934X_MBHC_MAX_BUTTONS;
	cfg->micb_mv = wcd->micb2_mv;
	cfg->micb_mv = wcd->common.micb_mv[1];
	cfg->linein_th = 5000;
	cfg->hs_thr = 1700;
	cfg->hph_thr = 50;

	wcd_dt_parse_mbhc_data(dev, cfg);


	return 0;
}

@@ -5888,6 +5850,8 @@ static int wcd934x_codec_probe(struct platform_device *pdev)
	wcd->sdev = to_slim_device(data->dev);
	mutex_init(&wcd->sysclk_mutex);
	mutex_init(&wcd->micb_lock);
	wcd->common.dev = dev->parent;
	wcd->common.max_bias = 4;

	ret = wcd934x_codec_parse_data(wcd);
	if (ret)
Loading