static int mv88fx_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct mv88fx_snd_chip *chip = mv88fx_pcm_get_chip(substream); mv88fx_snd_debug(""); if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) return mv88fx_i2s_snd_hw_capture_set(chip, substream); else return mv88fx_i2s_snd_hw_playback_set(chip, substream); }
static int mv88fx_snd_ctrl_new(struct snd_card *card) { int err = 0; struct mv88fx_snd_chip *chip = mv88fx_pcm_get_chip(); playback_src_mixer.rec = &chip->stream[SNDRV_PCM_STREAM_PLAYBACK].dig_mode; playback_mono_mixer.rec = &chip->stream[SNDRV_PCM_STREAM_PLAYBACK].mono_mode; capture_src_mixer.rec = &chip->stream[SNDRV_PCM_STREAM_CAPTURE].dig_mode; capture_mono_mixer.rec = &chip->stream[SNDRV_PCM_STREAM_CAPTURE].mono_mode; if (chip->pdata->i2s_play && chip->pdata->spdif_play) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_mixers [PLAYBACK_MIX_INDX], chip)); if (err < 0) return err; } if (chip->pdata->i2s_play || chip->pdata->spdif_play) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_mixers [PLAYBACK_MONO_MIX_INDX], chip)); if (err < 0) return err; } if (chip->pdata->i2s_rec && chip->pdata->spdif_rec) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_mixers [CAPTURE_MIX_INDX], chip)); if (err < 0) return err; } if (chip->pdata->i2s_rec || chip->pdata->spdif_rec) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_mixers [CAPTURE_MONO_MIX_INDX], chip)); if (err < 0) return err; } if (chip->pdata->spdif_play) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_mask, chip)); if (err < 0) return err; } if (chip->pdata->spdif_play) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_default, chip)); if (err < 0) return err; } if (chip->pdata->spdif_play) { err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_stream, chip)); if (err < 0) return err; } return err; }
static int mv88fx_i2s_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct mv88fx_snd_stream *audio_stream = runtime->private_data; struct mv88fx_snd_chip *chip = mv88fx_pcm_get_chip(substream); int result = 0; mv88fx_snd_debug("substream=%p cmd=%d audio_stream=%p", substream, cmd, audio_stream); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: mv88fx_snd_debug(""); /* enable interrupt */ mv88fx_snd_bitset(chip->base, MV_AUDIO_INT_MASK_REG(chip->port), AICR_PLAY_BYTES_INT); /* make sure the dma in pause state */ mv88fx_snd_bitset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_PAUSE_MASK); /* enable dma */ if ((audio_stream->dig_mode & I2S) && (chip->pcm_mode == PCM)) mv88fx_snd_bitset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_I2S_ENABLE_MASK); if (audio_stream->dig_mode & SPDIF) mv88fx_snd_bitset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_SPDIF_ENABLE_MASK); /* start dma */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_PAUSE_MASK); break; case SNDRV_PCM_TRIGGER_STOP: mv88fx_snd_debug(""); /* disable interrupt */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_INT_MASK_REG(chip->port), AICR_PLAY_BYTES_INT); /* make sure the dma in pause state */ mv88fx_snd_bitset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_PAUSE_MASK); /* always stop both I2S and SPDIF */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), (APCR_PLAY_I2S_ENABLE_MASK | APCR_PLAY_SPDIF_ENABLE_MASK)); /* check if busy twice */ while (mv88fx_snd_readl(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port)) & APCR_PLAY_BUSY_MASK) ; while (mv88fx_snd_readl(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port)) & APCR_PLAY_BUSY_MASK) ; break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: mv88fx_snd_debug(""); mv88fx_snd_bitset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_PAUSE_MASK); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mv88fx_snd_debug(""); mv88fx_snd_bitreset(chip->base, MV_AUDIO_PLAYBACK_CTRL_REG(chip->port), APCR_PLAY_PAUSE_MASK); break; default: result = -EINVAL; break; } spin_unlock(&chip->reg_lock); mv88fx_snd_debug("result=%d", result); return result; }
static int mv88fx_i2s_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct mv88fx_snd_stream *audio_stream = runtime->private_data; struct mv88fx_snd_chip *chip = mv88fx_pcm_get_chip(substream); int result = 0; mv88fx_snd_debug("substream=%p cmd=%d audio_stream=%p", substream, cmd, audio_stream); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: /* FIXME: should check if busy before */ mv88fx_snd_debug(""); /* make sure the dma in pause state */ mv88fx_snd_bitset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_PAUSE_MASK); /* enable interrupt */ mv88fx_snd_bitset(chip->base, MV_AUDIO_INT_MASK_REG(chip->port), AICR_RECORD_BYTES_INT); /* enable dma */ mv88fx_snd_debug("dig_mode=%x", audio_stream->dig_mode); if (audio_stream->dig_mode & I2S) { mv88fx_snd_debug("enable dma"); mv88fx_snd_bitset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_I2S_EN_MASK); } if (audio_stream->dig_mode & SPDIF) { mv88fx_snd_debug("enable spdif dma"); mv88fx_snd_bitset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_SPDIF_EN_MASK); } /* start dma */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_PAUSE_MASK); break; case SNDRV_PCM_TRIGGER_STOP: /* make sure the dma in pause state */ mv88fx_snd_bitset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_PAUSE_MASK); /* disable interrupt */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_INT_MASK_REG(chip->port), AICR_RECORD_BYTES_INT); /* always stop both I2S and SPDIF */ mv88fx_snd_bitreset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), (ARCR_RECORD_I2S_EN_MASK | ARCR_RECORD_SPDIF_EN_MASK)); /* FIXME: should check if busy after */ break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: mv88fx_snd_bitset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_PAUSE_MASK); break; case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mv88fx_snd_bitreset(chip->base, MV_AUDIO_RECORD_CTRL_REG(chip->port), ARCR_RECORD_PAUSE_MASK); break; default: result = -EINVAL; break; } spin_unlock(&chip->reg_lock); mv88fx_snd_debug("result=%d", result); return result; }