/* 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); }
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; }
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; }
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); }
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; }
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; }
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; }
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); }
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); }
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; }
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; }
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; }
/*--------------------------------------------------------------------------*\ * 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; }
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; }
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); }
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; }
/* 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; }
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; }
/* * 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); }
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; }
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; }
/** * 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; }
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; }
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; }
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; }