From d3294f53764f8f6bdb5e126f72e8a40a149a1d24 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Thu, 9 May 2019 09:26:53 +0900 Subject: [PATCH] ASoC: ac108: Fixes kernel bug message when starting to capture 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: [] snd_pcm_stream_lock+0x30/0x68 Call trace: [] dump_backtrace+0x0/0x270 [] show_stack+0x24/0x30 [] dump_stack+0xac/0xe8 [] __schedule_bug+0x7c/0xd8 [] __schedule+0x718/0x880 [] schedule+0x3c/0xa0 [] schedule_timeout+0x190/0x408 [] wait_for_common+0xa8/0x150 [] wait_for_completion_timeout+0x2c/0x38 [] bcm2835_i2c_xfer+0x16c/0x400 [] __i2c_transfer+0x12c/0x570 [] i2c_transfer+0x6c/0xc0 [] i2c_master_send+0x50/0x68 [] regmap_i2c_write+0x34/0x70 [] _regmap_raw_write+0x7cc/0x7e0 [] _regmap_bus_raw_write+0x70/0x88 [] _regmap_write+0x70/0x160 [] _regmap_update_bits+0xd8/0xf8 [] regmap_update_bits_base+0x68/0x98 [] ac10x_update_bits+0x48/0x88 [] ac108_trigger+0x118/0x130 Change-Id: I73ef21247e1dfbd0acd3272b6a73311377eb000d Signed-off-by: Jaechul Lee --- sound/soc/codecs/ac108.c | 59 ++++-------------------- sound/soc/seeed/seeed-voicecard.c | 96 ++++++++++++++++----------------------- 2 files changed, 48 insertions(+), 107 deletions(-) diff --git a/sound/soc/codecs/ac108.c b/sound/soc/codecs/ac108.c index 6be9e73..82f976d 100644 --- a/sound/soc/codecs/ac108.c +++ b/sound/soc/codecs/ac108.c @@ -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*/ diff --git a/sound/soc/seeed/seeed-voicecard.c b/sound/soc/seeed/seeed-voicecard.c index e6d55f6..8c4ee38 100644 --- a/sound/soc/seeed/seeed-voicecard.c +++ b/sound/soc/seeed/seeed-voicecard.c @@ -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) -- 2.7.4