mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
ASoC: qcom: AudioReach and WSA88xx fixes
Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com> says: Fixes found while bringing up speaker protection on the Lenovo ThinkPad T14s Gen 7 (Snapdragon X2 Elite) with WSA8845 speakers. - AudioReach: the module cfg blob size was used as an element count, so the allocation and copy were four times too large. - WSA88xx: speaker temperatures above 45 degC were rejected, runtime PM was left enabled on unbind (NULL dereference on wsa884x), and the VI sense port carried only half of the V/I pair. Tool use: an LLM coding assistant (Claude Code with Claude Opus) was used for some of the patches in this series, to debug the issues during bring-up and to draft the code and commit messages. Link: https://patch.msgid.link/20261023171316.819857-1-srinivas.kandagatla@oss.qualcomm.com
This commit is contained in:
commit
e163f6f079
|
|
@ -456,10 +456,11 @@
|
|||
|
||||
/*
|
||||
* Device will report senseless data in many cases, so discard any measurements
|
||||
* outside of valid range.
|
||||
* outside of the two-point trim range. Do not narrow this to ambient: a
|
||||
* speaker that has been playing easily runs well above 45 degC.
|
||||
*/
|
||||
#define WSA883X_LOW_TEMP_THRESHOLD 5
|
||||
#define WSA883X_HIGH_TEMP_THRESHOLD 45
|
||||
#define WSA883X_LOW_TEMP_THRESHOLD WSA883X_T1_TEMP
|
||||
#define WSA883X_HIGH_TEMP_THRESHOLD WSA883X_T2_TEMP
|
||||
|
||||
struct wsa883x_priv {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -551,7 +552,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
|
|||
.num = WSA883X_PORT_VISENSE + 1,
|
||||
.type = SDW_DPN_SIMPLE,
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.max_ch = 2,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}
|
||||
|
|
@ -572,7 +573,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
|
|||
},
|
||||
[WSA883X_PORT_VISENSE] = {
|
||||
.num = WSA883X_PORT_VISENSE + 1,
|
||||
.ch_mask = 0x1,
|
||||
.ch_mask = 0x3,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1430,7 +1431,7 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
|
|||
unsigned int dmeas_msb = 0, dmeas_lsb = 0;
|
||||
int d1, d2, dmeas;
|
||||
unsigned int mask;
|
||||
int ret, range;
|
||||
int ret;
|
||||
long val;
|
||||
|
||||
guard(mutex)(&wsa883x->sp_lock);
|
||||
|
|
@ -1493,8 +1494,8 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
|
|||
}
|
||||
|
||||
val = WSA883X_T1_TEMP + (((dmeas - d1) * (WSA883X_T2_TEMP - WSA883X_T1_TEMP)) / (d2 - d1));
|
||||
range = WSA883X_HIGH_TEMP_THRESHOLD - WSA883X_LOW_TEMP_THRESHOLD;
|
||||
if (in_range(val, WSA883X_LOW_TEMP_THRESHOLD, range)) {
|
||||
if (val >= WSA883X_LOW_TEMP_THRESHOLD &&
|
||||
val <= WSA883X_HIGH_TEMP_THRESHOLD) {
|
||||
wsa883x->temperature = val;
|
||||
*temp = val * 1000;
|
||||
ret = 0;
|
||||
|
|
@ -1668,7 +1669,9 @@ static int wsa883x_probe(struct sdw_slave *pdev,
|
|||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = devm_snd_soc_register_component(dev,
|
||||
&wsa883x_component_drv,
|
||||
|
|
|
|||
|
|
@ -720,10 +720,11 @@
|
|||
|
||||
/*
|
||||
* Device will report senseless data in many cases, so discard any measurements
|
||||
* outside of valid range.
|
||||
* outside of the two-point trim range. Do not narrow this to ambient: a
|
||||
* speaker that has been playing easily runs well above 45 degC.
|
||||
*/
|
||||
#define WSA884X_LOW_TEMP_THRESHOLD 5
|
||||
#define WSA884X_HIGH_TEMP_THRESHOLD 45
|
||||
#define WSA884X_LOW_TEMP_THRESHOLD WSA884X_T1_TEMP
|
||||
#define WSA884X_HIGH_TEMP_THRESHOLD WSA884X_T2_TEMP
|
||||
|
||||
struct wsa884x_priv {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -858,7 +859,7 @@ static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = {
|
|||
.num = WSA884X_PORT_VISENSE + 1,
|
||||
.type = SDW_DPN_SIMPLE,
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.max_ch = 2,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
},
|
||||
|
|
@ -891,7 +892,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
|
|||
},
|
||||
[WSA884X_PORT_VISENSE] = {
|
||||
.num = WSA884X_PORT_VISENSE + 1,
|
||||
.ch_mask = 0x1,
|
||||
.ch_mask = 0x3,
|
||||
},
|
||||
[WSA884X_PORT_CPS] = {
|
||||
.num = WSA884X_PORT_CPS + 1,
|
||||
|
|
@ -1929,8 +1930,8 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
|
|||
dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n",
|
||||
val, dmeas, d1, d2);
|
||||
|
||||
if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
|
||||
(val < WSA884X_HIGH_TEMP_THRESHOLD)) {
|
||||
if (val >= WSA884X_LOW_TEMP_THRESHOLD &&
|
||||
val <= WSA884X_HIGH_TEMP_THRESHOLD) {
|
||||
wsa884x->temperature = val;
|
||||
*temp = val * 1000;
|
||||
ret = 0;
|
||||
|
|
@ -2124,7 +2125,9 @@ static int wsa884x_probe(struct sdw_slave *pdev,
|
|||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_component(dev,
|
||||
&wsa884x_component_drv,
|
||||
|
|
|
|||
|
|
@ -312,22 +312,37 @@ audioreach_get_module_priv_data(const struct snd_soc_tplg_private *private)
|
|||
|
||||
for (sz = 0; sz < le32_to_cpu(private->size); ) {
|
||||
const struct snd_soc_tplg_vendor_array *mod_array;
|
||||
u32 array_size;
|
||||
|
||||
mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
|
||||
array_size = le32_to_cpu(mod_array->size);
|
||||
|
||||
if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) {
|
||||
struct audioreach_module_priv_data *pdata;
|
||||
u32 nwords;
|
||||
|
||||
pdata = kzalloc_flex(*pdata, data,
|
||||
le32_to_cpu(mod_array->size));
|
||||
/* size is the byte count of the __le32 data[] */
|
||||
nwords = array_size / sizeof(__le32);
|
||||
|
||||
/* the blob must lie within the private data */
|
||||
if (sizeof(*pdata) + (u64)array_size >
|
||||
le32_to_cpu(private->size) - sz)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pdata = kzalloc_flex(*pdata, data, nwords);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data,
|
||||
le32_to_cpu(mod_array->size)));
|
||||
memcpy(pdata, ((u8 *)private->data + sz),
|
||||
struct_size(pdata, data, nwords));
|
||||
return pdata;
|
||||
}
|
||||
|
||||
sz = sz + le32_to_cpu(mod_array->size);
|
||||
/* a zero size would never advance the walk */
|
||||
if (!array_size)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
sz = sz + array_size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -611,6 +626,12 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon
|
|||
return mod ? PTR_ERR(mod) : -ENODEV;
|
||||
|
||||
mod->data = audioreach_get_module_priv_data(&tplg_w->priv);
|
||||
if (IS_ERR(mod->data)) {
|
||||
int rc = PTR_ERR(mod->data);
|
||||
|
||||
mod->data = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
dobj = &w->dobj;
|
||||
dobj->private = mod;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user