static int mxs_pcm_dma_request(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mxs_runtime_data *prtd = runtime->private_data; struct mxs_pcm_dma_params *dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream); int desc_num = mxs_pcm_hardware.periods_max; int desc; int ret; if (!dma_data) return -ENODEV; prtd->params = dma_data; prtd->dma_ch = dma_data->dma_ch; ret = mxs_dma_request(prtd->dma_ch, mxs_pcm_dev, prtd->params->name); if (ret) { printk(KERN_ERR "%s: Failed to request DMA channel (%d:%d)\n", __func__, dma_data->dma_bus, dma_data->dma_ch); return ret; } /* Allocate memory for data and pio DMA descriptors */ for (desc = 0; desc < desc_num; desc++) { prtd->dma_desc_array[desc] = mxs_dma_alloc_desc(); if (prtd->dma_desc_array[desc] == NULL) { printk(KERN_ERR"%s Unable to allocate DMA command %d\n", __func__, desc); goto err; } } ret = request_irq(prtd->params->irq, mxs_pcm_dma_irq, 0, "MXS PCM DMA", substream); if (ret) { printk(KERN_ERR "%s: Unable to request DMA irq %d\n", __func__, prtd->params->irq); goto err; } /* Enable completion interrupt */ mxs_dma_ack_irq(prtd->dma_ch); mxs_dma_enable_irq(prtd->dma_ch, 1); return 0; err: while (--desc >= 0) mxs_dma_free_desc(prtd->dma_desc_array[desc]); mxs_dma_release(prtd->dma_ch, mxs_pcm_dev); return ret; }
static int __devexit mxs_hsadc_remove(struct platform_device *pdev) { struct mxs_hsadc_data *pd = platform_get_drvdata(pdev); u32 ctrl = 0; hsadc_cleanup_cdev(pd); // clean cdev interface if (pd->buf_phy) dma_free_coherent(NULL, DMA_BUF_SIZE, pd->buf, pd->buf_phy); if (pd->desc) mxs_dma_free_desc(pd->desc); mxs_dma_enable_irq(pd->dma_ch, 0); ctrl = readl(pd->hsadc_base + HSADC_CTRL1); ctrl &= ~(1<<31 | 1<<30 | 1<<29); // disable irq writel(ctrl, pd->hsadc_base + HSADC_CTRL1); mxs_dma_disable(pd->dma_ch); mxs_dma_release(pd->dma_ch, pd->dev); free_irq(pd->dev_irq, pd); free_irq(pd->dma_irq, pd); clk_disable(pd->hsadc_clk); clk_disable(pd->pwm_clk); clk_disable(pd->ref_hsadc_clk); clk_put(pd->hsadc_clk); clk_put(pd->pwm_clk); clk_put(pd->ref_hsadc_clk); iounmap(pd->pwm_base); iounmap(pd->hsadc_base); platform_set_drvdata(pdev, NULL); kfree(pd); #if HSADC_DEBUG printk(KERN_INFO "%s> driver removed.\n", HSADC_DEVICE_NAME); #endif 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; }