Skip to content

Commit e1cdc13

Browse files
author
Codrin Ciubotariu
committed
ASoC: atmel: mchp-pdmc: do not remove non-runtime controls
Removing controls causes issues if the stream is started from another control. Do not remove these controls when the stream is started/finished and make it return -EBUSY instead. The controller is considered busy when the audio filter and the SINC filter are used. Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
1 parent 92b5c25 commit e1cdc13

1 file changed

Lines changed: 34 additions & 50 deletions

File tree

sound/soc/atmel/mchp-pdmc.c

Lines changed: 34 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <linux/module.h>
1313
#include <linux/of.h>
1414
#include <linux/regmap.h>
15+
#include <linux/spinlock.h>
1516

1617
#include <sound/core.h>
1718
#include <sound/dmaengine_pcm.h>
@@ -106,6 +107,7 @@ struct mchp_pdmc_chmap {
106107

107108
struct mchp_pdmc {
108109
struct mic_map channel_mic_map[MCHP_PDMC_MAX_CHANNELS];
110+
spinlock_t busy_lock; /* lock protecting busy */
109111
struct device *dev;
110112
struct snd_dmaengine_dai_dma_data addr;
111113
struct regmap *regmap;
@@ -116,6 +118,7 @@ struct mchp_pdmc {
116118
int sinc_order;
117119
bool audio_filter_en;
118120
u8 gclk_enabled:1;
121+
u8 busy:1;
119122
};
120123

121124
static const char *const mchp_pdmc_sinc_filter_order_text[] = {
@@ -141,6 +144,7 @@ static int mchp_pdmc_sinc_order_get(struct snd_kcontrol *kcontrol,
141144
unsigned int item;
142145

143146
item = snd_soc_enum_val_to_item(e, dd->sinc_order);
147+
144148
uvalue->value.enumerated.item[0] = item;
145149

146150
return 0;
@@ -159,10 +163,19 @@ static int mchp_pdmc_sinc_order_put(struct snd_kcontrol *kcontrol,
159163
return -EINVAL;
160164

161165
val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
162-
if (val == dd->sinc_order)
166+
167+
spin_lock(&dd->busy_lock);
168+
if (dd->busy) {
169+
spin_unlock((&dd->busy_lock));
170+
return -EBUSY;
171+
}
172+
if (val == dd->sinc_order) {
173+
spin_unlock((&dd->busy_lock));
163174
return 0;
175+
}
164176

165177
dd->sinc_order = val;
178+
spin_unlock((&dd->busy_lock));
166179

167180
return 1;
168181
}
@@ -185,10 +198,18 @@ static int mchp_pdmc_af_put(struct snd_kcontrol *kcontrol,
185198
struct mchp_pdmc *dd = snd_soc_component_get_drvdata(component);
186199
bool af = uvalue->value.integer.value[0] ? true : false;
187200

188-
if (dd->audio_filter_en == af)
201+
spin_lock(&dd->busy_lock);
202+
if (dd->busy) {
203+
spin_unlock((&dd->busy_lock));
204+
return -EBUSY;
205+
}
206+
if (dd->audio_filter_en == af) {
207+
spin_unlock((&dd->busy_lock));
189208
return 0;
209+
}
190210

191211
dd->audio_filter_en = af;
212+
spin_unlock((&dd->busy_lock));
192213

193214
return 1;
194215
}
@@ -371,58 +392,10 @@ static const struct snd_kcontrol_new mchp_pdmc_snd_controls[] = {
371392
},
372393
};
373394

374-
static int mchp_pdmc_close(struct snd_soc_component *component,
375-
struct snd_pcm_substream *substream)
376-
{
377-
return snd_soc_add_component_controls(component, mchp_pdmc_snd_controls,
378-
ARRAY_SIZE(mchp_pdmc_snd_controls));
379-
}
380-
381-
static int mchp_pdmc_open(struct snd_soc_component *component,
382-
struct snd_pcm_substream *substream)
383-
{
384-
int i;
385-
386-
/* remove controls that can't be changed at runtime */
387-
for (i = 0; i < ARRAY_SIZE(mchp_pdmc_snd_controls); i++) {
388-
const struct snd_kcontrol_new *control = &mchp_pdmc_snd_controls[i];
389-
struct snd_ctl_elem_id id;
390-
struct snd_kcontrol *kctl;
391-
int err;
392-
393-
if (component->name_prefix)
394-
snprintf(id.name, sizeof(id.name), "%s %s", component->name_prefix,
395-
control->name);
396-
else
397-
strscpy(id.name, control->name, sizeof(id.name));
398-
399-
id.numid = 0;
400-
id.iface = control->iface;
401-
id.device = control->device;
402-
id.subdevice = control->subdevice;
403-
id.index = control->index;
404-
kctl = snd_ctl_find_id(component->card->snd_card, &id);
405-
if (!kctl) {
406-
dev_err(component->dev, "Failed to find %s\n", control->name);
407-
continue;
408-
}
409-
err = snd_ctl_remove(component->card->snd_card, kctl);
410-
if (err < 0) {
411-
dev_err(component->dev, "%d: Failed to remove %s\n", err,
412-
control->name);
413-
continue;
414-
}
415-
}
416-
417-
return 0;
418-
}
419-
420395
static const struct snd_soc_component_driver mchp_pdmc_dai_component = {
421396
.name = "mchp-pdmc",
422397
.controls = mchp_pdmc_snd_controls,
423398
.num_controls = ARRAY_SIZE(mchp_pdmc_snd_controls),
424-
.open = &mchp_pdmc_open,
425-
.close = &mchp_pdmc_close,
426399
};
427400

428401
static const unsigned int mchp_pdmc_1mic[] = {1};
@@ -598,6 +571,13 @@ static int mchp_pdmc_hw_params(struct snd_pcm_substream *substream,
598571
dd->gclk_enabled = 0;
599572
}
600573

574+
/*
575+
* from these point forward, we consider the controller busy, so the
576+
* audio filter and SINC order can't be changed
577+
*/
578+
spin_lock(&dd->busy_lock);
579+
dd->busy = 1;
580+
spin_unlock((&dd->busy_lock));
601581
for (osr_start = dd->audio_filter_en ? 64 : 8;
602582
osr_start <= 256 && best_diff_rate; osr_start *= 2) {
603583
long round_rate;
@@ -654,6 +634,9 @@ static int mchp_pdmc_hw_free(struct snd_pcm_substream *substream,
654634
{
655635
struct mchp_pdmc *dd = snd_soc_dai_get_drvdata(dai);
656636

637+
spin_lock(&dd->busy_lock);
638+
dd->busy = 0;
639+
spin_unlock((&dd->busy_lock));
657640
if (dd->gclk_enabled) {
658641
clk_disable_unprepare(dd->gclk);
659642
dd->gclk_enabled = 0;
@@ -1033,6 +1016,7 @@ static int mchp_pdmc_probe(struct platform_device *pdev)
10331016
*/
10341017
dd->audio_filter_en = true;
10351018
dd->sinc_order = 3;
1019+
spin_lock_init(&dd->busy_lock);
10361020

10371021
dd->addr.addr = (dma_addr_t)res->start + MCHP_PDMC_RHR;
10381022
platform_set_drvdata(pdev, dd);

0 commit comments

Comments
 (0)