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
107108struct 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
121124static 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-
420395static 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
428401static 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