diff options
author | Charles Keepax <ckeepax@opensource.wolfsonmicro.com> | 2015-06-25 09:35:11 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-07-07 13:15:12 +0100 |
commit | c05d9a8c7f55a901d9e8ec2a5f0730137bbfea4a (patch) | |
tree | a6e6382dc10ce2aaf458f8b1e1e36b0898620e7f /sound/soc/codecs/arizona.c | |
parent | d770e558e21961ad6cfdf0ff7df0eb5d7d4f0754 (diff) | |
download | linux-next-c05d9a8c7f55a901d9e8ec2a5f0730137bbfea4a.tar.gz |
ASoC: arizona: Implement stability check for EQ coefficients
Specifying unstable coefficients for the EQ can have a severe impact on
the audio. This patchs adds a stability check on the coefficients
written to the EQ, for this it is necessary to merge the mode control
and the coefficients as some coefficients may only be unstable with a
certain mode setting so it is ideal if these are always updated in sync.
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound/soc/codecs/arizona.c')
-rw-r--r-- | sound/soc/codecs/arizona.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05eae3e9..39967863d2ec 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2313,6 +2313,65 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = { }; EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls); +static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b) +{ + s16 a = be16_to_cpu(_a); + s16 b = be16_to_cpu(_b); + + if (!mode) { + return abs(a) >= 4096; + } else { + if (abs(b) >= 4096) + return true; + + return (abs((a << 16) / (4096 - b)) >= 4096 << 4); + } +} + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct soc_bytes *params = (void *)kcontrol->private_value; + unsigned int val; + __be16 *data; + int len; + int ret; + + len = params->num_regs * regmap_get_val_bytes(arizona->regmap); + + data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE); + + if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) || + arizona_eq_filter_unstable(true, data[4], data[5]) || + arizona_eq_filter_unstable(true, data[8], data[9]) || + arizona_eq_filter_unstable(true, data[12], data[13]) || + arizona_eq_filter_unstable(false, data[16], data[17])) { + dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n"); + ret = -EINVAL; + goto out; + } + + ret = regmap_read(arizona->regmap, params->base, &val); + if (ret != 0) + goto out; + + val &= ~ARIZONA_EQ1_B1_MODE; + data[0] |= cpu_to_be16(val); + + ret = regmap_raw_write(arizona->regmap, params->base, data, len); + +out: + kfree(data); + return ret; +} +EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_LICENSE("GPL"); |