summaryrefslogtreecommitdiff
path: root/sound/soc/soc-generic-dmaengine-pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/soc-generic-dmaengine-pcm.c')
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c121
1 files changed, 97 insertions, 24 deletions
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index d53786498b61..56a541b9ff9e 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -33,13 +33,13 @@
struct dmaengine_pcm {
struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
const struct snd_dmaengine_pcm_config *config;
- struct snd_soc_platform platform;
+ struct snd_soc_component component;
unsigned int flags;
};
-static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
+static struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p)
{
- return container_of(p, struct dmaengine_pcm, platform);
+ return container_of(p, struct dmaengine_pcm, component);
}
static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
@@ -88,7 +88,9 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
int (*prepare_slave_config)(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
@@ -119,7 +121,9 @@ static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
struct dma_chan *chan = pcm->chan[substream->stream];
struct snd_dmaengine_dai_dma_data *dma_data;
@@ -128,7 +132,8 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
- int i, ret;
+ snd_pcm_format_t i;
+ int ret;
if (pcm->config && pcm->config->pcm_hardware)
return snd_soc_set_runtime_hwparams(substream,
@@ -178,7 +183,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
* default assumption is that it supports 1, 2 and 4 bytes
* widths.
*/
- for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+ for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) {
int bits = snd_pcm_format_physical_width(i);
/*
@@ -206,7 +211,9 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
struct dma_chan *chan = pcm->chan[substream->stream];
int ret;
@@ -221,7 +228,9 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_substream *substream)
{
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
struct snd_dmaengine_dai_dma_data *dma_data;
dma_filter_fn fn = NULL;
@@ -260,9 +269,11 @@ static bool dmaengine_pcm_can_report_residue(struct device *dev,
static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
const struct snd_dmaengine_pcm_config *config = pcm->config;
- struct device *dev = rtd->platform->dev;
+ struct device *dev = component->dev;
struct snd_dmaengine_dai_dma_data *dma_data;
struct snd_pcm_substream *substream;
size_t prealloc_buffer_size;
@@ -296,7 +307,7 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
}
if (!pcm->chan[i]) {
- dev_err(rtd->platform->dev,
+ dev_err(component->dev,
"Missing dma channel for stream: %d\n", i);
return -EINVAL;
}
@@ -320,7 +331,9 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
return snd_dmaengine_pcm_pointer_no_residue(substream);
@@ -328,6 +341,41 @@ static snd_pcm_uframes_t dmaengine_pcm_pointer(
return snd_dmaengine_pcm_pointer(substream);
}
+static int dmaengine_copy_user(struct snd_pcm_substream *substream,
+ int channel, unsigned long hwoff,
+ void *buf, unsigned long bytes)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_component *component =
+ snd_soc_rtdcom_lookup(rtd, SND_DMAENGINE_PCM_DRV_NAME);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct dmaengine_pcm *pcm = soc_component_to_pcm(component);
+ int (*process)(struct snd_pcm_substream *substream,
+ int channel, unsigned long hwoff,
+ void *buf, unsigned long bytes) = pcm->config->process;
+ bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+ void *dma_ptr = runtime->dma_area + hwoff +
+ channel * (runtime->dma_bytes / runtime->channels);
+ int ret;
+
+ if (is_playback)
+ if (copy_from_user(dma_ptr, (void __user *)buf, bytes))
+ return -EFAULT;
+
+ if (process) {
+ ret = process(substream, channel, hwoff,
+ (void __user *)buf, bytes);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (!is_playback)
+ if (copy_to_user((void __user *)buf, dma_ptr, bytes))
+ return -EFAULT;
+
+ return 0;
+}
+
static const struct snd_pcm_ops dmaengine_pcm_ops = {
.open = dmaengine_pcm_open,
.close = snd_dmaengine_pcm_close,
@@ -338,14 +386,31 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = {
.pointer = dmaengine_pcm_pointer,
};
-static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
- .component_driver = {
- .probe_order = SND_SOC_COMP_ORDER_LATE,
- },
+static const struct snd_pcm_ops dmaengine_pcm_process_ops = {
+ .open = dmaengine_pcm_open,
+ .close = snd_dmaengine_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = dmaengine_pcm_hw_params,
+ .hw_free = snd_pcm_lib_free_pages,
+ .trigger = snd_dmaengine_pcm_trigger,
+ .pointer = dmaengine_pcm_pointer,
+ .copy_user = dmaengine_copy_user,
+};
+
+static const struct snd_soc_component_driver dmaengine_pcm_component = {
+ .name = SND_DMAENGINE_PCM_DRV_NAME,
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
.ops = &dmaengine_pcm_ops,
.pcm_new = dmaengine_pcm_new,
};
+static const struct snd_soc_component_driver dmaengine_pcm_component_process = {
+ .name = SND_DMAENGINE_PCM_DRV_NAME,
+ .probe_order = SND_SOC_COMP_ORDER_LATE,
+ .ops = &dmaengine_pcm_process_ops,
+ .pcm_new = dmaengine_pcm_new,
+};
+
static const char * const dmaengine_pcm_dma_channel_names[] = {
[SNDRV_PCM_STREAM_PLAYBACK] = "tx",
[SNDRV_PCM_STREAM_CAPTURE] = "rx",
@@ -431,6 +496,9 @@ int snd_dmaengine_pcm_register(struct device *dev,
if (!pcm)
return -ENOMEM;
+#ifdef CONFIG_DEBUG_FS
+ pcm->component.debugfs_prefix = "dma";
+#endif
pcm->config = config;
pcm->flags = flags;
@@ -438,8 +506,13 @@ int snd_dmaengine_pcm_register(struct device *dev,
if (ret)
goto err_free_dma;
- ret = snd_soc_add_platform(dev, &pcm->platform,
- &dmaengine_pcm_platform);
+ if (config && config->process)
+ ret = snd_soc_add_component(dev, &pcm->component,
+ &dmaengine_pcm_component_process,
+ NULL, 0);
+ else
+ ret = snd_soc_add_component(dev, &pcm->component,
+ &dmaengine_pcm_component, NULL, 0);
if (ret)
goto err_free_dma;
@@ -461,16 +534,16 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
*/
void snd_dmaengine_pcm_unregister(struct device *dev)
{
- struct snd_soc_platform *platform;
+ struct snd_soc_component *component;
struct dmaengine_pcm *pcm;
- platform = snd_soc_lookup_platform(dev);
- if (!platform)
+ component = snd_soc_lookup_component(dev, SND_DMAENGINE_PCM_DRV_NAME);
+ if (!component)
return;
- pcm = soc_platform_to_pcm(platform);
+ pcm = soc_component_to_pcm(component);
- snd_soc_remove_platform(platform);
+ snd_soc_unregister_component(dev);
dmaengine_pcm_release_chan(pcm);
kfree(pcm);
}