Example #1
0
/* this may get called several times by oss emulation */
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct omap_pcm_dma_data *dma_data;
	struct dma_slave_config config;
	struct dma_chan *chan;
	int err = 0;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	/* return if this is a bufferless transfer e.g.
	 * codec <--> BT codec or GSM modem -- lg FIXME */
	if (!dma_data)
		return 0;

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
	runtime->dma_bytes = params_buffer_bytes(params);

	chan = snd_dmaengine_pcm_get_chan(substream);
	if (!chan)
		return -EINVAL;

	/* fills in addr_width and direction */
	err = snd_hwparams_to_dma_slave_config(substream, params, &config);
	if (err)
		return err;

	snd_dmaengine_pcm_set_config_from_dai_data(substream,
			snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
			&config);

	return dmaengine_slave_config(chan, &config);
}
Example #2
0
static int tegra_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct tegra_runtime_data *prtd;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct tegra_pcm_dma_params * dmap;
	int ret = 0;

	prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL);
	if (prtd == NULL)
		return -ENOMEM;

	runtime->private_data = prtd;
	prtd->substream = substream;

	spin_lock_init(&prtd->lock);

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
		setup_dma_tx_request(&prtd->dma_req[0], dmap);
		setup_dma_tx_request(&prtd->dma_req[1], dmap);
	} else {
		dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
		setup_dma_rx_request(&prtd->dma_req[0], dmap);
		setup_dma_rx_request(&prtd->dma_req[1], dmap);
	}

	prtd->dma_req[0].dev = prtd;
	prtd->dma_req[1].dev = prtd;

	prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_CONTINUOUS_SINGLE);
	if (prtd->dma_chan == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	/* Set HW params now that initialization is complete */
	snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);

	/* Ensure that buffer size is a multiple of period size */
	ret = snd_pcm_hw_constraint_integer(runtime,
						SNDRV_PCM_HW_PARAM_PERIODS);
	if (ret < 0)
		goto err;

	return 0;

