Skip to content

Commit

Permalink
Merge remote-tracking branch 'asoc/topic/dma' into asoc-next
Browse files Browse the repository at this point in the history
  • Loading branch information
broonie committed Apr 18, 2013
2 parents 8ef53f6 + 22f38f7 commit d45a26b
Show file tree
Hide file tree
Showing 60 changed files with 900 additions and 1,083 deletions.
92 changes: 88 additions & 4 deletions include/sound/dmaengine_pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define __SOUND_DMAENGINE_PCM_H__

#include <sound/pcm.h>
#include <sound/soc.h>
#include <linux/dmaengine.h>

/**
Expand All @@ -32,19 +33,102 @@ 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);
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
4 changes: 4 additions & 0 deletions include/sound/soc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand Down
29 changes: 9 additions & 20 deletions sound/soc/atmel/atmel-pcm-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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,
Expand All @@ -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");
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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,
Expand Down
1 change: 0 additions & 1 deletion sound/soc/cirrus/edb93xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
#include <sound/soc.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include "ep93xx-pcm.h"

static int edb93xx_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
Expand Down
9 changes: 5 additions & 4 deletions sound/soc/cirrus/ep93xx-ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
#include <sound/soc.h>

#include <linux/platform_data/dma-ep93xx.h>
#include "ep93xx-pcm.h"

/*
* Per channel (1-4) registers.
Expand Down Expand Up @@ -101,14 +100,16 @@ struct ep93xx_ac97_info {
/* currently ALSA only supports a single AC97 device */
static struct ep93xx_ac97_info *ep93xx_ac97_info;

static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
.name = "ac97-pcm-out",
.dma_port = EP93XX_DMA_AAC1,
.direction = DMA_MEM_TO_DEV,
};

static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
.name = "ac97-pcm-in",
.dma_port = EP93XX_DMA_AAC1,
.direction = DMA_DEV_TO_MEM,
};

static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
Expand Down Expand Up @@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct ep93xx_pcm_dma_params *dma_data;
struct ep93xx_dma_data *dma_data;

if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &ep93xx_ac97_pcm_out;
Expand Down
16 changes: 8 additions & 8 deletions sound/soc/cirrus/ep93xx-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
#include <mach/ep93xx-regs.h>
#include <linux/platform_data/dma-ep93xx.h>

#include "ep93xx-pcm.h"

#define EP93XX_I2S_TXCLKCFG 0x00
#define EP93XX_I2S_RXCLKCFG 0x04
#define EP93XX_I2S_GLCTRL 0x0C
Expand Down Expand Up @@ -62,18 +60,20 @@ struct ep93xx_i2s_info {
struct clk *mclk;
struct clk *sclk;
struct clk *lrclk;
struct ep93xx_pcm_dma_params *dma_params;
struct ep93xx_dma_data *dma_data;
void __iomem *regs;
};

struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
[SNDRV_PCM_STREAM_PLAYBACK] = {
.name = "i2s-pcm-out",
.dma_port = EP93XX_DMA_I2S1,
.port = EP93XX_DMA_I2S1,
.direction = DMA_MEM_TO_DEV,
},
[SNDRV_PCM_STREAM_CAPTURE] = {
.name = "i2s-pcm-in",
.dma_port = EP93XX_DMA_I2S1,
.port = EP93XX_DMA_I2S1,
.direction = DMA_DEV_TO_MEM,
},
};

Expand Down Expand Up @@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;

snd_soc_dai_set_dma_data(cpu_dai, substream,
&info->dma_params[substream->stream]);
&info->dma_data[substream->stream]);
return 0;
}

Expand Down Expand Up @@ -403,7 +403,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
}

dev_set_drvdata(&pdev->dev, info);
info->dma_params = ep93xx_i2s_dma_params;
info->dma_data = ep93xx_i2s_dma_data;

err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
if (err)
Expand Down
38 changes: 4 additions & 34 deletions sound/soc/cirrus/ep93xx-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
#include <mach/hardware.h>
#include <mach/ep93xx-regs.h>

#include "ep93xx-pcm.h"

static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
Expand Down Expand Up @@ -68,40 +66,12 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct ep93xx_pcm_dma_params *dma_params;
struct ep93xx_dma_data *dma_data;
int ret;

snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);

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

dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
dma_data->port = dma_params->dma_port;
dma_data->name = dma_params->name;
dma_data->direction = snd_pcm_substream_to_dma_direction(substream);

ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
if (ret) {
kfree(dma_data);
return ret;
}

snd_dmaengine_pcm_set_data(substream, dma_data);

return 0;
}

static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
{
struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);

snd_dmaengine_pcm_close(substream);
kfree(dma_data);
return 0;
return snd_dmaengine_pcm_open_request_chan(substream,
ep93xx_pcm_dma_filter,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
}

static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
Expand Down Expand Up @@ -131,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,

static struct snd_pcm_ops ep93xx_pcm_ops = {
.open = ep93xx_pcm_open,
.close = ep93xx_pcm_close,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = ep93xx_pcm_hw_params,
.hw_free = ep93xx_pcm_hw_free,
Expand Down
Loading

0 comments on commit d45a26b

Please sign in to comment.