Skip to content

Commit 819cf1d

Browse files
TE-N-ShengjiuWangbroonie
authored andcommitted
ASoC: fsl_utils: Add snd_kcontrol functions for specific cases
There are some registers which are volatile, at pm runtime suspend state, the regmap cache only is enabled, regmap will return -EBUSY when trying to access these registers. static int _regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) { int ret; void *context = _regmap_map_get_context(map); if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) return 0; } if (map->cache_only) return -EBUSY; if (!regmap_readable(map, reg)) return -EIO; When exporting these registers by amixer interface to user space, there will be -EBUSY errors in mixer-test when the cpu dai is in idle. In order to avoid such error, needs to define FSL own functions to take a pm runtime reference before calling snd_soc_get_xr_sx(), snd_soc_get_enum_double(), snd_soc_get_volsw(), and so on. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Link: https://patch.msgid.link/20260310104235.1234569-2-shengjiu.wang@nxp.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 1f318b9 commit 819cf1d

2 files changed

Lines changed: 179 additions & 0 deletions

File tree

sound/soc/fsl/fsl_utils.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/clk-provider.h>
1111
#include <linux/module.h>
1212
#include <linux/of_address.h>
13+
#include <linux/pm_runtime.h>
1314
#include <sound/soc.h>
1415

1516
#include "fsl_utils.h"
@@ -197,6 +198,136 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
197198
}
198199
EXPORT_SYMBOL(fsl_asoc_constrain_rates);
199200

201+
/*
202+
* Below functions are used by mixer interface to avoid accessing registers
203+
* which are volatile at pm runtime suspend state (cache_only is enabled).
204+
*/
205+
int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
206+
struct snd_ctl_elem_value *ucontrol)
207+
{
208+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
209+
int ret = 0;
210+
211+
ret = pm_runtime_resume_and_get(component->dev);
212+
if (ret)
213+
return ret;
214+
215+
ret = snd_soc_get_xr_sx(kcontrol, ucontrol);
216+
217+
pm_runtime_put_autosuspend(component->dev);
218+
219+
return ret;
220+
}
221+
EXPORT_SYMBOL_GPL(fsl_asoc_get_xr_sx);
222+
223+
int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
224+
struct snd_ctl_elem_value *ucontrol)
225+
{
226+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
227+
int ret = 0;
228+
229+
ret = pm_runtime_resume_and_get(component->dev);
230+
if (ret)
231+
return ret;
232+
233+
ret = snd_soc_put_xr_sx(kcontrol, ucontrol);
234+
/*
235+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
236+
* case. return 0 to avoid control event notification.
237+
*/
238+
if (ret > 0)
239+
ret = 0;
240+
241+
pm_runtime_put_autosuspend(component->dev);
242+
243+
return ret;
244+
}
245+
EXPORT_SYMBOL_GPL(fsl_asoc_put_xr_sx);
246+
247+
int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
248+
struct snd_ctl_elem_value *ucontrol)
249+
{
250+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
251+
int ret = 0;
252+
253+
ret = pm_runtime_resume_and_get(component->dev);
254+
if (ret)
255+
return ret;
256+
257+
ret = snd_soc_get_enum_double(kcontrol, ucontrol);
258+
259+
pm_runtime_put_autosuspend(component->dev);
260+
261+
return ret;
262+
}
263+
EXPORT_SYMBOL_GPL(fsl_asoc_get_enum_double);
264+
265+
int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
266+
struct snd_ctl_elem_value *ucontrol)
267+
{
268+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
269+
int ret = 0;
270+
271+
ret = pm_runtime_resume_and_get(component->dev);
272+
if (ret)
273+
return ret;
274+
275+
ret = snd_soc_put_enum_double(kcontrol, ucontrol);
276+
/*
277+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
278+
* case. return 0 to avoid control event notification.
279+
*/
280+
if (ret > 0)
281+
ret = 0;
282+
283+
pm_runtime_put_autosuspend(component->dev);
284+
285+
return ret;
286+
}
287+
EXPORT_SYMBOL_GPL(fsl_asoc_put_enum_double);
288+
289+
int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
290+
struct snd_ctl_elem_value *ucontrol)
291+
{
292+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
293+
int ret = 0;
294+
295+
ret = pm_runtime_resume_and_get(component->dev);
296+
if (ret)
297+
return ret;
298+
299+
ret = snd_soc_get_volsw(kcontrol, ucontrol);
300+
301+
pm_runtime_put_autosuspend(component->dev);
302+
303+
return ret;
304+
}
305+
EXPORT_SYMBOL_GPL(fsl_asoc_get_volsw);
306+
307+
int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
308+
struct snd_ctl_elem_value *ucontrol)
309+
{
310+
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
311+
int ret = 0;
312+
313+
ret = pm_runtime_resume_and_get(component->dev);
314+
if (ret)
315+
return ret;
316+
317+
ret = snd_soc_put_volsw(kcontrol, ucontrol);
318+
/*
319+
* As this function only used by the SNDRV_CTL_ELEM_ACCESS_VOLATILE
320+
* case. return 0 to avoid control event notification.
321+
*/
322+
if (ret > 0)
323+
ret = 0;
324+
325+
pm_runtime_put_autosuspend(component->dev);
326+
327+
return ret;
328+
}
329+
EXPORT_SYMBOL_GPL(fsl_asoc_put_volsw);
330+
200331
MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
201332
MODULE_DESCRIPTION("Freescale ASoC utility code");
202333
MODULE_LICENSE("GPL v2");