err:
	if (prtd->dma_chan) {
		tegra_dma_free_channel(prtd->dma_chan);
	}

	kfree(prtd);

	return ret;
}
Example #3
0
static int s3c_dma_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct s3c24xx_runtime_data *prtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	unsigned long totbytes = params_buffer_bytes(params);
	struct s3c_dma_params *dma =
		snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
	int ret = 0;


	pr_debug("Entered %s\n", __func__);

	/* return if this is a bufferless transfer e.g.
	 * codec <--> BT codec or GSM modem -- lg FIXME */
	if (!dma)
		return 0;

	/* this may get called several times by oss emulation
	 * with different params -HW */
	if (prtd->params == NULL) {
		/* prepare DMA */
		prtd->params = dma;

		pr_debug("params %p, client %p, channel %d\n", prtd->params,
			prtd->params->client, prtd->params->channel);

		ret = s3c2410_dma_request(prtd->params->channel,
					  prtd->params->client, NULL);

		if (ret < 0) {
			printk(KERN_ERR "failed to get dma channel\n");
			return ret;
		}

		/* use the circular buffering if we have it available. */
		if (s3c_dma_has_circular())
			s3c2410_dma_setflags(prtd->params->channel,
					     S3C2410_DMAF_CIRCULAR);
	}

	s3c2410_dma_set_buffdone_fn(prtd->params->channel,
				    s3c24xx_audio_buffdone);

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	runtime->dma_bytes = totbytes;

	spin_lock_irq(&prtd->lock);
	prtd->dma_loaded = 0;
	prtd->dma_limit = runtime->hw.periods_min;
	prtd->dma_period = params_period_bytes(params);
	prtd->dma_start = runtime->dma_addr;
	prtd->dma_pos = prtd->dma_start;
	prtd->dma_end = prtd->dma_start + totbytes;
	spin_unlock_irq(&prtd->lock);

	return 0;
}
Example #4
0
static struct cygnus_aio_port *cygnus_dai_get_dma_data(
				struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;

	return snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream);
}
Example #5
0
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
	struct ep93xx_pcm_dma_params *dma_params;
	struct ep93xx_runtime_data *rtd;    
	int ret;

	dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
	snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);

	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
	if (!rtd) 
		return -ENOMEM;

	memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
	rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
	rtd->period_tasklet.data = (unsigned long)substream;

	rtd->cl.name = dma_params->name;
	rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
		((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
		 EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
	rtd->cl.cookie = substream;
	rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
	rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
	ret = ep93xx_dma_m2p_client_register(&rtd->cl);
	if (ret < 0) {
		kfree(rtd);
		return ret;
	}
	
	substream->runtime->private_data = rtd;
	return 0;
}
static void snd_imx_dma_err_callback(int channel, void *data, int err)
{
	struct snd_pcm_substream *substream = data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct imx_pcm_dma_params *dma_params = 
		snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
	int ret;

	pr_err("DMA timeout on channel %d -%s%s%s%s\n",
		 channel,
		 err & IMX_DMA_ERR_BURST ?    " burst" : "",
		 err & IMX_DMA_ERR_REQUEST ?  " request" : "",
		 err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
		 err & IMX_DMA_ERR_BUFFER ?   " buffer" : "");

	imx_dma_disable(iprtd->dma);
	ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
			IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
			DMA_MODE_WRITE : DMA_MODE_READ);
	if (!ret)
		imx_dma_enable(iprtd->dma);
}
static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct imx_pcm_dma_params *dma_params;
	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
	int err;

	dma_params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);

	iprtd->substream = substream;
	iprtd->buf = (unsigned int *)substream->dma_buffer.area;
	iprtd->period_cnt = 0;

	pr_debug("%s: buf: %p period: %d periods: %d\n",
			__func__, iprtd->buf, iprtd->period, iprtd->periods);

	err = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
			IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
			substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
			DMA_MODE_WRITE : DMA_MODE_READ);
	if (err)
		return err;

	return 0;
}
Example #8
0
static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *dai)
{
    struct snd_dmaengine_dai_dma_data *dma_data;
    u32 iismod;

    pr_debug("Entered %s\n", __func__);

    dma_data = snd_soc_dai_get_dma_data(dai, substream);

    /* Working copies of register */
    iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
    pr_debug("hw_params r: IISMOD: %x\n", iismod);

    switch (params_width(params)) {
    case 8:
        iismod &= ~S3C2410_IISMOD_16BIT;
        dma_data->addr_width = 1;
        break;
    case 16:
        iismod |= S3C2410_IISMOD_16BIT;
        dma_data->addr_width = 2;
        break;
    default:
        return -EINVAL;
    }

    writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
    pr_debug("hw_params w: IISMOD: %x\n", iismod);
    return 0;
}
Example #9
0
static int skl_link_pcm_trigger(struct snd_pcm_substream *substream,
	int cmd, struct snd_soc_dai *dai)
{
	struct hdac_ext_stream *link_dev =
				snd_soc_dai_get_dma_data(dai, substream);
	struct hdac_ext_bus *ebus = get_bus_ctx(substream);
	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);

	dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_RESUME:
		skl_link_pcm_prepare(substream, dai);
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		snd_hdac_ext_stream_decouple(ebus, stream, true);
		snd_hdac_ext_link_stream_start(link_dev);
		break;

	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_STOP:
		snd_hdac_ext_link_stream_clear(link_dev);
		if (cmd == SNDRV_PCM_TRIGGER_SUSPEND)
			snd_hdac_ext_stream_decouple(ebus, stream, false);
		break;

	default:
		return -EINVAL;
	}
	return 0;
}
Example #10
0
static int skl_link_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
	struct hdac_ext_stream *link_dev;
	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
	struct hdac_ext_dma_params *dma_params;
	struct snd_soc_dai *codec_dai = rtd->codec_dai;
	struct skl_pipe_params p_params = {0};

	link_dev = snd_hdac_ext_stream_assign(ebus, substream,
					HDAC_EXT_STREAM_TYPE_LINK);
	if (!link_dev)
		return -EBUSY;

	snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);

	/* set the stream tag in the codec dai dma params  */
	dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
	if (dma_params)
		dma_params->stream_tag =  hdac_stream(link_dev)->stream_tag;

	p_params.s_fmt = snd_pcm_format_width(params_format(params));
	p_params.ch = params_channels(params);
	p_params.s_freq = params_rate(params);
	p_params.stream = substream->stream;
	p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1;

	return skl_tplg_be_update_params(dai, &p_params);
}
Example #11
0
static void skl_pcm_close(struct snd_pcm_substream *substream,
		struct snd_soc_dai *dai)
{
	struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
	struct skl_dma_params *dma_params = NULL;
	struct skl *skl = ebus_to_skl(ebus);

	dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name);

	snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus));

	dma_params = snd_soc_dai_get_dma_data(dai, substream);
	/*
	 * now we should set this to NULL as we are freeing by the
	 * dma_params
	 */
	snd_soc_dai_set_dma_data(dai, substream, NULL);
	skl_set_suspend_active(substream, dai, false);

	/*
	 * check if close is for "Reference Pin" and set back the
	 * CGCTL.MISCBDCGE if disabled by driver
	 */
	if (!strncmp(dai->name, "Reference Pin", 13) &&
			skl->skl_sst->miscbdcg_disabled) {
		skl->skl_sst->enable_miscbdcge(dai->dev, true);
		skl->skl_sst->miscbdcg_disabled = false;
	}

	kfree(dma_params);
}
Example #12
0
static int skl_get_format(struct snd_pcm_substream *substream,
		struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
	struct skl_dma_params *dma_params;
	struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
	int format_val = 0;

	if (ebus->ppcap) {
		struct snd_pcm_runtime *runtime = substream->runtime;

		format_val = snd_hdac_calc_stream_format(runtime->rate,
						runtime->channels,
						runtime->format,
						32, 0);
	} else {
		struct snd_soc_dai *codec_dai = rtd->codec_dai;

		dma_params = snd_soc_dai_get_dma_data(codec_dai, substream);
		if (dma_params)
			format_val = dma_params->format;
	}

	return format_val;
}
Example #13
0
static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct tegra_runtime_data *prtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct tegra_pcm_dma_params * dmap;

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
	if (dmap) {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			setup_dma_tx_request(&prtd->dma_req[0], dmap);
			setup_dma_tx_request(&prtd->dma_req[1], dmap);
		} else {
			setup_dma_rx_request(&prtd->dma_req[0], dmap);
			setup_dma_rx_request(&prtd->dma_req[1], dmap);
		}
	}
	prtd->dma_req[0].size = params_period_bytes(params);
	prtd->dma_req[1].size = prtd->dma_req[0].size;

	return 0;
}
Example #14
0
static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct atmel_pcm_dma_params *prtd;
	struct ssc_device *ssc;
	int ret;

	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
	ssc = prtd->ssc;

	ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
	if (ret) {
		pr_err("atmel-pcm: hwparams to dma slave configure failed\n");
		return ret;
	}

	slave_config->dst_addr = ssc->phybase + SSC_THR;
	slave_config->dst_maxburst = 1;

	slave_config->src_addr = ssc->phybase + SSC_RHR;
	slave_config->src_maxburst = 1;

	prtd->dma_intr_handler = atmel_pcm_dma_irq;

	return 0;
}
Example #15
0
/*--------------------------------------------------------------------------*\
 * PCM operations
\*--------------------------------------------------------------------------*/
static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct atmel_runtime_data *prtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;

	/* this may get called several times by oss emulation
	 * with different params */

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
	runtime->dma_bytes = params_buffer_bytes(params);

	prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;

	prtd->dma_buffer = runtime->dma_addr;
	prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
	prtd->period_size = params_period_bytes(params);

	pr_debug("atmel-pcm: "
		"hw_params: DMA for %s initialized "
		"(dma_bytes=%u, period_size=%u)\n",
		prtd->params->name,
		runtime->dma_bytes,
		prtd->period_size);
	return 0;
}
Example #16
0
static int pxa3xx_ssp_startup(struct snd_pcm_substream *substream,
	struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
	struct ssp_device *ssp;
	int ret = 0;
	u32 sscr0;

	if (!cpu_dai->active) {
		ret = ssp_init(&ssp_dev[cpu_dai->id], cpu_dai->id + 1,
				SSP_NO_IRQ);
		if(ret)
			return ret;
		ssp = ssp_dev[cpu_dai->id].ssp; 
		sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
		sscr0 &= ~SSCR0_SSE;
		__raw_writel(sscr0, ssp->mmio_base + SSCR0);

		cpu_dai->private_data = ssp;
	}

	kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);

	return ret;
}
/**
 * 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 snd_soc_pcm_runtime *rtd = substream->private_data;
	struct atmel_pcm_dma_params *prtd;

	prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, 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);
	}
}
static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct sport_device *sport = runtime->private_data;
	unsigned int diff;
	snd_pcm_uframes_t frames;
	struct bf5xx_i2s_pcm_data *dma_data;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	pr_debug("%s enter\n", __func__);
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		diff = sport_curr_offset_tx(sport);
	} else {
		diff = sport_curr_offset_rx(sport);
	}

	/*
	 * TX at least can report one frame beyond the end of the
	 * buffer if we hit the wraparound case - clamp to within the
	 * buffer as the ALSA APIs require.
	 */
	if (diff == snd_pcm_lib_buffer_bytes(substream))
		diff = 0;

	frames = bytes_to_frames(substream->runtime, diff);
	if (dma_data->tdm_mode)
		frames = frames * runtime->channels / 8;

	return frames;
}
static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct sport_device *sport = runtime->private_data;
	int period_bytes = frames_to_bytes(runtime, runtime->period_size);
	struct bf5xx_i2s_pcm_data *dma_data;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	if (dma_data->tdm_mode)
		period_bytes = period_bytes / runtime->channels * 8;

	pr_debug("%s enter\n", __func__);
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
		sport_config_tx_dma(sport, runtime->dma_area,
			runtime->periods, period_bytes);
	} else {
		sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
		sport_config_rx_dma(sport, runtime->dma_area,
			runtime->periods, period_bytes);
	}

	return 0;
}
Example #20
0
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct omap_mcbsp_data *mcbsp_data = snd_soc_dai_get_drvdata(cpu_dai);
	struct omap_pcm_dma_data *dma_data;
	int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
	int words;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
	if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
		/*
		 * Configure McBSP threshold based on either:
		 * packet_size, when the sDMA is in packet mode, or
		 * based on the period size.
		 */
		if (dma_data->packet_size)
			words = dma_data->packet_size;
		else
			words = snd_pcm_lib_period_bytes(substream) /
							(mcbsp_data->wlen / 8);
	else
		words = 1;

	/* Configure McBSP internal buffer usage */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
	else
		omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
}
Example #21
0
int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct tegra_runtime_data *prtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct tegra_pcm_dma_params * dmap;
	int i;

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	/* Limit dma_req_count to period count */
	if (prtd->dma_req_count > params_periods(params))
		prtd->dma_req_count = params_periods(params);
	dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
	if (dmap) {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			for (i = 0; i < prtd->dma_req_count; i++)
				setup_dma_tx_request(&prtd->dma_req[i], dmap);
		} else {
			for (i = 0; i < prtd->dma_req_count; i++)
				setup_dma_rx_request(&prtd->dma_req[i], dmap);
		}
	}
	for (i = 0; i < prtd->dma_req_count; i++)
		prtd->dma_req[i].size = params_period_bytes(params);

	return 0;
}
Example #22
0
/* this may get called several times by oss emulation */
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
			      struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct omap_runtime_data *prtd = runtime->private_data;
	struct omap_pcm_dma_data *dma_data;
	int err = 0;

	dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);

	/* return if this is a bufferless transfer e.g.
	 * codec <--> BT codec or GSM modem -- lg FIXME */
	if (!dma_data)
		return 0;

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
	runtime->dma_bytes = params_buffer_bytes(params);

	if (prtd->dma_data)
		return 0;
	prtd->dma_data = dma_data;
	err = omap_request_dma(dma_data->dma_req, dma_data->name,
			       omap_pcm_dma_irq, substream, &prtd->dma_ch);
	if (!err) {
		/*
		 * Link channel with itself so DMA doesn't need any
		 * reprogramming while looping the buffer
		 */
		omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
	}

	return err;
}
Example #23
0
static int sun5i_spdif_trigger(struct snd_pcm_substream *substream,
                              int cmd, struct snd_soc_dai *dai)
{
	int ret = 0;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct sun5i_dma_params *dma_data = 
					snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	switch (cmd) {
		case SNDRV_PCM_TRIGGER_START:
		case SNDRV_PCM_TRIGGER_RESUME:
		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
			if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
				sun5i_snd_rxctrl(1);
			} else {
				sun5i_snd_txctrl(substream, 1);
			}
			sw_dma_ctrl(dma_data->channel, SW_DMAOP_STARTED);
			break;
		case SNDRV_PCM_TRIGGER_STOP:
		case SNDRV_PCM_TRIGGER_SUSPEND:
		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
			if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
				sun5i_snd_rxctrl(0);
			} else {
			  sun5i_snd_txctrl(substream, 0);
			}
			break;
		default:
			ret = -EINVAL;
			break;
	}

		return ret;
}					
Example #24
0
/*
 * Stream DMA parameters. DMA request line and port address are set runtime
 * since they are different between OMAP1 and later OMAPs
 */
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
	struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
	struct omap_pcm_dma_data *dma_data;
	int words;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	/*
	 * Configure McBSP threshold based on either:
	 * packet_size, when the sDMA is in packet mode, or based on the
	 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
	 * for mono streams.
	 */
	if (dma_data->packet_size)
		words = dma_data->packet_size;
	else
		words = 1;

	/* Configure McBSP internal buffer usage */
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		omap_mcbsp_set_tx_threshold(mcbsp, words);
	else
		omap_mcbsp_set_rx_threshold(mcbsp, words);
}
Example #25
0
static int ux500_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
        struct snd_pcm_hw_params *params,
        struct dma_slave_config *slave_config)
{
    struct snd_soc_pcm_runtime *rtd = substream->private_data;
    struct ux500_msp_dma_params *dma_params;
    struct stedma40_chan_cfg *dma_cfg;
    int ret;

    dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
    dma_cfg = dma_params->dma_cfg;

    ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
    if (ret)
        return ret;

    slave_config->dst_maxburst = 4;
    slave_config->dst_addr_width = dma_cfg->dst_info.data_width;
    slave_config->src_maxburst = 4;
    slave_config->src_addr_width = dma_cfg->src_info.data_width;

    if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
        slave_config->dst_addr = dma_params->tx_rx_addr;
    else
        slave_config->src_addr = dma_params->tx_rx_addr;

    return 0;
}
Example #26
0
static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
			     int channel, unsigned long pos,
			     unsigned long count)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int sample_size = runtime->sample_bits / 8;
	void *buf = runtime->dma_area;
	struct bf5xx_i2s_pcm_data *dma_data;
	unsigned int offset, samples;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	if (dma_data->tdm_mode) {
		offset = bytes_to_frames(runtime, pos) * 8 * sample_size;
		samples = bytes_to_frames(runtime, count) * 8;
	} else {
		offset = pos;
		samples = bytes_to_samples(runtime, count);
	}

	snd_pcm_format_set_silence(runtime->format, buf + offset, samples);

	return 0;
}
Example #27
0
/**
 * ssp_dai_hw_params - Allocate memory for Ring Buffer according
 * to hw_params.
 * It's called in a non-atomic context
 *
 * @param substream Substream for which the stream function is called
 * @param hw_params Stream command thats requested from upper layer
 * @param cpu_dai Pointer to the CPU DAI that is used
 * return status 0 ==> OK
 *
 */
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
		struct snd_pcm_hw_params *hw_params,
		struct snd_soc_dai *cpu_dai)
{
	struct intel_ssp_config *ssp_config;

