diff options
Diffstat (limited to 'target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch')
-rw-r--r-- | target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch b/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch new file mode 100644 index 0000000000..296d5cccd1 --- /dev/null +++ b/target/linux/xburst/patches-3.10/016-ASoC-jz4740-Use-the-generic-dmaengine-PCM-driver.patch @@ -0,0 +1,519 @@ +From a20f54fdd500e5bccc9bd1ca4ac9f150addf2e64 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen <lars@metafoo.de> +Date: Sat, 27 Apr 2013 21:26:30 +0200 +Subject: [PATCH 16/16] ASoC: jz4740: Use the generic dmaengine PCM driver + +Since there is a dmaengine driver for the jz4740 DMA controller now we can use +the generic dmaengine PCM driver instead of a custom one. + +Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> +Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> +--- + sound/soc/jz4740/Kconfig | 1 + + sound/soc/jz4740/jz4740-i2s.c | 48 +++---- + sound/soc/jz4740/jz4740-pcm.c | 310 ++--------------------------------------- + sound/soc/jz4740/jz4740-pcm.h | 20 --- + 4 files changed, 27 insertions(+), 352 deletions(-) + delete mode 100644 sound/soc/jz4740/jz4740-pcm.h + +diff --git a/sound/soc/jz4740/Kconfig b/sound/soc/jz4740/Kconfig +index 5351cba..29f76af 100644 +--- a/sound/soc/jz4740/Kconfig ++++ b/sound/soc/jz4740/Kconfig +@@ -1,6 +1,7 @@ + config SND_JZ4740_SOC + tristate "SoC Audio for Ingenic JZ4740 SoC" + depends on MACH_JZ4740 && SND_SOC ++ select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for codecs attached to + the JZ4740 I2S interface. You will also need to select the audio +diff --git a/sound/soc/jz4740/jz4740-i2s.c b/sound/soc/jz4740/jz4740-i2s.c +index 9a12644..5d04134 100644 +--- a/sound/soc/jz4740/jz4740-i2s.c ++++ b/sound/soc/jz4740/jz4740-i2s.c +@@ -29,9 +29,12 @@ + #include <sound/pcm_params.h> + #include <sound/soc.h> + #include <sound/initval.h> ++#include <sound/dmaengine_pcm.h> ++ ++#include <asm/mach-jz4740/dma.h> + + #include "jz4740-i2s.h" +-#include "jz4740-pcm.h" ++ + + #define JZ_REG_AIC_CONF 0x00 + #define JZ_REG_AIC_CTRL 0x04 +@@ -89,8 +92,8 @@ struct jz4740_i2s { + struct clk *clk_aic; + struct clk *clk_i2s; + +- struct jz4740_pcm_config pcm_config_playback; +- struct jz4740_pcm_config pcm_config_capture; ++ struct snd_dmaengine_dai_dma_data playback_dma_data; ++ struct snd_dmaengine_dai_dma_data capture_dma_data; + }; + + static inline uint32_t jz4740_i2s_read(const struct jz4740_i2s *i2s, +@@ -233,8 +236,6 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + { + struct jz4740_i2s *i2s = snd_soc_dai_get_drvdata(dai); +- enum jz4740_dma_width dma_width; +- struct jz4740_pcm_config *pcm_config; + unsigned int sample_size; + uint32_t ctrl; + +@@ -243,11 +244,9 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + sample_size = 0; +- dma_width = JZ4740_DMA_WIDTH_8BIT; + break; + case SNDRV_PCM_FORMAT_S16: + sample_size = 1; +- dma_width = JZ4740_DMA_WIDTH_16BIT; + break; + default: + return -EINVAL; +@@ -260,22 +259,13 @@ static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, + ctrl |= JZ_AIC_CTRL_MONO_TO_STEREO; + else + ctrl &= ~JZ_AIC_CTRL_MONO_TO_STEREO; +- +- pcm_config = &i2s->pcm_config_playback; +- pcm_config->dma_config.dst_width = dma_width; +- + } else { + ctrl &= ~JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_MASK; + ctrl |= sample_size << JZ_AIC_CTRL_INPUT_SAMPLE_SIZE_OFFSET; +- +- pcm_config = &i2s->pcm_config_capture; +- pcm_config->dma_config.src_width = dma_width; + } + + jz4740_i2s_write(i2s, JZ_REG_AIC_CTRL, ctrl); + +- snd_soc_dai_set_dma_data(dai, substream, pcm_config); +- + return 0; + } + +@@ -342,25 +332,19 @@ static int jz4740_i2s_resume(struct snd_soc_dai *dai) + + static void jz4740_i2c_init_pcm_config(struct jz4740_i2s *i2s) + { +- struct jz4740_dma_config *dma_config; ++ struct snd_dmaengine_dai_dma_data *dma_data; + + /* Playback */ +- dma_config = &i2s->pcm_config_playback.dma_config; +- dma_config->src_width = JZ4740_DMA_WIDTH_32BIT; +- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; +- dma_config->request_type = JZ4740_DMA_TYPE_AIC_TRANSMIT; +- dma_config->flags = JZ4740_DMA_SRC_AUTOINC; +- dma_config->mode = JZ4740_DMA_MODE_SINGLE; +- i2s->pcm_config_playback.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; ++ dma_data = &i2s->playback_dma_data; ++ dma_data->maxburst = 16; ++ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_TRANSMIT; ++ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; + + /* Capture */ +- dma_config = &i2s->pcm_config_capture.dma_config; +- dma_config->dst_width = JZ4740_DMA_WIDTH_32BIT; +- dma_config->transfer_size = JZ4740_DMA_TRANSFER_SIZE_16BYTE; +- dma_config->request_type = JZ4740_DMA_TYPE_AIC_RECEIVE; +- dma_config->flags = JZ4740_DMA_DST_AUTOINC; +- dma_config->mode = JZ4740_DMA_MODE_SINGLE; +- i2s->pcm_config_capture.fifo_addr = i2s->phys_base + JZ_REG_AIC_FIFO; ++ dma_data = &i2s->capture_dma_data; ++ dma_data->maxburst = 16; ++ dma_data->slave_id = JZ4740_DMA_TYPE_AIC_RECEIVE; ++ dma_data->addr = i2s->phys_base + JZ_REG_AIC_FIFO; + } + + static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) +@@ -371,6 +355,8 @@ static int jz4740_i2s_dai_probe(struct snd_soc_dai *dai) + clk_enable(i2s->clk_aic); + + jz4740_i2c_init_pcm_config(i2s); ++ dai->playback_dma_data = &i2s->playback_dma_data; ++ dai->capture_dma_data = &i2s->capture_dma_data; + + conf = (7 << JZ_AIC_CONF_FIFO_RX_THRESHOLD_OFFSET) | + (8 << JZ_AIC_CONF_FIFO_TX_THRESHOLD_OFFSET) | +diff --git a/sound/soc/jz4740/jz4740-pcm.c b/sound/soc/jz4740/jz4740-pcm.c +index 7100592..79fcade 100644 +--- a/sound/soc/jz4740/jz4740-pcm.c ++++ b/sound/soc/jz4740/jz4740-pcm.c +@@ -19,38 +19,14 @@ + #include <linux/platform_device.h> + #include <linux/slab.h> + +-#include <linux/dma-mapping.h> ++#include <sound/dmaengine_pcm.h> + +-#include <sound/core.h> +-#include <sound/pcm.h> +-#include <sound/pcm_params.h> +-#include <sound/soc.h> +- +-#include <asm/mach-jz4740/dma.h> +-#include "jz4740-pcm.h" +- +-struct jz4740_runtime_data { +- unsigned long dma_period; +- dma_addr_t dma_start; +- dma_addr_t dma_pos; +- dma_addr_t dma_end; +- +- struct jz4740_dma_chan *dma; +- +- dma_addr_t fifo_addr; +-}; +- +-/* identify hardware playback capabilities */ + static const struct snd_pcm_hardware jz4740_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, +- +- .rates = SNDRV_PCM_RATE_8000_48000, +- .channels_min = 1, +- .channels_max = 2, + .period_bytes_min = 16, + .period_bytes_max = 2 * PAGE_SIZE, + .periods_min = 2, +@@ -59,290 +35,22 @@ static const struct snd_pcm_hardware jz4740_pcm_hardware = { + .fifo_size = 32, + }; + +-static void jz4740_pcm_start_transfer(struct jz4740_runtime_data *prtd, +- struct snd_pcm_substream *substream) +-{ +- unsigned long count; +- +- if (prtd->dma_pos == prtd->dma_end) +- prtd->dma_pos = prtd->dma_start; +- +- if (prtd->dma_pos + prtd->dma_period > prtd->dma_end) +- count = prtd->dma_end - prtd->dma_pos; +- else +- count = prtd->dma_period; +- +- jz4740_dma_disable(prtd->dma); +- +- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { +- jz4740_dma_set_src_addr(prtd->dma, prtd->dma_pos); +- jz4740_dma_set_dst_addr(prtd->dma, prtd->fifo_addr); +- } else { +- jz4740_dma_set_src_addr(prtd->dma, prtd->fifo_addr); +- jz4740_dma_set_dst_addr(prtd->dma, prtd->dma_pos); +- } +- +- jz4740_dma_set_transfer_count(prtd->dma, count); +- +- prtd->dma_pos += count; +- +- jz4740_dma_enable(prtd->dma); +-} +- +-static void jz4740_pcm_dma_transfer_done(struct jz4740_dma_chan *dma, int err, +- void *dev_id) +-{ +- struct snd_pcm_substream *substream = dev_id; +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd = runtime->private_data; +- +- snd_pcm_period_elapsed(substream); +- +- jz4740_pcm_start_transfer(prtd, substream); +-} +- +-static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream, +- struct snd_pcm_hw_params *params) +-{ +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd = runtime->private_data; +- struct snd_soc_pcm_runtime *rtd = substream->private_data; +- struct jz4740_pcm_config *config; +- +- config = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); +- +- if (!config) +- return 0; +- +- if (!prtd->dma) { +- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) +- prtd->dma = jz4740_dma_request(substream, "PCM Capture"); +- else +- prtd->dma = jz4740_dma_request(substream, "PCM Playback"); +- } +- +- if (!prtd->dma) +- return -EBUSY; +- +- jz4740_dma_configure(prtd->dma, &config->dma_config); +- prtd->fifo_addr = config->fifo_addr; +- +- jz4740_dma_set_complete_cb(prtd->dma, jz4740_pcm_dma_transfer_done); +- +- snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); +- runtime->dma_bytes = params_buffer_bytes(params); +- +- 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 + runtime->dma_bytes; +- +- return 0; +-} +- +-static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream) +-{ +- struct jz4740_runtime_data *prtd = substream->runtime->private_data; +- +- snd_pcm_set_runtime_buffer(substream, NULL); +- if (prtd->dma) { +- jz4740_dma_free(prtd->dma); +- prtd->dma = NULL; +- } +- +- return 0; +-} +- +-static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) +-{ +- struct jz4740_runtime_data *prtd = substream->runtime->private_data; +- +- if (!prtd->dma) +- return -EBUSY; +- +- prtd->dma_pos = prtd->dma_start; +- +- return 0; +-} +- +-static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +-{ +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd = runtime->private_data; +- +- switch (cmd) { +- case SNDRV_PCM_TRIGGER_START: +- case SNDRV_PCM_TRIGGER_RESUME: +- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +- jz4740_pcm_start_transfer(prtd, substream); +- break; +- case SNDRV_PCM_TRIGGER_STOP: +- case SNDRV_PCM_TRIGGER_SUSPEND: +- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +- jz4740_dma_disable(prtd->dma); +- break; +- default: +- break; +- } +- +- return 0; +-} +- +-static snd_pcm_uframes_t jz4740_pcm_pointer(struct snd_pcm_substream *substream) +-{ +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd = runtime->private_data; +- unsigned long byte_offset; +- snd_pcm_uframes_t offset; +- struct jz4740_dma_chan *dma = prtd->dma; +- +- /* prtd->dma_pos points to the end of the current transfer. So by +- * subtracting prdt->dma_start we get the offset to the end of the +- * current period in bytes. By subtracting the residue of the transfer +- * we get the current offset in bytes. */ +- byte_offset = prtd->dma_pos - prtd->dma_start; +- byte_offset -= jz4740_dma_get_residue(dma); +- +- offset = bytes_to_frames(runtime, byte_offset); +- if (offset >= runtime->buffer_size) +- offset = 0; +- +- return offset; +-} +- +-static int jz4740_pcm_open(struct snd_pcm_substream *substream) +-{ +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd; +- +- prtd = kzalloc(sizeof(*prtd), GFP_KERNEL); +- if (prtd == NULL) +- return -ENOMEM; +- +- snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); +- +- runtime->private_data = prtd; +- +- return 0; +-} +- +-static int jz4740_pcm_close(struct snd_pcm_substream *substream) +-{ +- struct snd_pcm_runtime *runtime = substream->runtime; +- struct jz4740_runtime_data *prtd = runtime->private_data; +- +- kfree(prtd); +- +- return 0; +-} +- +-static int jz4740_pcm_mmap(struct snd_pcm_substream *substream, +- struct vm_area_struct *vma) +-{ +- return remap_pfn_range(vma, vma->vm_start, +- substream->dma_buffer.addr >> PAGE_SHIFT, +- vma->vm_end - vma->vm_start, vma->vm_page_prot); +-} +- +-static struct snd_pcm_ops jz4740_pcm_ops = { +- .open = jz4740_pcm_open, +- .close = jz4740_pcm_close, +- .ioctl = snd_pcm_lib_ioctl, +- .hw_params = jz4740_pcm_hw_params, +- .hw_free = jz4740_pcm_hw_free, +- .prepare = jz4740_pcm_prepare, +- .trigger = jz4740_pcm_trigger, +- .pointer = jz4740_pcm_pointer, +- .mmap = jz4740_pcm_mmap, +-}; +- +-static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +-{ +- struct snd_pcm_substream *substream = pcm->streams[stream].substream; +- struct snd_dma_buffer *buf = &substream->dma_buffer; +- size_t size = jz4740_pcm_hardware.buffer_bytes_max; +- +- buf->dev.type = SNDRV_DMA_TYPE_DEV; +- buf->dev.dev = pcm->card->dev; +- buf->private_data = NULL; +- +- buf->area = dma_alloc_noncoherent(pcm->card->dev, size, +- &buf->addr, GFP_KERNEL); +- if (!buf->area) +- return -ENOMEM; +- +- buf->bytes = size; +- +- return 0; +-} +- +-static void jz4740_pcm_free(struct snd_pcm *pcm) +-{ +- struct snd_pcm_substream *substream; +- struct snd_dma_buffer *buf; +- int stream; +- +- for (stream = 0; stream < SNDRV_PCM_STREAM_LAST; ++stream) { +- substream = pcm->streams[stream].substream; +- if (!substream) +- continue; +- +- buf = &substream->dma_buffer; +- if (!buf->area) +- continue; +- +- dma_free_noncoherent(pcm->card->dev, buf->bytes, buf->area, +- buf->addr); +- buf->area = NULL; +- } +-} +- +-static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); +- +-static int jz4740_pcm_new(struct snd_soc_pcm_runtime *rtd) +-{ +- struct snd_card *card = rtd->card->snd_card; +- struct snd_pcm *pcm = rtd->pcm; +- int ret = 0; +- +- if (!card->dev->dma_mask) +- card->dev->dma_mask = &jz4740_pcm_dmamask; +- +- if (!card->dev->coherent_dma_mask) +- card->dev->coherent_dma_mask = DMA_BIT_MASK(32); +- +- if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { +- ret = jz4740_pcm_preallocate_dma_buffer(pcm, +- SNDRV_PCM_STREAM_PLAYBACK); +- if (ret) +- goto err; +- } +- +- if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { +- ret = jz4740_pcm_preallocate_dma_buffer(pcm, +- SNDRV_PCM_STREAM_CAPTURE); +- if (ret) +- goto err; +- } +- +-err: +- return ret; +-} +- +-static struct snd_soc_platform_driver jz4740_soc_platform = { +- .ops = &jz4740_pcm_ops, +- .pcm_new = jz4740_pcm_new, +- .pcm_free = jz4740_pcm_free, ++static const struct snd_dmaengine_pcm_config jz4740_dmaengine_pcm_config = { ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++ .pcm_hardware = &jz4740_pcm_hardware, ++ .prealloc_buffer_size = 256 * PAGE_SIZE, + }; + + static int jz4740_pcm_probe(struct platform_device *pdev) + { +- return snd_soc_register_platform(&pdev->dev, &jz4740_soc_platform); ++ return snd_dmaengine_pcm_register(&pdev->dev, ++ &jz4740_dmaengine_pcm_config, ++ SND_DMAENGINE_PCM_FLAG_COMPAT); + } + + static int jz4740_pcm_remove(struct platform_device *pdev) + { +- snd_soc_unregister_platform(&pdev->dev); ++ snd_dmaengine_pcm_unregister(&pdev->dev); + return 0; + } + +diff --git a/sound/soc/jz4740/jz4740-pcm.h b/sound/soc/jz4740/jz4740-pcm.h +deleted file mode 100644 +index 1220cbb..0000000 +--- a/sound/soc/jz4740/jz4740-pcm.h ++++ /dev/null +@@ -1,20 +0,0 @@ +-/* +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- */ +- +-#ifndef _JZ4740_PCM_H +-#define _JZ4740_PCM_H +- +-#include <linux/dma-mapping.h> +-#include <asm/mach-jz4740/dma.h> +- +- +-struct jz4740_pcm_config { +- struct jz4740_dma_config dma_config; +- phys_addr_t fifo_addr; +-}; +- +-#endif +-- +1.7.10.4 + |