Commit 349dd239 authored by Bard Liao's avatar Bard Liao Committed by Mark Brown

ASoC: max98373: don't access volatile registers in bias level off

We will set regcache_cache_only true in suspend. As a result,
regmap_read will return error when we try to read volatile
registers in suspend. Besides, it doesn't make sense to read
feedback data when codec is not active. To make userspace
happy, this patch returns a cached value shich should be a
valid value.
Signed-off-by: default avatarBard Liao <yung-chuan.liao@linux.intel.com>
Link: https://lore.kernel.org/r/20201217074556.32370-1-yung-chuan.liao@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 6108f990
......@@ -19,6 +19,12 @@
#include <sound/tlv.h>
#include "max98373.h"
static const u32 max98373_i2c_cache_reg[] = {
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
};
static struct reg_default max98373_reg[] = {
{MAX98373_R2000_SW_RESET, 0x00},
{MAX98373_R2001_INT_RAW1, 0x00},
......@@ -472,6 +478,11 @@ static struct snd_soc_dai_driver max98373_dai[] = {
static int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
int i;
/* cache feedback register values before suspend */
for (i = 0; i < max98373->cache_num; i++)
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
regcache_cache_only(max98373->regmap, true);
regcache_mark_dirty(max98373->regmap);
......@@ -509,6 +520,7 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
{
int ret = 0;
int reg = 0;
int i;
struct max98373_priv *max98373 = NULL;
max98373 = devm_kzalloc(&i2c->dev, sizeof(*max98373), GFP_KERNEL);
......@@ -534,6 +546,14 @@ static int max98373_i2c_probe(struct i2c_client *i2c,
return ret;
}
max98373->cache_num = ARRAY_SIZE(max98373_i2c_cache_reg);
max98373->cache = devm_kcalloc(&i2c->dev, max98373->cache_num,
sizeof(*max98373->cache),
GFP_KERNEL);
for (i = 0; i < max98373->cache_num; i++)
max98373->cache[i].reg = max98373_i2c_cache_reg[i];
/* voltage/current slot & gpio configuration */
max98373_slot_config(&i2c->dev, max98373);
......
......@@ -23,6 +23,12 @@ struct sdw_stream_data {
struct sdw_stream_runtime *sdw_stream;
};
static const u32 max98373_sdw_cache_reg[] = {
MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK,
MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK,
MAX98373_R20B6_BDE_CUR_STATE_READBACK,
};
static struct reg_default max98373_reg[] = {
{MAX98373_R0040_SCP_INIT_STAT_1, 0x00},
{MAX98373_R0041_SCP_INIT_MASK_1, 0x00},
......@@ -245,6 +251,11 @@ static const struct regmap_config max98373_sdw_regmap = {
static __maybe_unused int max98373_suspend(struct device *dev)
{
struct max98373_priv *max98373 = dev_get_drvdata(dev);
int i;
/* cache feedback register values before suspend */
for (i = 0; i < max98373->cache_num; i++)
regmap_read(max98373->regmap, max98373->cache[i].reg, &max98373->cache[i].val);
regcache_cache_only(max98373->regmap, true);
......@@ -757,6 +768,7 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
{
struct max98373_priv *max98373;
int ret;
int i;
struct device *dev = &slave->dev;
/* Allocate and assign private driver data structure */
......@@ -768,6 +780,14 @@ static int max98373_init(struct sdw_slave *slave, struct regmap *regmap)
max98373->regmap = regmap;
max98373->slave = slave;
max98373->cache_num = ARRAY_SIZE(max98373_sdw_cache_reg);
max98373->cache = devm_kcalloc(dev, max98373->cache_num,
sizeof(*max98373->cache),
GFP_KERNEL);
for (i = 0; i < max98373->cache_num; i++)
max98373->cache[i].reg = max98373_sdw_cache_reg[i];
/* Read voltage and slot configuration */
max98373_slot_config(dev, max98373);
......
......@@ -168,6 +168,31 @@ static SOC_ENUM_SINGLE_DECL(max98373_adc_samplerate_enum,
MAX98373_R2051_MEAS_ADC_SAMPLING_RATE, 0,
max98373_ADC_samplerate_text);
static int max98373_feedback_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct max98373_priv *max98373 = snd_soc_component_get_drvdata(component);
int i;
if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF) {
/*
* Register values will be cached before suspend. The cached value
* will be a valid value and userspace will happy with that.
*/
for (i = 0; i < max98373->cache_num; i++) {
if (mc->reg == max98373->cache[i].reg) {
ucontrol->value.integer.value[0] = max98373->cache[i].val;
return 0;
}
}
}
return snd_soc_put_volsw(kcontrol, ucontrol);
}
static const struct snd_kcontrol_new max98373_snd_controls[] = {
SOC_SINGLE("Digital Vol Sel Switch", MAX98373_R203F_AMP_DSP_CFG,
MAX98373_AMP_VOL_SEL_SHIFT, 1, 0),
......@@ -209,8 +234,10 @@ SOC_SINGLE("ADC PVDD FLT Switch", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
MAX98373_FLT_EN_SHIFT, 1, 0),
SOC_SINGLE("ADC TEMP FLT Switch", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
MAX98373_FLT_EN_SHIFT, 1, 0),
SOC_SINGLE("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0),
SOC_SINGLE("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0),
SOC_SINGLE_EXT("ADC PVDD", MAX98373_R2054_MEAS_ADC_PVDD_CH_READBACK, 0, 0xFF, 0,
max98373_feedback_get, NULL),
SOC_SINGLE_EXT("ADC TEMP", MAX98373_R2055_MEAS_ADC_THERM_CH_READBACK, 0, 0xFF, 0,
max98373_feedback_get, NULL),
SOC_SINGLE("ADC PVDD FLT Coeff", MAX98373_R2052_MEAS_ADC_PVDD_FLT_CFG,
0, 0x3, 0),
SOC_SINGLE("ADC TEMP FLT Coeff", MAX98373_R2053_MEAS_ADC_THERM_FLT_CFG,
......@@ -226,7 +253,8 @@ SOC_SINGLE("BDE LVL1 Thresh", MAX98373_R2097_BDE_L1_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL2 Thresh", MAX98373_R2098_BDE_L2_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL3 Thresh", MAX98373_R2099_BDE_L3_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE LVL4 Thresh", MAX98373_R209A_BDE_L4_THRESH, 0, 0xFF, 0),
SOC_SINGLE("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0),
SOC_SINGLE_EXT("BDE Active Level", MAX98373_R20B6_BDE_CUR_STATE_READBACK, 0, 8, 0,
max98373_feedback_get, NULL),
SOC_SINGLE("BDE Clip Mode Switch", MAX98373_R2092_BDE_CLIPPER_MODE, 0, 1, 0),
SOC_SINGLE("BDE Thresh Hysteresis", MAX98373_R209B_BDE_THRESH_HYST, 0, 0xFF, 0),
SOC_SINGLE("BDE Hold Time", MAX98373_R2090_BDE_LVL_HOLD, 0, 0xFF, 0),
......
......@@ -203,6 +203,11 @@
/* MAX98373_R2000_SW_RESET */
#define MAX98373_SOFT_RESET (0x1 << 0)
struct max98373_cache {
u32 reg;
u32 val;
};
struct max98373_priv {
struct regmap *regmap;
int reset_gpio;
......@@ -212,6 +217,9 @@ struct max98373_priv {
bool interleave_mode;
unsigned int ch_size;
bool tdm_mode;
/* cache for reading a valid fake feedback value */
struct max98373_cache *cache;
int cache_num;
/* variables to support soundwire */
struct sdw_slave *slave;
bool hw_init;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment