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,
/*ALSA PCM audio operations*/
.hw_params = ac108_hw_params,
.prepare = ac108_prepare,
- .trigger = ac108_trigger,
.digital_mute = ac108_aif_mute,
/*DAI format configuration*/
#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;
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);
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,
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]) {
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)