	pr_info("SSP DAI: FCT %s enters\n",
			__func__);

	WARN(!cpu_dai, "SSP DAI: ERROR NULL cpu_dai\n");
	if (!cpu_dai)
		return -EINVAL;

	ssp_config = snd_soc_dai_get_dma_data(cpu_dai, substream);
	pr_info("SSP DAI: FCT %s ssp_config %p\n",
				__func__,
				ssp_config);

	/*
	 * The set HW Config is only once for a CPU DAI
	 */

	if (cpu_dai->active == 1) {
		intel_mid_i2s_command(ssp_config->i2s_handle,
						SSP_CMD_SET_HW_CONFIG,
						&(ssp_config->i2s_settings));

	}

	switch (substream->stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
		if (intel_mid_i2s_command(ssp_config->i2s_handle,
				SSP_CMD_ALLOC_TX, NULL)) {
			pr_err("can not alloc TX DMA Channel\n");
			return -EBUSY;
		}
		break;

	case SNDRV_PCM_STREAM_CAPTURE:
		if (intel_mid_i2s_command(ssp_config->i2s_handle,
				SSP_CMD_ALLOC_RX, NULL)) {
			pr_err("can not alloc RX DMA Channel\n");
			return -EBUSY;
		}
		break;

	default:
		pr_err("SSP DAI: FCT %s Bad stream_dir: %d\n",
				__func__, substream->stream);
		return -EINVAL;
	}

