ASoC: ac108: Fixes kernel bug message when starting to capture
authorJaechul Lee <jcsing.lee@samsung.com>
Thu, 9 May 2019 00:26:53 +0000 (09:26 +0900)
committerHoegeun Kwon <hoegeun.kwon@samsung.com>
Thu, 3 Aug 2023 09:35:23 +0000 (18:35 +0900)
The code in the trigger function is moved to prepare function that is
called right before trigger function. clock operation would be ran by
parepare function without disabling preemption.

BUG: scheduling while atomic: arecord/1244/0x00000004
Preemption disabled at:
[<ffffff80087c4a08>] snd_pcm_stream_lock+0x30/0x68

Call trace:
[<ffffff800808b250>] dump_backtrace+0x0/0x270
[<ffffff800808b4e4>] show_stack+0x24/0x30
[<ffffff8008ae87c4>] dump_stack+0xac/0xe8
[<ffffff80080cc814>] __schedule_bug+0x7c/0xd8
[<ffffff8008afb558>] __schedule+0x718/0x880
[<ffffff8008afb6fc>] schedule+0x3c/0xa0
[<ffffff8008aff028>] schedule_timeout+0x190/0x408
[<ffffff8008afc4b8>] wait_for_common+0xa8/0x150
[<ffffff8008afc5c4>] wait_for_completion_timeout+0x2c/0x38
[<ffffff80086e5a0c>] bcm2835_i2c_xfer+0x16c/0x400
[<ffffff80086deedc>] __i2c_transfer+0x12c/0x570
[<ffffff80086df38c>] i2c_transfer+0x6c/0xc0
[<ffffff80086df430>] i2c_master_send+0x50/0x68
[<ffffff8008584454>] regmap_i2c_write+0x34/0x70
[<ffffff800857fe34>] _regmap_raw_write+0x7cc/0x7e0
[<ffffff800857feb8>] _regmap_bus_raw_write+0x70/0x88
[<ffffff800857ea48>] _regmap_write+0x70/0x160
[<ffffff800857ec10>] _regmap_update_bits+0xd8/0xf8
[<ffffff80085800b0>] regmap_update_bits_base+0x68/0x98
[<ffffff8008805838>] ac10x_update_bits+0x48/0x88
[<ffffff8008805c00>] ac108_trigger+0x118/0x130

Change-Id: Ib0f5edc86d363005abd75f989d732e917617f3fe
Signed-off-by: Jaechul Lee <jcsing.lee@samsung.com>
sound/soc/codecs/ac108.c
sound/soc/seeed/seeed-voicecard.c

index 6be9e73..82f976d 100644 (file)
@@ -1033,61 +1033,23 @@ static int ac108_set_clock(int y_start_n_stop) {
 static int ac108_prepare(struct snd_pcm_substream *substream,
                                        struct snd_soc_dai *dai)
 {
-       dev_dbg(dai->dev, "%s() stream=%s\n",
-               __func__,
-               snd_pcm_stream_str(substream));
-
-       return 0;
-}
-
-static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
-                            struct snd_soc_dai *dai)
-{
        struct snd_soc_codec *codec = dai->codec;
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-       unsigned long flags;
-       int ret = 0;
        u8 r;
 
-       dev_dbg(dai->dev, "%s() stream=%s  cmd=%d\n",
-               __FUNCTION__,
-               snd_pcm_stream_str(substream),
-               cmd);
-
-       spin_lock_irqsave(&ac10x->lock, flags);
-
-       if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
-               ac101_trigger(substream, cmd, dai);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                      goto __ret;
-               }
-       }
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               /* disable global clock if lrck disabled */
-               ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
-               if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
-                       /* disable global clock */
-                       ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
-               }
+       dev_dbg(dai->dev, "%s() stream=%s\n",
+               __func__,
+               snd_pcm_stream_str(substream));
 
-               /* delayed clock starting, move to machine trigger() */
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               break;
-       default:
-               ret = -EINVAL;
+       /* disable global clock if lrck disabled */
+       ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
+       if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
+               dev_err(dai->dev, "%s() jcsing ac108 multi update\n", __FUNCTION__);
+               /* disable global clock */
+               ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
        }
 
