mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 17:57:38 -04:00
ASoC: SDCA: Add PDE verification reusable helper
Implement sdca_asoc_pde_ensure_ps() helper function to poll for PDE power state transitions. Per SDCA specification, after writing REQUESTED_PS, drivers must poll ACTUAL_PS until the target power state is reached. Changes include: - Add sdca_asoc_pde_ensure_ps() to handle ACTUAL_PS polling with support for device-specific delay tables or default intervals - Export function via sdca_asoc.h for use by SDCA-compliant drivers - Refactor entity_pde_event() in sdca_asoc.c to use the helper Signed-off-by: Niranjan H Y <niranjan.hy@ti.com> Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev> Link: https://patch.msgid.link/20260505111806.2280-2-niranjan.hy@ti.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
struct device;
|
||||
struct regmap;
|
||||
struct sdca_function_data;
|
||||
struct sdca_pde_delay;
|
||||
struct snd_ctl_elem_value;
|
||||
struct snd_kcontrol;
|
||||
struct snd_kcontrol_new;
|
||||
@@ -99,4 +100,9 @@ int sdca_asoc_q78_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int sdca_asoc_q78_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
|
||||
int function_id, int entity_id,
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays);
|
||||
#endif // __SDCA_ASOC_H__
|
||||
|
||||
@@ -359,15 +359,77 @@ static int entity_parse_ot(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sdca_asoc_pde_poll_actual_ps - Verify PDE power state reached target state
|
||||
* @dev: Pointer to the device for error logging.
|
||||
* @regmap: Register map for reading ACTUAL_PS register.
|
||||
* @function_id: SDCA function identifier.
|
||||
* @entity_id: SDCA entity identifier for the power domain.
|
||||
* @from_ps: Source power state (SDCA_PDE_PSn value).
|
||||
* @to_ps: Target power state (SDCA_PDE_PSn value).
|
||||
* @pde_delays: Pointer to array of PDE delay specifications for this device,
|
||||
* or NULL to use default polling interval.
|
||||
* @num_delays: Number of entries in pde_delays array.
|
||||
*
|
||||
* This function polls the ACTUAL_PS register to verify that a PDE power state
|
||||
* transition has completed. Per SDCA specification, after writing REQUESTED_PS,
|
||||
* the caller must poll ACTUAL_PS until it reflects the requested state.
|
||||
*
|
||||
* This function implements the polling logic but does NOT modify the power state.
|
||||
* The caller is responsible for writing REQUESTED_PS before invoking this function.
|
||||
*
|
||||
* If a delay table is provided, appropriate polling intervals are extracted based
|
||||
* on the from_ps and to_ps transition. If no table is provided or no matching entry
|
||||
* is found, a default polling interval is used.
|
||||
*
|
||||
* Return: Returns zero when ACTUAL_PS reaches the target state, -ETIMEDOUT if the
|
||||
* polling times out before reaching the target state, or a negative error code if
|
||||
* a register read fails.
|
||||
*/
|
||||
int sdca_asoc_pde_poll_actual_ps(struct device *dev, struct regmap *regmap,
|
||||
int function_id, int entity_id,
|
||||
int from_ps, int to_ps,
|
||||
const struct sdca_pde_delay *pde_delays,
|
||||
int num_delays)
|
||||
{
|
||||
static const int polls = 100;
|
||||
static const int default_poll_us = 1000;
|
||||
unsigned int reg, val;
|
||||
int i, poll_us = default_poll_us;
|
||||
int ret;
|
||||
|
||||
if (pde_delays && num_delays > 0) {
|
||||
for (i = 0; i < num_delays; i++) {
|
||||
if (pde_delays[i].from_ps == from_ps && pde_delays[i].to_ps == to_ps) {
|
||||
poll_us = pde_delays[i].us / polls;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg = SDW_SDCA_CTL(function_id, entity_id, SDCA_CTL_PDE_ACTUAL_PS, 0);
|
||||
|
||||
for (i = 0; i < polls; i++) {
|
||||
if (i)
|
||||
fsleep(poll_us);
|
||||
|
||||
ret = regmap_read(regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (val == to_ps)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(sdca_asoc_pde_poll_actual_ps, "SND_SOC_SDCA");
|
||||
|
||||
static int entity_pde_event(struct snd_soc_dapm_widget *widget,
|
||||
struct snd_kcontrol *kctl, int event)
|
||||
{
|
||||
struct snd_soc_component *component = snd_soc_dapm_to_component(widget->dapm);
|
||||
struct sdca_entity *entity = widget->priv;
|
||||
static const int polls = 100;
|
||||
unsigned int reg, val;
|
||||
int from, to, i;
|
||||
int poll_us;
|
||||
int from, to;
|
||||
int ret;
|
||||
|
||||
if (!component)
|
||||
@@ -386,33 +448,17 @@ static int entity_pde_event(struct snd_soc_dapm_widget *widget,
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < entity->pde.num_max_delay; i++) {
|
||||
struct sdca_pde_delay *delay = &entity->pde.max_delay[i];
|
||||
ret = sdca_asoc_pde_poll_actual_ps(component->dev, component->regmap,
|
||||
SDW_SDCA_CTL_FUNC(widget->reg),
|
||||
SDW_SDCA_CTL_ENT(widget->reg),
|
||||
from, to,
|
||||
entity->pde.max_delay,
|
||||
entity->pde.num_max_delay);
|
||||
if (ret)
|
||||
dev_err(component->dev, "%s: PDE transition %x -> %x failed, err=%d\n",
|
||||
entity->label, from, to, ret);
|
||||
|
||||
if (delay->from_ps == from && delay->to_ps == to) {
|
||||
poll_us = delay->us / polls;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reg = SDW_SDCA_CTL(SDW_SDCA_CTL_FUNC(widget->reg),
|
||||
SDW_SDCA_CTL_ENT(widget->reg),
|
||||
SDCA_CTL_PDE_ACTUAL_PS, 0);
|
||||
|
||||
for (i = 0; i < polls; i++) {
|
||||
if (i)
|
||||
fsleep(poll_us);
|
||||
|
||||
ret = regmap_read(component->regmap, reg, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
else if (val == to)
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_err(component->dev, "%s: power transition failed: %x\n",
|
||||
entity->label, val);
|
||||
return -ETIMEDOUT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int entity_parse_pde(struct device *dev,
|
||||
|
||||
Reference in New Issue
Block a user