diff options
-rw-r--r-- | sound/soc/soc-topology.c | 1 | ||||
-rw-r--r-- | sound/soc/sti/uniperif.h | 1 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_player.c | 35 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_reader.c | 27 |
4 files changed, 49 insertions, 15 deletions
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 3e9b1c0bb1ce..058bc99c6c34 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c | |||
@@ -933,6 +933,7 @@ static int soc_tplg_denum_create_texts(struct soc_enum *se, | |||
933 | } | 933 | } |
934 | } | 934 | } |
935 | 935 | ||
936 | se->texts = (const char * const *)se->dobj.control.dtexts; | ||
936 | return 0; | 937 | return 0; |
937 | 938 | ||
938 | err: | 939 | err: |
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index d487dd2ef016..cfcb0ea9d99d 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h | |||
@@ -1299,6 +1299,7 @@ struct uniperif { | |||
1299 | int ver; /* IP version, used by register access macros */ | 1299 | int ver; /* IP version, used by register access macros */ |
1300 | struct regmap_field *clk_sel; | 1300 | struct regmap_field *clk_sel; |
1301 | struct regmap_field *valid_sel; | 1301 | struct regmap_field *valid_sel; |
1302 | spinlock_t irq_lock; /* use to prevent race condition with IRQ */ | ||
1302 | 1303 | ||
1303 | /* capabilities */ | 1304 | /* capabilities */ |
1304 | const struct snd_pcm_hardware *hw; | 1305 | const struct snd_pcm_hardware *hw; |
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 60ae31a303ab..d7e8dd46d2cc 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -65,10 +65,13 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | |||
65 | unsigned int status; | 65 | unsigned int status; |
66 | unsigned int tmp; | 66 | unsigned int tmp; |
67 | 67 | ||
68 | if (player->state == UNIPERIF_STATE_STOPPED) { | 68 | spin_lock(&player->irq_lock); |
69 | /* Unexpected IRQ: do nothing */ | 69 | if (!player->substream) |
70 | return IRQ_NONE; | 70 | goto irq_spin_unlock; |
71 | } | 71 | |
72 | snd_pcm_stream_lock(player->substream); | ||
73 | if (player->state == UNIPERIF_STATE_STOPPED) | ||
74 | goto stream_unlock; | ||
72 | 75 | ||
73 | /* Get interrupt status & clear them immediately */ | 76 | /* Get interrupt status & clear them immediately */ |
74 | status = GET_UNIPERIF_ITS(player); | 77 | status = GET_UNIPERIF_ITS(player); |
@@ -88,9 +91,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | |||
88 | SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); | 91 | SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); |
89 | 92 | ||
90 | /* Stop the player */ | 93 | /* Stop the player */ |
91 | snd_pcm_stream_lock(player->substream); | ||
92 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | 94 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); |
93 | snd_pcm_stream_unlock(player->substream); | ||
94 | } | 95 | } |
95 | 96 | ||
96 | ret = IRQ_HANDLED; | 97 | ret = IRQ_HANDLED; |
@@ -104,9 +105,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | |||
104 | SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); | 105 | SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); |
105 | 106 | ||
106 | /* Stop the player */ | 107 | /* Stop the player */ |
107 | snd_pcm_stream_lock(player->substream); | ||
108 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | 108 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); |
109 | snd_pcm_stream_unlock(player->substream); | ||
110 | 109 | ||
111 | ret = IRQ_HANDLED; | 110 | ret = IRQ_HANDLED; |
112 | } | 111 | } |
@@ -116,7 +115,8 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | |||
116 | if (!player->underflow_enabled) { | 115 | if (!player->underflow_enabled) { |
117 | dev_err(player->dev, | 116 | dev_err(player->dev, |
118 | "unexpected Underflow recovering\n"); | 117 | "unexpected Underflow recovering\n"); |
119 | return -EPERM; | 118 | ret = -EPERM; |
119 | goto stream_unlock; | ||
120 | } | 120 | } |
121 | /* Read the underflow recovery duration */ | 121 | /* Read the underflow recovery duration */ |
122 | tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); | 122 | tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); |
@@ -138,13 +138,16 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | |||
138 | dev_err(player->dev, "Underflow recovery failed\n"); | 138 | dev_err(player->dev, "Underflow recovery failed\n"); |
139 | 139 | ||
140 | /* Stop the player */ | 140 | /* Stop the player */ |
141 | snd_pcm_stream_lock(player->substream); | ||
142 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | 141 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); |
143 | snd_pcm_stream_unlock(player->substream); | ||
144 | 142 | ||
145 | ret = IRQ_HANDLED; | 143 | ret = IRQ_HANDLED; |
146 | } | 144 | } |
147 | 145 | ||
146 | stream_unlock: | ||
147 | snd_pcm_stream_unlock(player->substream); | ||
148 | irq_spin_unlock: | ||
149 | spin_unlock(&player->irq_lock); | ||
150 | |||
148 | return ret; | 151 | return ret; |
149 | } | 152 | } |
150 | 153 | ||
@@ -588,6 +591,7 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, | |||
588 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 591 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
589 | struct uniperif *player = priv->dai_data.uni; | 592 | struct uniperif *player = priv->dai_data.uni; |
590 | struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; | 593 | struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; |
594 | unsigned long flags; | ||
591 | 595 | ||
592 | mutex_lock(&player->ctrl_lock); | 596 | mutex_lock(&player->ctrl_lock); |
593 | iec958->status[0] = ucontrol->value.iec958.status[0]; | 597 | iec958->status[0] = ucontrol->value.iec958.status[0]; |
@@ -596,12 +600,14 @@ static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, | |||
596 | iec958->status[3] = ucontrol->value.iec958.status[3]; | 600 | iec958->status[3] = ucontrol->value.iec958.status[3]; |
597 | mutex_unlock(&player->ctrl_lock); | 601 | mutex_unlock(&player->ctrl_lock); |
598 | 602 | ||
603 | spin_lock_irqsave(&player->irq_lock, flags); | ||
599 | if (player->substream && player->substream->runtime) | 604 | if (player->substream && player->substream->runtime) |
600 | uni_player_set_channel_status(player, | 605 | uni_player_set_channel_status(player, |
601 | player->substream->runtime); | 606 | player->substream->runtime); |
602 | else | 607 | else |
603 | uni_player_set_channel_status(player, NULL); | 608 | uni_player_set_channel_status(player, NULL); |
604 | 609 | ||
610 | spin_unlock_irqrestore(&player->irq_lock, flags); | ||
605 | return 0; | 611 | return 0; |
606 | } | 612 | } |
607 | 613 | ||
@@ -686,9 +692,12 @@ static int uni_player_startup(struct snd_pcm_substream *substream, | |||
686 | { | 692 | { |
687 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 693 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
688 | struct uniperif *player = priv->dai_data.uni; | 694 | struct uniperif *player = priv->dai_data.uni; |
695 | unsigned long flags; | ||
689 | int ret; | 696 | int ret; |
690 | 697 | ||
698 | spin_lock_irqsave(&player->irq_lock, flags); | ||
691 | player->substream = substream; | 699 | player->substream = substream; |
700 | spin_unlock_irqrestore(&player->irq_lock, flags); | ||
692 | 701 | ||
693 | player->clk_adj = 0; | 702 | player->clk_adj = 0; |
694 | 703 | ||
@@ -986,12 +995,15 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, | |||
986 | { | 995 | { |
987 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 996 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
988 | struct uniperif *player = priv->dai_data.uni; | 997 | struct uniperif *player = priv->dai_data.uni; |
998 | unsigned long flags; | ||
989 | 999 | ||
1000 | spin_lock_irqsave(&player->irq_lock, flags); | ||
990 | if (player->state != UNIPERIF_STATE_STOPPED) | 1001 | if (player->state != UNIPERIF_STATE_STOPPED) |
991 | /* Stop the player */ | 1002 | /* Stop the player */ |
992 | uni_player_stop(player); | 1003 | uni_player_stop(player); |
993 | 1004 | ||
994 | player->substream = NULL; | 1005 | player->substream = NULL; |
1006 | spin_unlock_irqrestore(&player->irq_lock, flags); | ||
995 | } | 1007 | } |
996 | 1008 | ||
997 | static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, | 1009 | static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, |
@@ -1096,6 +1108,7 @@ int uni_player_init(struct platform_device *pdev, | |||
1096 | } | 1108 | } |
1097 | 1109 | ||
1098 | mutex_init(&player->ctrl_lock); | 1110 | mutex_init(&player->ctrl_lock); |
1111 | spin_lock_init(&player->irq_lock); | ||
1099 | 1112 | ||
1100 | /* Ensure that disabled by default */ | 1113 | /* Ensure that disabled by default */ |
1101 | SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); | 1114 | SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); |
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 5992c6ab3833..ee0055e60852 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c | |||
@@ -46,10 +46,15 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | |||
46 | struct uniperif *reader = dev_id; | 46 | struct uniperif *reader = dev_id; |
47 | unsigned int status; | 47 | unsigned int status; |
48 | 48 | ||
49 | spin_lock(&reader->irq_lock); | ||
50 | if (!reader->substream) | ||
51 | goto irq_spin_unlock; | ||
52 | |||
53 | snd_pcm_stream_lock(reader->substream); | ||
49 | if (reader->state == UNIPERIF_STATE_STOPPED) { | 54 | if (reader->state == UNIPERIF_STATE_STOPPED) { |
50 | /* Unexpected IRQ: do nothing */ | 55 | /* Unexpected IRQ: do nothing */ |
51 | dev_warn(reader->dev, "unexpected IRQ\n"); | 56 | dev_warn(reader->dev, "unexpected IRQ\n"); |
52 | return IRQ_HANDLED; | 57 | goto stream_unlock; |
53 | } | 58 | } |
54 | 59 | ||
55 | /* Get interrupt status & clear them immediately */ | 60 | /* Get interrupt status & clear them immediately */ |
@@ -60,13 +65,16 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | |||
60 | if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { | 65 | if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { |
61 | dev_err(reader->dev, "FIFO error detected\n"); | 66 | dev_err(reader->dev, "FIFO error detected\n"); |
62 | 67 | ||
63 | snd_pcm_stream_lock(reader->substream); | ||
64 | snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); | 68 | snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); |
65 | snd_pcm_stream_unlock(reader->substream); | ||
66 | 69 | ||
67 | return IRQ_HANDLED; | 70 | ret = IRQ_HANDLED; |
68 | } | 71 | } |
69 | 72 | ||
73 | stream_unlock: | ||
74 | snd_pcm_stream_unlock(reader->substream); | ||
75 | irq_spin_unlock: | ||
76 | spin_unlock(&reader->irq_lock); | ||
77 | |||
70 | return ret; | 78 | return ret; |
71 | } | 79 | } |
72 | 80 | ||
@@ -347,8 +355,13 @@ static int uni_reader_startup(struct snd_pcm_substream *substream, | |||
347 | { | 355 | { |
348 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 356 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
349 | struct uniperif *reader = priv->dai_data.uni; | 357 | struct uniperif *reader = priv->dai_data.uni; |
358 | unsigned long flags; | ||
350 | int ret; | 359 | int ret; |
351 | 360 | ||
361 | spin_lock_irqsave(&reader->irq_lock, flags); | ||
362 | reader->substream = substream; | ||
363 | spin_unlock_irqrestore(&reader->irq_lock, flags); | ||
364 | |||
352 | if (!UNIPERIF_TYPE_IS_TDM(reader)) | 365 | if (!UNIPERIF_TYPE_IS_TDM(reader)) |
353 | return 0; | 366 | return 0; |
354 | 367 | ||
@@ -373,11 +386,15 @@ static void uni_reader_shutdown(struct snd_pcm_substream *substream, | |||
373 | { | 386 | { |
374 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 387 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
375 | struct uniperif *reader = priv->dai_data.uni; | 388 | struct uniperif *reader = priv->dai_data.uni; |
389 | unsigned long flags; | ||
376 | 390 | ||
391 | spin_lock_irqsave(&reader->irq_lock, flags); | ||
377 | if (reader->state != UNIPERIF_STATE_STOPPED) { | 392 | if (reader->state != UNIPERIF_STATE_STOPPED) { |
378 | /* Stop the reader */ | 393 | /* Stop the reader */ |
379 | uni_reader_stop(reader); | 394 | uni_reader_stop(reader); |
380 | } | 395 | } |
396 | reader->substream = NULL; | ||
397 | spin_unlock_irqrestore(&reader->irq_lock, flags); | ||
381 | } | 398 | } |
382 | 399 | ||
383 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { | 400 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { |
@@ -412,6 +429,8 @@ int uni_reader_init(struct platform_device *pdev, | |||
412 | return -EBUSY; | 429 | return -EBUSY; |
413 | } | 430 | } |
414 | 431 | ||
432 | spin_lock_init(&reader->irq_lock); | ||
433 | |||
415 | return 0; | 434 | return 0; |
416 | } | 435 | } |
417 | EXPORT_SYMBOL_GPL(uni_reader_init); | 436 | EXPORT_SYMBOL_GPL(uni_reader_init); |