sound/soc/fsl/fsl_utils.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,52 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
3131
const struct snd_pcm_hw_constraint_list *original_constr,
3232
struct clk *pll8k_clk, struct clk *pll11k_clk,
3333
struct clk *ext_clk, int *target_rates);
34+
35+
/* Similar to SOC_SINGLE_XR_SX, but it is for read only registers. */
36+
#define FSL_ASOC_SINGLE_XR_SX_EXT_RO(xname, xregbase, xregcount, xnbits, \
37+
xmin, xmax, xinvert, xhandler_get) \
38+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
39+
.access = SNDRV_CTL_ELEM_ACCESS_READ | \
40+
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
41+
.info = snd_soc_info_xr_sx, .get = xhandler_get, \
42+
.private_value = (unsigned long)&(struct soc_mreg_control) \
43+
{.regbase = xregbase, .regcount = xregcount, .nbits = xnbits, \
44+
.invert = xinvert, .min = xmin, .max = xmax} }
45+
46+
/* Similar to SOC_SINGLE_EXT, but it is for volatile register. */
47+
#define FSL_ASOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\
48+
xhandler_get, xhandler_put) \
49+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
50+
.access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
51+
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
52+
.info = snd_soc_info_volsw, \
53+
.get = xhandler_get, .put = xhandler_put, \
54+
.private_value = SOC_SINGLE_VALUE(xreg, xshift, 0, xmax, xinvert, 0) }
55+
56+
#define FSL_ASOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
57+
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
58+
.access = SNDRV_CTL_ELEM_ACCESS_VOLATILE | \
59+
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
60+
.info = snd_soc_info_enum_double, \
61+
.get = xhandler_get, .put = xhandler_put, \
62+
.private_value = (unsigned long)&xenum }
63+
64+
int fsl_asoc_get_xr_sx(struct snd_kcontrol *kcontrol,
65+
struct snd_ctl_elem_value *ucontrol);
66+
67+
int fsl_asoc_put_xr_sx(struct snd_kcontrol *kcontrol,
68+
struct snd_ctl_elem_value *ucontrol);
69+
70+
int fsl_asoc_get_enum_double(struct snd_kcontrol *kcontrol,
71+
struct snd_ctl_elem_value *ucontrol);
72+
73+
int fsl_asoc_put_enum_double(struct snd_kcontrol *kcontrol,
74+
struct snd_ctl_elem_value *ucontrol);
75+
76+
int fsl_asoc_get_volsw(struct snd_kcontrol *kcontrol,
77+
struct snd_ctl_elem_value *ucontrol);
78+
79+
int fsl_asoc_put_volsw(struct snd_kcontrol *kcontrol,
80+
struct snd_ctl_elem_value *ucontrol);
81+
3482
#endif /* _FSL_UTILS_H */

0 commit comments

Comments
 (0)