static int tegra_set_avp_device(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); struct snd_soc_card *card = data->card; struct snd_soc_pcm_runtime *rtd; struct snd_pcm_substream *substream; struct tegra_runtime_data *prtd; int id, old_id = data->avp_device_id; id = ucontrol->value.integer.value[0]; if ((id >= card->num_rtd) || (id < 0)) id = -1; if (old_id >= 0) { rtd = &card->rtd[old_id]; substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (substream && substream->runtime) { prtd = (struct tegra_runtime_data *) snd_dmaengine_pcm_get_data(substream); if (!prtd) return -EINVAL; if (prtd->running) return -EBUSY; prtd->disable_intr = false; } } if (id >= 0) { rtd = &card->rtd[id]; substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (substream && substream->runtime) { prtd = (struct tegra_runtime_data *) snd_dmaengine_pcm_get_data(substream); if (!prtd) return -EINVAL; if (prtd->running) return -EBUSY; prtd->disable_intr = true; if (data->avp_dma_addr || prtd->avp_dma_addr) prtd->avp_dma_addr = data->avp_dma_addr; } } data->avp_device_id = id; return 1; }
static int tegra_get_dma_addr(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct tegra_asoc_utils_data *data = snd_kcontrol_chip(kcontrol); struct snd_soc_card *card = data->card; struct snd_soc_pcm_runtime *rtd; struct snd_pcm_substream *substream; struct tegra_runtime_data *prtd; if (data->avp_device_id < 0) return 0; rtd = &card->rtd[data->avp_device_id]; substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; if (!substream || !substream->runtime) return 0; prtd = (struct tegra_runtime_data *) snd_dmaengine_pcm_get_data(substream); if (!prtd) return 0; ucontrol->value.integer.value[0] = 0; ucontrol->value.integer.value[0] = prtd->avp_dma_addr ? (long)prtd->avp_dma_addr : (long)substream->runtime->dma_addr; return 0; }
/** * atmel_pcm_dma_irq: SSC interrupt handler for DMAENGINE enabled SSC * * We use DMAENGINE to send/receive data to/from SSC so this ISR is only to * check if any overrun occured. */ static void atmel_pcm_dma_irq(u32 ssc_sr, struct snd_pcm_substream *substream) { struct atmel_pcm_dma_params *prtd; prtd = snd_dmaengine_pcm_get_data(substream); if (ssc_sr & prtd->mask->ssc_error) { if (snd_pcm_running(substream)) pr_warn("atmel-pcm: buffer %s on %s (SSC_SR=%#x)\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "underrun" : "overrun", prtd->name, ssc_sr); /* stop RX and capture: will be enabled again at restart */ ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable); snd_pcm_stream_lock(substream); snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); snd_pcm_stream_unlock(substream); /* now drain RHR and read status to remove xrun condition */ ssc_readx(prtd->ssc->regs, SSC_RHR); ssc_readx(prtd->ssc->regs, SSC_SR); } }
int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_pcm_dma_params * dmap; struct tegra_runtime_data *prtd; if (rtd->dai_link->no_pcm) return 0; dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); prtd = (struct tegra_runtime_data *) snd_dmaengine_pcm_get_data(substream); if (!dmap) return 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: prtd->running = 1; if (prtd->disable_intr) { substream->runtime->dma_addr = prtd->avp_dma_addr; substream->runtime->no_period_wakeup = 1; } else { substream->runtime->no_period_wakeup = 0; } return snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_START); case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: prtd->running = 0; return snd_dmaengine_pcm_trigger(substream, SNDRV_PCM_TRIGGER_STOP); default: return -EINVAL; } return 0; }
static int tegra_pcm_close(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct tegra_runtime_data *tegra_prtd; if (rtd->dai_link->no_pcm) return 0; tegra_prtd = (struct tegra_runtime_data *)snd_dmaengine_pcm_get_data( substream); kfree(tegra_prtd); snd_dmaengine_pcm_set_data(substream, NULL); snd_dmaengine_pcm_close_release_chan(substream); return 0; }