Skip to content

Commit

Permalink
ASoC: pxa: pxa-pcm-lib: switch over to snd-soc-dmaengine-pcm
Browse files Browse the repository at this point in the history
This patch removes the old PXA DMA API usage and switches over to
generic functions provided by snd-soc-dmaengine-pcm.

More cleanups may be done on top of this, and some function stubs can
now be removed completetly. However, the intention here was to keep
the transition as small as possible.

This was tested on the mioa701 pxa27x board.

Signed-off-by: Daniel Mack <[email protected]>
[trivial change from mmp-dma to pxa-dma]
Signed-off-by: Robert Jarzmik <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
zonque authored and broonie committed Sep 30, 2015
1 parent 5c0e869 commit 58ceb57
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 228 deletions.
1 change: 0 additions & 1 deletion include/sound/pxa2xx-lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ extern int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
extern snd_pcm_uframes_t pxa2xx_pcm_pointer(struct snd_pcm_substream *substream);
extern int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream);
extern void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id);
extern int __pxa2xx_pcm_open(struct snd_pcm_substream *substream);
extern int __pxa2xx_pcm_close(struct snd_pcm_substream *substream);
extern int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
Expand Down
13 changes: 11 additions & 2 deletions sound/arm/pxa2xx-ac97.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmaengine.h>
#include <linux/dma/pxa-dma.h>

#include <sound/core.h>
#include <sound/pcm.h>
Expand Down Expand Up @@ -43,15 +44,23 @@ static struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
.reset = pxa2xx_ac97_reset,
};

static unsigned long pxa2xx_ac97_pcm_out_req = 12;
static struct pxad_param pxa2xx_ac97_pcm_out_req = {
.prio = PXAD_PRIO_LOWEST,
.drcmr = 12,
};

static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_out = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
.maxburst = 32,
.filter_data = &pxa2xx_ac97_pcm_out_req,
};

static unsigned long pxa2xx_ac97_pcm_in_req = 11;
static struct pxad_param pxa2xx_ac97_pcm_in_req = {
.prio = PXAD_PRIO_LOWEST,
.drcmr = 11,
};

static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_in = {
.addr = __PREG(PCDR),
.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
Expand Down
201 changes: 36 additions & 165 deletions sound/arm/pxa2xx-pcm-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/dma/pxa-dma.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/pxa2xx-lib.h>
#include <sound/dmaengine_pcm.h>

#include <mach/dma.h>

#include "pxa2xx-pcm.h"

static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
Expand All @@ -31,188 +30,81 @@ static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
.period_bytes_min = 32,
.period_bytes_max = 8192 - 32,
.periods_min = 1,
.periods_max = PAGE_SIZE/sizeof(pxa_dma_desc),
.periods_max = 256,
.buffer_bytes_max = 128 * 1024,
.fifo_size = 32,
};

int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd = runtime->private_data;
size_t totsize = params_buffer_bytes(params);
size_t period = params_period_bytes(params);
pxa_dma_desc *dma_desc;
dma_addr_t dma_buff_phys, next_desc_phys;
u32 dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_dmaengine_dai_dma_data *dma_params;
struct dma_slave_config config;
int ret;

/* temporary transition hack */
switch (rtd->params->addr_width) {
case DMA_SLAVE_BUSWIDTH_1_BYTE:
dcmd |= DCMD_WIDTH1;
break;
case DMA_SLAVE_BUSWIDTH_2_BYTES:
dcmd |= DCMD_WIDTH2;
break;
case DMA_SLAVE_BUSWIDTH_4_BYTES:
dcmd |= DCMD_WIDTH4;
break;
default:
/* can't happen */
break;
}
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!dma_params)
return 0;

switch (rtd->params->maxburst) {
case 8:
dcmd |= DCMD_BURST8;
break;
case 16:
dcmd |= DCMD_BURST16;
break;
case 32:
dcmd |= DCMD_BURST32;
break;
}
ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
if (ret)
return ret;

snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = totsize;
snd_dmaengine_pcm_set_config_from_dai_data(substream,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
&config);

dma_desc = rtd->dma_desc_array;
next_desc_phys = rtd->dma_desc_array_phys;
dma_buff_phys = runtime->dma_addr;
do {
next_desc_phys += sizeof(pxa_dma_desc);
dma_desc->ddadr = next_desc_phys;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_desc->dsadr = dma_buff_phys;
dma_desc->dtadr = rtd->params->addr;
} else {
dma_desc->dsadr = rtd->params->addr;
dma_desc->dtadr = dma_buff_phys;
}
if (period > totsize)
period = totsize;
dma_desc->dcmd = dcmd | period | DCMD_ENDIRQEN;
dma_desc++;
dma_buff_phys += period;
} while (totsize -= period);
dma_desc[-1].ddadr = rtd->dma_desc_array_phys;
ret = dmaengine_slave_config(chan, &config);
if (ret)
return ret;

snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

return 0;
}
EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);

int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;

if (rtd && rtd->params && rtd->params->filter_data) {
unsigned long req = *(unsigned long *) rtd->params->filter_data;
DRCMR(req) = 0;
}

snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);

int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
int ret = 0;

switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
DCSR(prtd->dma_ch) = DCSR_RUN;
break;

case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
DCSR(prtd->dma_ch) &= ~DCSR_RUN;
break;

case SNDRV_PCM_TRIGGER_RESUME:
DCSR(prtd->dma_ch) |= DCSR_RUN;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
DCSR(prtd->dma_ch) |= DCSR_RUN;
break;

default:
ret = -EINVAL;
}

return ret;
return snd_dmaengine_pcm_trigger(substream, cmd);
}
EXPORT_SYMBOL(pxa2xx_pcm_trigger);

snd_pcm_uframes_t
pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *prtd = runtime->private_data;

dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);

if (x == runtime->buffer_size)
x = 0;
return x;
return snd_dmaengine_pcm_pointer(substream);
}
EXPORT_SYMBOL(pxa2xx_pcm_pointer);

int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
{
struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
unsigned long req;

if (!prtd || !prtd->params)
return 0;

if (prtd->dma_ch == -1)
return -EINVAL;

DCSR(prtd->dma_ch) &= ~DCSR_RUN;
DCSR(prtd->dma_ch) = 0;
DCMD(prtd->dma_ch) = 0;
req = *(unsigned long *) prtd->params->filter_data;
DRCMR(req) = prtd->dma_ch | DRCMR_MAPVLD;

return 0;
}
EXPORT_SYMBOL(__pxa2xx_pcm_prepare);

void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
int dcsr;

dcsr = DCSR(dma_ch);
DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;

if (dcsr & DCSR_ENDINTR) {
snd_pcm_period_elapsed(substream);
} else {
printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
dma_ch, dcsr);
snd_pcm_stop_xrun(substream);
}
}
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);

int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd;
struct snd_dmaengine_dai_dma_data *dma_params;
int ret;

runtime->hw = pxa2xx_pcm_hardware;

dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
if (!dma_params)
return 0;

/*
* For mysterious reasons (and despite what the manual says)
* playback samples are lost if the DMA count is not a multiple
Expand All @@ -221,48 +113,27 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
if (ret)
goto out;
return ret;

ret = snd_pcm_hw_constraint_step(runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
if (ret)
goto out;
return ret;

ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
goto out;

ret = -ENOMEM;
rtd = kzalloc(sizeof(*rtd), GFP_KERNEL);
if (!rtd)
goto out;
rtd->dma_desc_array =
dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
&rtd->dma_desc_array_phys, GFP_KERNEL);
if (!rtd->dma_desc_array)
goto err1;
return ret;

rtd->dma_ch = -1;
runtime->private_data = rtd;
return 0;

err1:
kfree(rtd);
out:
return ret;
return snd_dmaengine_pcm_open_request_chan(substream,
pxad_filter_fn,
dma_params->filter_data);
}
EXPORT_SYMBOL(__pxa2xx_pcm_open);

int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct pxa2xx_runtime_data *rtd = runtime->private_data;

dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
rtd->dma_desc_array, rtd->dma_desc_array_phys);
kfree(rtd);
return 0;
return snd_dmaengine_pcm_close_release_chan(substream);
}
EXPORT_SYMBOL(__pxa2xx_pcm_close);

Expand Down
12 changes: 3 additions & 9 deletions sound/arm/pxa2xx-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,13 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)

rtd->params = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
client->playback_params : client->capture_params;
ret = pxa_request_dma("dma", DMA_PRIO_LOW,
pxa2xx_pcm_dma_irq, substream);
if (ret < 0)
goto err2;
rtd->dma_ch = ret;

ret = client->startup(substream);
if (!ret)
goto out;
goto err2;

return 0;

pxa_free_dma(rtd->dma_ch);
err2:
__pxa2xx_pcm_close(substream);
out:
Expand All @@ -66,9 +62,7 @@ static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
{
struct pxa2xx_pcm_client *client = substream->private_data;
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;

pxa_free_dma(rtd->dma_ch);
client->shutdown(substream);

return __pxa2xx_pcm_close(substream);
Expand Down
2 changes: 0 additions & 2 deletions sound/arm/pxa2xx-pcm.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
struct pxa2xx_runtime_data {
int dma_ch;
struct snd_dmaengine_dai_dma_data *params;
struct pxa_dma_desc *dma_desc_array;
dma_addr_t dma_desc_array_phys;
};

struct pxa2xx_pcm_client {
Expand Down
Loading

0 comments on commit 58ceb57

Please sign in to comment.