Skip to content

Commit

Permalink
ASoC: fsl_micfil: rework quality setting
Browse files Browse the repository at this point in the history
For the quality setting the quality setting register values are directly
exposed to the kcontrol and thus to userspace. This is unfortunate
because the register settings contains invalid bit combinations marked
as "N/A". For userspace it doesn't make much sense to be able to set
these just to see that the driver responds with "Please make sure you
select a valid quality." in the kernel log.

Work around this by adding get/set functions for the quality setting.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Acked-by: Shengjiu Wang <shengjiu.wang@gmail.com>
Link: https://lore.kernel.org/r/20220414162249.3934543-17-s.hauer@pengutronix.de
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Sascha Hauer authored and Mark Brown committed Apr 19, 2022
1 parent e8936f6 commit bea1d61
Showing 1 changed file with 78 additions and 31 deletions.
109 changes: 78 additions & 31 deletions sound/soc/fsl/fsl_micfil.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@

#define MICFIL_OSR_DEFAULT 16

enum quality {
QUALITY_HIGH,
QUALITY_MEDIUM,
QUALITY_LOW,
QUALITY_VLOW0,
QUALITY_VLOW1,
QUALITY_VLOW2,
};

struct fsl_micfil {
struct platform_device *pdev;
struct regmap *regmap;
Expand All @@ -42,7 +51,7 @@ struct fsl_micfil {
unsigned int dataline;
char name[32];
int irq[MICFIL_IRQ_LINES];
int quality; /*QUALITY 2-0 bits */
enum quality quality;
};

struct fsl_micfil_soc_data {
Expand All @@ -65,29 +74,73 @@ static const struct of_device_id fsl_micfil_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, fsl_micfil_dt_ids);

/* Table 5. Quality Modes
* Medium 0 0 0
* High 0 0 1
* Very Low 2 1 0 0
* Very Low 1 1 0 1
* Very Low 0 1 1 0
* Low 1 1 1
*/
static const char * const micfil_quality_select_texts[] = {
"Medium", "High",
"N/A", "N/A",
"VLow2", "VLow1",
"VLow0", "Low",
[QUALITY_HIGH] = "High",
[QUALITY_MEDIUM] = "Medium",
[QUALITY_LOW] = "Low",
[QUALITY_VLOW0] = "VLow0",
[QUALITY_VLOW1] = "Vlow1",
[QUALITY_VLOW2] = "Vlow2",
};

static const struct soc_enum fsl_micfil_quality_enum =
SOC_ENUM_SINGLE(REG_MICFIL_CTRL2,
MICFIL_CTRL2_QSEL_SHIFT,
ARRAY_SIZE(micfil_quality_select_texts),
micfil_quality_select_texts);
SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(micfil_quality_select_texts),
micfil_quality_select_texts);

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

static int micfil_set_quality(struct fsl_micfil *micfil)
{
u32 qsel;

switch (micfil->quality) {
case QUALITY_HIGH:
qsel = MICFIL_QSEL_HIGH_QUALITY;
break;
case QUALITY_MEDIUM:
qsel = MICFIL_QSEL_MEDIUM_QUALITY;
break;
case QUALITY_LOW:
qsel = MICFIL_QSEL_LOW_QUALITY;
break;
case QUALITY_VLOW0:
qsel = MICFIL_QSEL_VLOW0_QUALITY;
break;
case QUALITY_VLOW1:
qsel = MICFIL_QSEL_VLOW1_QUALITY;
break;
case QUALITY_VLOW2:
qsel = MICFIL_QSEL_VLOW2_QUALITY;
break;
}

return regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_QSEL,
FIELD_PREP(MICFIL_CTRL2_QSEL, qsel));
}

static int micfil_quality_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);

ucontrol->value.integer.value[0] = micfil->quality;

return 0;
}

static int micfil_quality_set(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
struct fsl_micfil *micfil = snd_soc_component_get_drvdata(cmpnt);

micfil->quality = ucontrol->value.integer.value[0];

return micfil_set_quality(micfil);
}

static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
SOC_SINGLE_SX_TLV("CH0 Volume", REG_MICFIL_OUT_CTRL,
MICFIL_OUTGAIN_CHX_SHIFT(0), 0xF, 0x7, gain_tlv),
Expand All @@ -107,7 +160,7 @@ static const struct snd_kcontrol_new fsl_micfil_snd_controls[] = {
MICFIL_OUTGAIN_CHX_SHIFT(7), 0xF, 0x7, gain_tlv),
SOC_ENUM_EXT("MICFIL Quality Select",
fsl_micfil_quality_enum,
snd_soc_get_enum_double, snd_soc_put_enum_double),
micfil_quality_get, micfil_quality_set),
};

/* The SRES is a self-negated bit which provides the CPU with the
Expand Down Expand Up @@ -207,22 +260,21 @@ static int fsl_set_clock_params(struct device *dev, unsigned int rate)
{
struct fsl_micfil *micfil = dev_get_drvdata(dev);
int clk_div = 8;
int osr = MICFIL_OSR_DEFAULT;
int ret;

ret = clk_set_rate(micfil->mclk, rate * clk_div * MICFIL_OSR_DEFAULT * 8);
ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8);
if (ret)
return ret;

/* set CICOSR */
ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_CICOSR,
FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - MICFIL_OSR_DEFAULT));
ret = micfil_set_quality(micfil);
if (ret)
return ret;

ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_CLKDIV,
FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div));
MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR,
FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) |
FIELD_PREP(MICFIL_CTRL2_CICOSR, 16 - osr));

return ret;
}
Expand Down Expand Up @@ -275,12 +327,7 @@ static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai)
struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev);
int ret;

/* set qsel to medium */
ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2,
MICFIL_CTRL2_QSEL,
FIELD_PREP(MICFIL_CTRL2_QSEL, MICFIL_QSEL_MEDIUM_QUALITY));
if (ret)
return ret;
micfil->quality = QUALITY_MEDIUM;

/* set default gain to max_gain */
regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777);
Expand Down

0 comments on commit bea1d61

Please sign in to comment.