/* * Make a circular DMA descriptor list */ static int mxs_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct mxs_runtime_data *prtd = runtime->private_data; dma_addr_t dma_buffer_phys; int periods_num, playback, i; playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0; periods_num = prtd->dma_totsize / prtd->dma_period; dma_buffer_phys = runtime->dma_addr; /* Reset DMA channel, enable interrupt */ mxs_dma_reset(prtd->dma_ch); /* Set up a DMA chain to sent DMA buffer */ for (i = 0; i < periods_num; i++) { int ret; /* Link with previous command */ prtd->dma_desc_array[i]->cmd.cmd.bits.bytes = prtd->dma_period; prtd->dma_desc_array[i]->cmd.cmd.bits.irq = 1; prtd->dma_desc_array[i]->cmd.cmd.bits.dec_sem = 0; prtd->dma_desc_array[i]->cmd.cmd.bits.chain = 1; /* Set DMA direction */ if (playback) prtd->dma_desc_array[i]->cmd.cmd.bits.command = \ DMA_READ; else prtd->dma_desc_array[i]->cmd.cmd.bits.command = \ DMA_WRITE; prtd->dma_desc_array[i]->cmd.address = dma_buffer_phys; ret = mxs_dma_desc_append(prtd->dma_ch, \ prtd->dma_desc_array[i]); if (ret) { printk(KERN_ERR "%s: Failed to append DMA descriptor\n", __func__); return ret; } /* Next data chunk */ dma_buffer_phys += prtd->dma_period; } return 0; }
int submit_request(struct mxs_hsadc_data* pdx, unsigned long count) { unsigned long sample_count; memset(pdx->buf, 0, count); pdx->desc->cmd.cmd.bits.bytes = count; pdx->desc->cmd.cmd.bits.pio_words = 0; pdx->desc->cmd.cmd.bits.wait4end = 1; pdx->desc->cmd.cmd.bits.dec_sem = 1; pdx->desc->cmd.cmd.bits.irq = 1; pdx->desc->cmd.cmd.bits.command = DMA_WRITE; pdx->desc->cmd.address = pdx->buf_phy; if(mxs_dma_desc_append(pdx->dma_ch, pdx->desc)) { return -EINVAL; } // // byte(s) to sample count // sample_count = adc_sample_percision == 8 ? count : (count >> 1); // 10-bit & 12-bit mode a sample word is two bytes size writel(sample_count, pdx->hsadc_base + HSADC_SEQUENCE_SAMPLES_NUM); writel(1, pdx->hsadc_base + HSADC_SEQUENCE_NUM); writel(1<<31 | 1<<30 | 1<<29, pdx->hsadc_base + HSADC_CTRL1); // enable irq mxs_dma_reset(pdx->dma_ch); mxs_dma_ack_irq(pdx->dma_ch); mxs_dma_enable_irq(pdx->dma_ch, 1); if(mxs_dma_enable(pdx->dma_ch)) { return -EINVAL; } writel(RUN, pdx->hsadc_base + HSADC_CTRL0_SET); writel(SOFT_TRIGGER, pdx->hsadc_base + HSADC_CTRL0_SET); return 0; }
static int mxs_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_pcm_runtime *runtime = substream->runtime; struct mxs_runtime_data *prtd = substream->runtime->private_data; int ret = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: if ((prtd->params->dma_ch == MXS_DMA_CHANNEL_AHB_APBX_SPDIF) && (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) && ((prtd->format == SNDRV_PCM_FORMAT_S24_LE) || (prtd->format == SNDRV_PCM_FORMAT_S20_3LE))) { prtd->appl_ptr_bytes = frames_to_bytes(runtime, runtime->control->appl_ptr); memmove(runtime->dma_area + 1, runtime->dma_area, prtd->appl_ptr_bytes - 1); } mxs_dma_enable(prtd->dma_ch); break; case SNDRV_PCM_TRIGGER_STOP: mxs_pcm_stop(substream); break; case SNDRV_PCM_TRIGGER_RESUME: if (mxs_pm_get_target() == PM_SUSPEND_MEM) { mxs_dma_reset(prtd->dma_ch); mxs_dma_ack_irq(prtd->dma_ch); mxs_dma_enable_irq(prtd->dma_ch, 1); mxs_pcm_prepare(substream); if ((prtd->params->dma_ch == MXS_DMA_CHANNEL_AHB_APBX_SPDIF) && (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) && (runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) && ((prtd->format == SNDRV_PCM_FORMAT_S24_LE) || (prtd->format == SNDRV_PCM_FORMAT_S20_3LE))) { prtd->appl_ptr_bytes = frames_to_bytes(runtime, runtime->control->appl_ptr); memmove(runtime->dma_area + 1, runtime->dma_area, prtd->appl_ptr_bytes - 1); } mxs_dma_enable(prtd->dma_ch); } else mxs_dma_unfreeze(prtd->dma_ch); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: mxs_dma_unfreeze(prtd->dma_ch); break; case SNDRV_PCM_TRIGGER_SUSPEND: if (mxs_pm_get_target() == PM_SUSPEND_MEM) { mxs_pcm_stop(substream); mdelay(30); } else { mxs_dma_freeze(prtd->dma_ch); mdelay(30); } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: mxs_dma_freeze(prtd->dma_ch); mdelay(30); break; default: ret = -EINVAL; break; } return ret; }