-__ret:
-       spin_unlock_irqrestore(&ac10x->lock, flags);
-
-       return ret;
+       return 0;
 }
 
 int ac108_audio_startup(struct snd_pcm_substream *substream,
@@ -1140,7 +1102,6 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
        /*ALSA PCM audio operations*/
        .hw_params      = ac108_hw_params,
        .prepare        = ac108_prepare,
-       .trigger        = ac108_trigger,
        .digital_mute   = ac108_aif_mute,
 
        /*DAI format configuration*/
index e6d55f6..8c4ee38 100644 (file)
@@ -77,6 +77,9 @@ struct seeed_card_info {
 #define CELL   "#sound-dai-cells"
 #define PREFIX "seeed-voice-card,"
 
+#define _SET_CLOCK_CNT         2
+static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
+
 static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
@@ -110,6 +113,7 @@ static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
 static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct snd_soc_dai *dai = rtd->codec_dai;
        struct seeed_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
        struct seeed_dai_props *dai_props =
                seeed_priv_to_props(priv, rtd->num);
@@ -122,6 +126,19 @@ static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
        clk_disable_unprepare(dai_props->cpu_dai.clk);
 
        clk_disable_unprepare(dai_props->codec_dai.clk);
+
+       if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               return;
+
+       /* interrupt environment */
+       if (in_irq() || in_nmi() || in_serving_softirq()) {
+               priv->try_stop = 0;
+               if (0 != schedule_work(&priv->work_codec_clk)) {
+               }
+       } else {
+               if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
+               if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
+       }
 }
 
 static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
@@ -153,13 +170,31 @@ static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
                if (ret && ret != -ENOTSUPP)
                        goto err;
        }
+
        return 0;
 err:
        return ret;
 }
 
-#define _SET_CLOCK_CNT         2
-static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
+int seeed_voice_card_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
+
+       if (cancel_work_sync(&priv->work_codec_clk) != 0) {}
+
+       #if CONFIG_AC10X_TRIG_LOCK
+       /* I know it will degrades performance, but I have no choice */
+       spin_lock_irqsave(&priv->lock, flags);
+       #endif
+       if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
+       if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
+       #if CONFIG_AC10X_TRIG_LOCK
+       spin_unlock_irqrestore(&priv->lock, flags);
+       #endif
+
+       return 0;
+}
 
 int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int)) {
        if (! _set_clock[stream]) {
@@ -190,66 +225,11 @@ static void work_cb_codec_clk(struct work_struct *work)
        return;
 }
 
-static int seeed_voice_card_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       struct snd_soc_pcm_runtime *rtd = substream->private_data;
-       struct snd_soc_dai *dai = rtd->codec_dai;
-       struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
-       #if CONFIG_AC10X_TRIG_LOCK
-       unsigned long flags;
-       #endif
-       int ret = 0;
-
-       dev_dbg(rtd->card->dev, "%s() stream=%s  cmd=%d play:%d, capt:%d\n",
-               __FUNCTION__, snd_pcm_stream_str(substream), cmd,
-               dai->playback_active, dai->capture_active);
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (cancel_work_sync(&priv->work_codec_clk) != 0) {}
-               #if CONFIG_AC10X_TRIG_LOCK
-               /* I know it will degrades performance, but I have no choice */
-               spin_lock_irqsave(&priv->lock, flags);
-               #endif
-               if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
-               if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
-               #if CONFIG_AC10X_TRIG_LOCK
-               spin_unlock_irqrestore(&priv->lock, flags);
-               #endif
-               break;
-
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               /* capture channel resync, if overrun */
-               if (dai->capture_active && substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       break;
-               }
-
-               /* interrupt environment */
-               if (in_irq() || in_nmi() || in_serving_softirq()) {
-                       priv->try_stop = 0;
-                       if (0 != schedule_work(&priv->work_codec_clk)) {
-                       }
-               } else {
-                       if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
-                       if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
-               }
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
 static struct snd_soc_ops seeed_voice_card_ops = {
        .startup = seeed_voice_card_startup,
        .shutdown = seeed_voice_card_shutdown,
        .hw_params = seeed_voice_card_hw_params,
-       .trigger = seeed_voice_card_trigger,
+       .prepare = seeed_voice_card_prepare,
 };
 
 static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)