Skip to content

Commit 93afd02

Browse files
charleskeepaxbroonie
authored andcommitted
ASoC: cs42l43: Cache shutter IRQ control pointers
The microphone/speaker privacy shutter ALSA control handlers need to call pm_runtime_resume, since the hardware needs to be powered up to check the hardware state of the shutter. The IRQ handler for the shutters also needs to notify the ALSA control to inform user-space the shutters updated. However this leads to a mutex inversion, between the sdw_dev_lock and the controls_rwsem. To avoid this mutex inversion cache the kctl pointers before the IRQ handler, which avoids the need to lookup the control and take the controls_rwsem. Suggested-by: Jaroslav Kysela <[email protected]> Signed-off-by: Charles Keepax <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 4791c42 commit 93afd02

File tree

2 files changed

+58
-17
lines changed

2 files changed

+58
-17
lines changed

sound/soc/codecs/cs42l43.c

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <linux/bitops.h>
99
#include <linux/bits.h>
10+
#include <linux/build_bug.h>
1011
#include <linux/clk.h>
1112
#include <linux/device.h>
1213
#include <linux/err.h>
@@ -252,24 +253,20 @@ CS42L43_IRQ_COMPLETE(load_detect)
252253
static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
253254
{
254255
struct cs42l43_codec *priv = data;
255-
static const char * const controls[] = {
256-
"Decimator 1 Switch",
257-
"Decimator 2 Switch",
258-
"Decimator 3 Switch",
259-
"Decimator 4 Switch",
260-
};
261-
int i, ret;
256+
struct snd_soc_component *component = priv->component;
257+
int i;
262258

263259
dev_dbg(priv->dev, "Microphone shutter changed\n");
264260

265-
if (!priv->component)
261+
if (!component)
266262
return IRQ_NONE;
267263

268-
for (i = 0; i < ARRAY_SIZE(controls); i++) {
269-
ret = snd_soc_component_notify_control(priv->component,
270-
controls[i]);
271-
if (ret)
264+
for (i = 1; i < ARRAY_SIZE(priv->kctl); i++) {
265+
if (!priv->kctl[i])
272266
return IRQ_NONE;
267+
268+
snd_ctl_notify(component->card->snd_card,
269+
SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[i]->id);
273270
}
274271

275272
return IRQ_HANDLED;
@@ -278,18 +275,19 @@ static irqreturn_t cs42l43_mic_shutter(int irq, void *data)
278275
static irqreturn_t cs42l43_spk_shutter(int irq, void *data)
279276
{
280277
struct cs42l43_codec *priv = data;
281-
int ret;
278+
struct snd_soc_component *component = priv->component;
282279

283280
dev_dbg(priv->dev, "Speaker shutter changed\n");
284281

285-
if (!priv->component)
282+
if (!component)
286283
return IRQ_NONE;
287284

288-
ret = snd_soc_component_notify_control(priv->component,
289-
"Speaker Digital Switch");
290-
if (ret)
285+
if (!priv->kctl[0])
291286
return IRQ_NONE;
292287

288+
snd_ctl_notify(component->card->snd_card,
289+
SNDRV_CTL_EVENT_MASK_VALUE, &priv->kctl[0]->id);
290+
293291
return IRQ_HANDLED;
294292
}
295293

@@ -590,7 +588,46 @@ static int cs42l43_asp_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mas
590588
return 0;
591589
}
592590

591+
static int cs42l43_dai_probe(struct snd_soc_dai *dai)
592+
{
593+
struct snd_soc_component *component = dai->component;
594+
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
595+
static const char * const controls[] = {
596+
"Speaker Digital Switch",
597+
"Decimator 1 Switch",
598+
"Decimator 2 Switch",
599+
"Decimator 3 Switch",
600+
"Decimator 4 Switch",
601+
};
602+
int i;
603+
604+
static_assert(ARRAY_SIZE(controls) == ARRAY_SIZE(priv->kctl));
605+
606+
for (i = 0; i < ARRAY_SIZE(controls); i++) {
607+
if (priv->kctl[i])
608+
continue;
609+
610+
priv->kctl[i] = snd_soc_component_get_kcontrol(component, controls[i]);
611+
}
612+
613+
return 0;
614+
}
615+
616+
static int cs42l43_dai_remove(struct snd_soc_dai *dai)
617+
{
618+
struct snd_soc_component *component = dai->component;
619+
struct cs42l43_codec *priv = snd_soc_component_get_drvdata(component);
620+
int i;
621+
622+
for (i = 0; i < ARRAY_SIZE(priv->kctl); i++)
623+
priv->kctl[i] = NULL;
624+
625+
return 0;
626+
}
627+
593628
static const struct snd_soc_dai_ops cs42l43_asp_ops = {
629+
.probe = cs42l43_dai_probe,
630+
.remove = cs42l43_dai_remove,
594631
.startup = cs42l43_startup,
595632
.hw_params = cs42l43_asp_hw_params,
596633
.set_fmt = cs42l43_asp_set_fmt,
@@ -611,6 +648,8 @@ static int cs42l43_sdw_hw_params(struct snd_pcm_substream *substream,
611648
}
612649

613650
static const struct snd_soc_dai_ops cs42l43_sdw_ops = {
651+
.probe = cs42l43_dai_probe,
652+
.remove = cs42l43_dai_remove,
614653
.startup = cs42l43_startup,
615654
.set_stream = cs42l43_sdw_set_stream,
616655
.hw_params = cs42l43_sdw_hw_params,

sound/soc/codecs/cs42l43.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ struct cs42l43_codec {
100100
struct delayed_work hp_ilimit_clear_work;
101101
bool hp_ilimited;
102102
int hp_ilimit_count;
103+
104+
struct snd_kcontrol *kctl[5];
103105
};
104106

105107
#if IS_REACHABLE(CONFIG_SND_SOC_CS42L43_SDW)

0 commit comments

Comments
 (0)