Unverified Commit c5fae31f authored by Mark Brown's avatar Mark Brown
Browse files

ASoC: fsl_micfil: Set default quality and channel

Merge series from Chancel Liu <chancel.liu@nxp.com>:

Add default quality for different platforms.
Set channel range control.
parents 47857dae ef1a7e02
Loading
Loading
Loading
Loading
+109 −23
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/dma/imx-dma.h>
#include <linux/log2.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -92,6 +93,9 @@ struct fsl_micfil_soc_data {
	bool volume_sx;
	u64  formats;
	int  fifo_offset;
	enum quality default_quality;
	/* stores const value in formula to calculate range */
	int rangeadj_const[3][2];
};

static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
@@ -102,6 +106,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mm = {
	.formats = SNDRV_PCM_FMTBIT_S16_LE,
	.volume_sx = true,
	.fifo_offset = 0,
	.default_quality = QUALITY_VLOW0,
};

static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
@@ -112,6 +117,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx8mp = {
	.formats = SNDRV_PCM_FMTBIT_S32_LE,
	.volume_sx = false,
	.fifo_offset = 0,
	.default_quality = QUALITY_MEDIUM,
	.rangeadj_const = {{27, 7}, {27, 7}, {26, 7}},
};

static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
@@ -124,6 +131,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx93 = {
	.use_verid = true,
	.volume_sx = false,
	.fifo_offset = 0,
	.default_quality = QUALITY_MEDIUM,
	.rangeadj_const = {{30, 6}, {30, 6}, {29, 6}},
};

static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
@@ -136,6 +145,8 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = {
	.use_verid = true,
	.volume_sx = false,
	.fifo_offset = -4,
	.default_quality = QUALITY_MEDIUM,
	.rangeadj_const = {{34, 6}, {34, 6}, {33, 6}},
};

static const struct of_device_id fsl_micfil_dt_ids[] = {
@@ -162,9 +173,69 @@ static const struct soc_enum fsl_micfil_quality_enum =

static DECLARE_TLV_DB_SCALE(gain_tlv, 0, 100, 0);

static int micfil_get_max_range(struct fsl_micfil *micfil)
{
	int max_range;

	switch (micfil->quality) {
	case QUALITY_HIGH:
	case QUALITY_VLOW0:
		max_range = micfil->soc->rangeadj_const[0][0] - micfil->soc->rangeadj_const[0][1] *
			    ilog2(2 * MICFIL_OSR_DEFAULT);
		break;
	case QUALITY_MEDIUM:
	case QUALITY_VLOW1:
		max_range = micfil->soc->rangeadj_const[1][0] - micfil->soc->rangeadj_const[1][1] *
			    ilog2(MICFIL_OSR_DEFAULT);
		break;
	case QUALITY_LOW:
	case QUALITY_VLOW2:
		max_range = micfil->soc->rangeadj_const[2][0] - micfil->soc->rangeadj_const[2][1] *
			    ilog2(MICFIL_OSR_DEFAULT);
		break;
	default:
		return 0;
	}
	max_range = max_range < 0 ? 0 : max_range;

	return max_range;
}

static int micfil_range_set(struct snd_kcontrol *kcontrol,
			    struct snd_ctl_elem_value *ucontrol)
{
	struct snd_soc_component *cmpnt = snd_kcontrol_chip(kcontrol);
	struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);
	struct soc_mixer_control *mc =
		(struct soc_mixer_control *)kcontrol->private_value;
	unsigned int shift = mc->shift;
	int max_range, new_range;

	new_range = ucontrol->value.integer.value[0];
	max_range = micfil_get_max_range(micfil);
	if (new_range > max_range)
		dev_warn(&micfil->pdev->dev, "range makes channel %d data unreliable\n", shift / 4);

	regmap_update_bits(micfil->regmap, REG_MICFIL_OUT_CTRL, 0xF << shift, new_range << shift);

	return 0;
}

static int micfil_set_quality(struct fsl_micfil *micfil)
{
	u32 qsel;
	int range, max_range;
	u32 qsel, val;
	int i;

	if (!micfil->soc->volume_sx) {
		regmap_read(micfil->regmap, REG_MICFIL_OUT_CTRL, &val);
		max_range = micfil_get_max_range(micfil);
		for (i = 0; i < micfil->soc->fifos; i++) {
			range = (val >> MICFIL_OUTGAIN_CHX_SHIFT(i)) & 0xF;
			if (range > max_range)
				dev_warn(&micfil->pdev->dev, "please reset channel %d range\n", i);
		}
	}

	switch (micfil->quality) {
	case QUALITY_HIGH:
@@ -362,23 +433,31 @@ static int hwvad_detected(struct snd_kcontrol *kcontrol,
	return 0;
}

static const struct snd_kcontrol_new fsl_micfil_volume_controls[] = {
	SOC_SINGLE_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH1 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH2 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH3 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH4 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH5 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH6 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0, gain_tlv),
	SOC_SINGLE_TLV("CH7 Volume", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0, gain_tlv),
static const struct snd_kcontrol_new fsl_micfil_range_controls[] = {
	SOC_SINGLE_EXT("CH0 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH1 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(1), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH2 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(2), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH3 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(3), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH4 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(4), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH5 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(5), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH6 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(6), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
	SOC_SINGLE_EXT("CH7 Range", REG_MICFIL_OUT_CTRL,
		       MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0,
		       snd_soc_get_volsw, micfil_range_set),
};

static const struct snd_kcontrol_new fsl_micfil_volume_sx_controls[] = {
@@ -890,13 +969,20 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
	struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
	struct device *dev = cpu_dai->dev;
	unsigned int val = 0;
	int ret, i;
	int ret, i, max_range;

	micfil->quality = QUALITY_VLOW0;
	micfil->quality = micfil->soc->default_quality;
	micfil->card = cpu_dai->component->card;

	/* set default gain to 2 */
	if (micfil->soc->volume_sx) {
		regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222);
	} else {
		max_range = micfil_get_max_range(micfil);
		for (i = 1; i < micfil->soc->fifos; i++)
			max_range |= max_range << 4;
		regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, max_range);
	}

	/* set DC Remover in bypass mode*/
	for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++)
@@ -930,8 +1016,8 @@ static int fsl_micfil_component_probe(struct snd_soc_component *component)
		snd_soc_add_component_controls(component, fsl_micfil_volume_sx_controls,
					       ARRAY_SIZE(fsl_micfil_volume_sx_controls));
	else
		snd_soc_add_component_controls(component, fsl_micfil_volume_controls,
					       ARRAY_SIZE(fsl_micfil_volume_controls));
		snd_soc_add_component_controls(component, fsl_micfil_range_controls,
					       ARRAY_SIZE(fsl_micfil_range_controls));

	return 0;
}