Loading include/sound/dmaengine_pcm.h +88 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #define __SOUND_DMAENGINE_PCM_H__ #include <sound/pcm.h> #include <sound/soc.h> #include <linux/dmaengine.h> /** Loading @@ -32,9 +33,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream) return DMA_DEV_TO_MEM; } void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data); void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream); int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd); Loading @@ -42,9 +40,95 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); struct dma_chan *chan); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, void *filter_data); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); /** * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data * @addr: Address of the DAI data source or destination register. * @addr_width: Width of the DAI data source or destination register. * @maxburst: Maximum number of words(note: words, as in units of the * src_addr_width member, not bytes) that can be send to or received from the * DAI in one burst. * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; enum dma_slave_buswidth addr_width; u32 maxburst; unsigned int slave_id; void *filter_data; }; void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_pcm_substream *substream, const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); /* * Try to request the DMA channel using compat_request_channel or * compat_filter_fn if it couldn't be requested through devicetree. */ #define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0) /* * Don't try to request the DMA channels through devicetree. This flag only * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well. */ #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1) /* * The platforms dmaengine driver does not support reporting the amount of * bytes that are still left to transfer. */ #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM * @prepare_slave_config: Callback used to fill in the DMA slave_config for a * PCM substream. Will be called from the PCM drivers hwparams callback. * @compat_request_channel: Callback to request a DMA channel for platforms * which do not use devicetree. * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. * @prealloc_buffer_size: Size of the preallocated audio buffer. * * Note: If both compat_request_channel and compat_filter_fn are set * compat_request_channel will be used to request the channel and * compat_filter_fn will be ignored. Otherwise the channel will be requested * using dma_request_channel with compat_filter_fn as the filter function. */ struct snd_dmaengine_pcm_config { int (*prepare_slave_config)(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); struct dma_chan *(*compat_request_channel)( struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream); dma_filter_fn compat_filter_fn; const struct snd_pcm_hardware *pcm_hardware; unsigned int prealloc_buffer_size; }; int snd_dmaengine_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config, unsigned int flags); void snd_dmaengine_pcm_unregister(struct device *dev); int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); #endif include/sound/soc.h +4 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,10 @@ int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv); void snd_soc_remove_platform(struct snd_soc_platform *platform); struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev); int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); Loading sound/soc/Kconfig +4 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ config SND_SOC_AC97_BUS config SND_SOC_DMAENGINE_PCM bool config SND_SOC_GENERIC_DMAENGINE_PCM bool select SND_SOC_DMAENGINE_PCM # All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" Loading sound/soc/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) snd-soc-core-objs += soc-dmaengine-pcm.o endif ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) snd-soc-core-objs += soc-generic-dmaengine-pcm.o endif obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ Loading sound/soc/atmel/atmel-pcm-dma.c +9 −20 Original line number Diff line number Diff line Loading @@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { 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_dmaengine_pcm_get_data(substream); prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (ssc_sr & prtd->mask->ssc_error) { if (snd_pcm_running(substream)) Loading Loading @@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave) } static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd) { struct atmel_pcm_dma_params *prtd; struct ssc_device *ssc; struct dma_chan *dma_chan; struct dma_slave_config slave_config; int ret; prtd = snd_dmaengine_pcm_get_data(substream); ssc = prtd->ssc; ret = snd_hwparams_to_dma_slave_config(substream, params, Loading @@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, slave_config.src_maxburst = 1; } slave_config.device_fc = false; dma_chan = snd_dmaengine_pcm_get_chan(substream); if (dmaengine_slave_config(dma_chan, &slave_config)) { pr_err("atmel-pcm: failed to configure dma channel\n"); Loading @@ -158,15 +155,13 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, if (ssc->pdev) sdata = ssc->pdev->dev.platform_data; ret = snd_dmaengine_pcm_open(substream, filter, sdata); ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata); if (ret) { pr_err("atmel-pcm: dmaengine pcm open failed\n"); return -EINVAL; } snd_dmaengine_pcm_set_data(substream, prtd); ret = atmel_pcm_configure_dma(substream, params); ret = atmel_pcm_configure_dma(substream, params, prtd); if (ret) { pr_err("atmel-pcm: failed to configure dmai\n"); goto err; Loading @@ -176,15 +171,16 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, return 0; err: snd_dmaengine_pcm_close(substream); snd_dmaengine_pcm_close_release_chan(substream); return ret; } static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; prtd = snd_dmaengine_pcm_get_data(substream); prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); Loading @@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) return 0; } static int atmel_pcm_close(struct snd_pcm_substream *substream) { snd_dmaengine_pcm_close(substream); return 0; } static struct snd_pcm_ops atmel_pcm_ops = { .open = atmel_pcm_open, .close = atmel_pcm_close, .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, .prepare = atmel_pcm_dma_prepare, Loading Loading
include/sound/dmaengine_pcm.h +88 −4 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #define __SOUND_DMAENGINE_PCM_H__ #include <sound/pcm.h> #include <sound/soc.h> #include <linux/dmaengine.h> /** Loading @@ -32,9 +33,6 @@ snd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream) return DMA_DEV_TO_MEM; } void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data); void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream); int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream, const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd); Loading @@ -42,9 +40,95 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); struct dma_chan *chan); int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream); int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream, dma_filter_fn filter_fn, void *filter_data); int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream); struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn, void *filter_data); struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream); /** * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data * @addr: Address of the DAI data source or destination register. * @addr_width: Width of the DAI data source or destination register. * @maxburst: Maximum number of words(note: words, as in units of the * src_addr_width member, not bytes) that can be send to or received from the * DAI in one burst. * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. */ struct snd_dmaengine_dai_dma_data { dma_addr_t addr; enum dma_slave_buswidth addr_width; u32 maxburst; unsigned int slave_id; void *filter_data; }; void snd_dmaengine_pcm_set_config_from_dai_data( const struct snd_pcm_substream *substream, const struct snd_dmaengine_dai_dma_data *dma_data, struct dma_slave_config *config); /* * Try to request the DMA channel using compat_request_channel or * compat_filter_fn if it couldn't be requested through devicetree. */ #define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0) /* * Don't try to request the DMA channels through devicetree. This flag only * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well. */ #define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1) /* * The platforms dmaengine driver does not support reporting the amount of * bytes that are still left to transfer. */ #define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM * @prepare_slave_config: Callback used to fill in the DMA slave_config for a * PCM substream. Will be called from the PCM drivers hwparams callback. * @compat_request_channel: Callback to request a DMA channel for platforms * which do not use devicetree. * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. * @prealloc_buffer_size: Size of the preallocated audio buffer. * * Note: If both compat_request_channel and compat_filter_fn are set * compat_request_channel will be used to request the channel and * compat_filter_fn will be ignored. Otherwise the channel will be requested * using dma_request_channel with compat_filter_fn as the filter function. */ struct snd_dmaengine_pcm_config { int (*prepare_slave_config)(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); struct dma_chan *(*compat_request_channel)( struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream); dma_filter_fn compat_filter_fn; const struct snd_pcm_hardware *pcm_hardware; unsigned int prealloc_buffer_size; }; int snd_dmaengine_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config, unsigned int flags); void snd_dmaengine_pcm_unregister(struct device *dev); int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); #endif
include/sound/soc.h +4 −0 Original line number Diff line number Diff line Loading @@ -373,6 +373,10 @@ int snd_soc_poweroff(struct device *dev); int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv); void snd_soc_unregister_platform(struct device *dev); int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv); void snd_soc_remove_platform(struct snd_soc_platform *platform); struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev); int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, struct snd_soc_dai_driver *dai_drv, int num_dai); Loading
sound/soc/Kconfig +4 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,10 @@ config SND_SOC_AC97_BUS config SND_SOC_DMAENGINE_PCM bool config SND_SOC_GENERIC_DMAENGINE_PCM bool select SND_SOC_DMAENGINE_PCM # All the supported SoCs source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" Loading
sound/soc/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),) snd-soc-core-objs += soc-dmaengine-pcm.o endif ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) snd-soc-core-objs += soc-generic-dmaengine-pcm.o endif obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ Loading
sound/soc/atmel/atmel-pcm-dma.c +9 −20 Original line number Diff line number Diff line Loading @@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = { 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_dmaengine_pcm_get_data(substream); prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); if (ssc_sr & prtd->mask->ssc_error) { if (snd_pcm_running(substream)) Loading Loading @@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave) } static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd) { struct atmel_pcm_dma_params *prtd; struct ssc_device *ssc; struct dma_chan *dma_chan; struct dma_slave_config slave_config; int ret; prtd = snd_dmaengine_pcm_get_data(substream); ssc = prtd->ssc; ret = snd_hwparams_to_dma_slave_config(substream, params, Loading @@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, slave_config.src_maxburst = 1; } slave_config.device_fc = false; dma_chan = snd_dmaengine_pcm_get_chan(substream); if (dmaengine_slave_config(dma_chan, &slave_config)) { pr_err("atmel-pcm: failed to configure dma channel\n"); Loading @@ -158,15 +155,13 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, if (ssc->pdev) sdata = ssc->pdev->dev.platform_data; ret = snd_dmaengine_pcm_open(substream, filter, sdata); ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata); if (ret) { pr_err("atmel-pcm: dmaengine pcm open failed\n"); return -EINVAL; } snd_dmaengine_pcm_set_data(substream, prtd); ret = atmel_pcm_configure_dma(substream, params); ret = atmel_pcm_configure_dma(substream, params, prtd); if (ret) { pr_err("atmel-pcm: failed to configure dmai\n"); goto err; Loading @@ -176,15 +171,16 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream, return 0; err: snd_dmaengine_pcm_close(substream); snd_dmaengine_pcm_close_release_chan(substream); return ret; } static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct atmel_pcm_dma_params *prtd; prtd = snd_dmaengine_pcm_get_data(substream); prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); Loading @@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream) return 0; } static int atmel_pcm_close(struct snd_pcm_substream *substream) { snd_dmaengine_pcm_close(substream); return 0; } static struct snd_pcm_ops atmel_pcm_ops = { .open = atmel_pcm_open, .close = atmel_pcm_close, .close = snd_dmaengine_pcm_close_release_chan, .ioctl = snd_pcm_lib_ioctl, .hw_params = atmel_pcm_hw_params, .prepare = atmel_pcm_dma_prepare, Loading