	ssp_config->intel_mid_dma_alloc = true;

	pr_debug("SSP DAI: FCT %s leaves\n",
			__func__);

	return 0;
}
Example #28
0
static int edma_engine_config(struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct mvf_pcm_runtime_data *iprtd = runtime->private_data;
	u32 size = frames_to_bytes(runtime, runtime->period_size);
	struct imx_pcm_dma_params *dma_params;
	u32 sg_addr;
	int i;

	dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	iprtd->dma_buf_phys = runtime->dma_addr;
	iprtd->dma_buf_next = iprtd->dma_buf_phys;
	iprtd->dma_buf_end = iprtd->dma_buf_phys + runtime->periods * size;

	sg_addr = iprtd->tcd_buf_phys;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		iprtd->src_addr = iprtd->dma_buf_next;
		iprtd->dst_addr = dma_params->dma_addr;
		iprtd->soffset = 2;
		iprtd->doffset = 0;
	} else {
		iprtd->src_addr = dma_params->dma_addr;
		iprtd->dst_addr = iprtd->dma_buf_next;
		iprtd->soffset = 0;
		iprtd->doffset = 2;
	}

	mcf_edma_set_tcd_params(iprtd->tcd_chan,
		iprtd->src_addr, iprtd->dst_addr,
		MCF_EDMA_TCD_ATTR_SSIZE_16BIT | MCF_EDMA_TCD_ATTR_DSIZE_16BIT,
		iprtd->soffset, 4, 0, size / 4, size / 4, iprtd->doffset,
		sg_addr, 1, 0, 1);

	for (i = 0; i < TCD_NUMBER; i++) {
		iprtd->dma_buf_next += size;
		if (iprtd->dma_buf_next >= iprtd->dma_buf_end)
			iprtd->dma_buf_next = iprtd->dma_buf_phys;

		sg_addr = iprtd->tcd_buf_phys +
			((i + 1) % TCD_NUMBER) * sizeof(struct edma_tcd);

		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			iprtd->src_addr = iprtd->dma_buf_next;
		else
			iprtd->dst_addr = iprtd->dma_buf_next;

		fill_tcd_params(&iprtd->tcd[i],
			iprtd->src_addr, iprtd->dst_addr,
			MCF_EDMA_TCD_ATTR_SSIZE_16BIT |
				MCF_EDMA_TCD_ATTR_DSIZE_16BIT,
			iprtd->soffset, 4, 0, size / 4, size / 4,
			iprtd->doffset, sg_addr, 1, 0, 1);
	}

	return 0;
}
Example #29
0
static int bf5xx_pcm_copy(struct snd_pcm_substream *substream,
			  int channel, unsigned long pos,
			  void *buf, unsigned long count)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned int sample_size = runtime->sample_bits / 8;
	struct bf5xx_i2s_pcm_data *dma_data;
	unsigned int i;
	void *src, *dst;

	dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);

	if (dma_data->tdm_mode) {
		pos = bytes_to_frames(runtime, pos);
		count = bytes_to_frames(runtime, count);
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			src = buf;
			dst = runtime->dma_area;
			dst += pos * sample_size * 8;

			while (count--) {
				for (i = 0; i < runtime->channels; i++) {
					memcpy(dst + dma_data->map[i] *
						sample_size, src, sample_size);
					src += sample_size;
				}
				dst += 8 * sample_size;
			}
		} else {
			src = runtime->dma_area;
			src += pos * sample_size * 8;
			dst = buf;

			while (count--) {
				for (i = 0; i < runtime->channels; i++) {
					memcpy(dst, src + dma_data->map[i] *
						sample_size, sample_size);
					dst += sample_size;
				}
				src += 8 * sample_size;
			}
		}
	} else {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
			src = buf;
			dst = runtime->dma_area;
			dst += pos;
		} else {
			src = runtime->dma_area;
			src += pos;
			dst = buf;
		}

		memcpy(dst, src, count);
	}

	return 0;
}
Example #30
0
static int dma_hw_params(struct snd_pcm_substream *substream,
	struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct runtime_data *prtd = runtime->private_data;
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	unsigned long totbytes = params_buffer_bytes(params);
	struct s3c_dma_params *dma =
		snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
	struct samsung_dma_req req;
	struct samsung_dma_config config;

	pr_debug("Entered %s\n", __func__);

	/* return if this is a bufferless transfer e.g.
	 * codec <--> BT codec or GSM modem -- lg FIXME */
	if (!dma)
		return 0;

	/* this may get called several times by oss emulation
	 * with different params -HW */
	if (prtd->params == NULL) {
		/* prepare DMA */
		prtd->params = dma;

		pr_debug("params %p, client %p, channel %d\n", prtd->params,
			prtd->params->client, prtd->params->channel);

		prtd->params->ops = samsung_dma_get_ops();

		req.cap = (samsung_dma_has_circular() ?
			DMA_CYCLIC : DMA_SLAVE);
		req.client = prtd->params->client;
		config.direction =
			(substream->stream == SNDRV_PCM_STREAM_PLAYBACK
			? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
		config.width = prtd->params->dma_size;
		config.maxburst = 1;
		config.fifo = prtd->params->dma_addr;
		prtd->params->ch = prtd->params->ops->request(
				prtd->params->channel, &req);
		prtd->params->ops->config(prtd->params->ch, &config);
	}

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	runtime->dma_bytes = totbytes;

	spin_lock_irq(&prtd->lock);
	prtd->dma_loaded = 0;
	prtd->dma_period = params_period_bytes(params);
	prtd->dma_start = runtime->dma_addr;
	prtd->dma_pos = prtd->dma_start;
	prtd->dma_end = prtd->dma_start + totbytes;
	spin_unlock_irq(&prtd->lock);

	return 0;
}