Commit d45a26bd authored by Mark Brown's avatar Mark Brown

Merge remote-tracking branch 'asoc/topic/dma' into asoc-next

parents 8ef53f68 22f38f79
......@@ -16,6 +16,7 @@
#define __SOUND_DMAENGINE_PCM_H__
#include <sound/pcm.h>
#include <sound/soc.h>
#include <linux/dmaengine.h>
/**
......@@ -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);
......@@ -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
......@@ -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);
......
......@@ -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"
......
......@@ -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/
......
......@@ -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))
......@@ -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,
......@@ -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");
......@@ -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;
......@@ -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);
......@@ -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,
......
......@@ -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)
......
......@@ -23,7 +23,6 @@
#include <sound/soc.h>
#include <linux/platform_data/dma-ep93xx.h>
#include "ep93xx-pcm.h"
/*
* Per channel (1-4) registers.
......@@ -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,
......@@ -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;
......
......@@ -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
......@@ -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,
},
};
......@@ -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;
}
......@@ -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)
......
......@@ -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 |
......@@ -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,
......@@ -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,
......
/*
* sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
* Copyright (C) 2006 Applied Data Systems
*
* 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 _EP93XX_SND_SOC_PCM_H
#define _EP93XX_SND_SOC_PCM_H
struct ep93xx_pcm_dma_params {
char *name;
int dma_port;
};
#endif /* _EP93XX_SND_SOC_PCM_H */
......@@ -21,8 +21,6 @@
#include <asm/mach-types.h>
#include <mach/hardware.h>
#include "ep93xx-pcm.h"
static struct snd_soc_dai_link simone_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
......
......@@ -21,7 +21,6 @@
#include <mach/hardware.h>
#include "../codecs/tlv320aic23.h"
#include "ep93xx-pcm.h"
#define CODEC_CLOCK 5644800
......
......@@ -118,7 +118,7 @@ config SND_SOC_IMX_PCM_FIQ
config SND_SOC_IMX_PCM_DMA
bool
select SND_SOC_DMAENGINE_PCM
select SND_SOC_GENERIC_DMAENGINE_PCM
select SND_SOC_IMX_PCM
config SND_SOC_IMX_AUDMUX
......
......@@ -27,6 +27,7 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "fsl_ssi.h"
#include "imx-pcm.h"
......@@ -122,8 +123,10 @@ struct fsl_ssi_private {
bool ssi_on_imx;
struct clk *clk;
struct platform_device *imx_pcm_pdev;
struct imx_pcm_dma_params dma_params_tx;
struct imx_pcm_dma_params dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct imx_dma_data filter_data_tx;
struct imx_dma_data filter_data_rx;
struct {
unsigned int rfrc;
......@@ -422,12 +425,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
ssi_private->second_stream = substream;
}
if (ssi_private->ssi_on_imx)
snd_soc_dai_set_dma_data(dai, substream,
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
&ssi_private->dma_params_tx :
&ssi_private->dma_params_rx);
return 0;
}
......@@ -549,6 +546,18 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
}
}
static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
{
struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
if (ssi_private->ssi_on_imx) {
dai->playback_dma_data = &ssi_private->dma_params_tx;
dai->capture_dma_data = &ssi_private->dma_params_rx;
}
return 0;
}
static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
.startup = fsl_ssi_startup,
.hw_params = fsl_ssi_hw_params,
......@@ -558,6 +567,7 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
/* Template for the CPU dai driver structure */
static struct snd_soc_dai_driver fsl_ssi_dai_template = {
.probe = fsl_ssi_dai_probe,
.playback = {
/* The SSI does not support monaural audio. */
.channels_min = 2,
......@@ -649,6 +659,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
const uint32_t *iprop;
struct resource res;
char name[64];
bool shared;
/* SSIs that are not connected on the board should have a
* status = "disabled"
......@@ -737,14 +748,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
* We have burstsize be "fifo_depth - 2" to match the SSI
* watermark setting in fsl_ssi_startup().
*/
ssi_private->dma_params_tx.burstsize =
ssi_private->dma_params_tx.maxburst =
ssi_private->fifo_depth - 2;
ssi_private->dma_params_rx.burstsize =
ssi_private->dma_params_rx.maxburst =
ssi_private->fifo_depth - 2;
ssi_private->dma_params_tx.dma_addr =
ssi_private->dma_params_tx.addr =
ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
ssi_private->dma_params_rx.dma_addr =
ssi_private->dma_params_rx.addr =
ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
ssi_private->dma_params_tx.filter_data =
&ssi_private->filter_data_tx;
ssi_private->dma_params_rx.filter_data =
&ssi_private->filter_data_rx;
/*
* TODO: This is a temporary solution and should be changed
* to use generic DMA binding later when the helplers get in.
......@@ -755,14 +770,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "could not get dma events\n");
goto error_clk;
}
ssi_private->dma_params_tx.dma = dma_events[0];
ssi_private->dma_params_rx.dma = dma_events[1];
ssi_private->dma_params_tx.shared_peripheral =
of_device_is_compatible(of_get_parent(np),
"fsl,spba-bus");
ssi_private->dma_params_rx.shared_peripheral =
ssi_private->dma_params_tx.shared_peripheral;
shared = of_device_is_compatible(of_get_parent(np),
"fsl,spba-bus");
imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
dma_events[0], shared);
imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
dma_events[1], shared);
}
/* Initialize the the device_attribute structure */
......
......@@ -11,74 +11,30 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/types.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <linux/platform_data/dma-imx.h>
#include "imx-pcm.h"
static bool filter(struct dma_chan *chan, void *param)
{
struct snd_dmaengine_dai_dma_data *dma_data = param;
if (!imx_dma_is_general_purpose(chan))
return false;
chan->private = param;
chan->private = dma_data->filter_data;
return true;
}
static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct imx_pcm_dma_params *dma_params;
struct dma_slave_config slave_config;
int ret;
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
if (ret)
return ret;
slave_config.device_fc = false;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config.dst_addr = dma_params->dma_addr;
slave_config.dst_maxburst = dma_params->burstsize;
} else {
slave_config.src_addr = dma_params->dma_addr;
slave_config.src_maxburst = dma_params->burstsize;
}
ret = dmaengine_slave_config(chan, &slave_config);
if (ret)
return ret;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
return 0;
}
static struct snd_pcm_hardware snd_imx_hardware = {
static const struct snd_pcm_hardware imx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
......@@ -97,64 +53,22 @@ static struct snd_pcm_hardware snd_imx_hardware = {
.fifo_size = 0,
};
static int snd_imx_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct imx_pcm_dma_params *dma_params;
struct imx_dma_data *dma_data;
int ret;
snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
if (!dma_data)
return -ENOMEM;
dma_data->peripheral_type = dma_params->shared_peripheral ?
IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
dma_data->priority = DMA_PRIO_HIGH;
dma_data->dma_request = dma_params->dma;
ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
if (ret) {
kfree(dma_data);
return ret;
}
snd_dmaengine_pcm_set_data(substream, dma_data);
return 0;
}
static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
.pcm_hardware = &imx_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = filter,
.prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
};
static int snd_imx_close(struct snd_pcm_substream *substream)
int imx_pcm_dma_init(struct platform_device *pdev)
{
struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
snd_dmaengine_pcm_close(substream);
kfree(dma_data);
return 0;
return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
static struct snd_pcm_ops imx_pcm_ops = {
.open = snd_imx_open,
.close = snd_imx_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_imx_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer_no_residue,
.mmap = snd_imx_pcm_mmap,
};
static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
.ops = &imx_pcm_ops,
.pcm_new = imx_pcm_new,
.pcm_free = imx_pcm_free,
};
int imx_pcm_dma_init(struct platform_device *pdev)
void imx_pcm_dma_exit(struct platform_device *pdev)
{
return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
snd_dmaengine_pcm_unregister(&pdev->dev);
}
......@@ -299,8 +299,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
imx_ssi_fiq_base = (unsigned long)ssi->base;
ssi->dma_params_tx.burstsize = 4;
ssi->dma_params_rx.burstsize = 6;
ssi->dma_params_tx.maxburst = 4;
ssi->dma_params_rx.maxburst = 6;
ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
if (ret)
......
......@@ -114,7 +114,11 @@ static int imx_pcm_probe(struct platform_device *pdev)
static int imx_pcm_remove(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
snd_soc_unregister_platform(&pdev->dev);
else
imx_pcm_dma_exit(pdev);
return 0;
}
......
......@@ -13,17 +13,24 @@
#ifndef _IMX_PCM_H
#define _IMX_PCM_H
#include <linux/platform_data/dma-imx.h>
/*
* Do not change this as the FIQ handler depends on this size
*/
#define IMX_SSI_DMABUF_SIZE (64 * 1024)
struct imx_pcm_dma_params {
int dma;
unsigned long dma_addr;
int burstsize;
bool shared_peripheral; /* The peripheral is on SPBA bus */
};
static inline void
imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
int dma, bool shared)
{
dma_data->dma_request = dma;
dma_data->priority = DMA_PRIO_HIGH;
if (shared)
dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
else
dma_data->peripheral_type = IMX_DMATYPE_SSI;
}
int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma);
......@@ -32,11 +39,16 @@ void imx_pcm_free(struct snd_pcm *pcm);
#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
int imx_pcm_dma_init(struct platform_device *pdev);
void imx_pcm_dma_exit(struct platform_device *pdev);
#else
static inline int imx_pcm_dma_init(struct platform_device *pdev)
{
return -ENODEV;
}
static inline void imx_pcm_dma_exit(struct platform_device *pdev)
{
}
#endif
#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
......
......@@ -232,23 +232,6 @@ static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
return 0;
}
static int imx_ssi_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai)
{
struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
struct imx_pcm_dma_params *dma_data;
/* Tx/Rx config */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &ssi->dma_params_tx;
else
dma_data = &ssi->dma_params_rx;
snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
return 0;
}
/*
* Should only be called when port is inactive (i.e. SSIEN = 0),
* although can be called multiple times by upper layers.
......@@ -353,7 +336,6 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
}
static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
.startup = imx_ssi_startup,
.hw_params = imx_ssi_hw_params,
.set_fmt = imx_ssi_set_dai_fmt,
.set_clkdiv = imx_ssi_set_dai_clkdiv,
......@@ -369,10 +351,14 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
snd_soc_dai_set_drvdata(dai, ssi);
val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
writel(val, ssi->base + SSI_SFCSR);
/* Tx/Rx config */
dai->playback_dma_data = &ssi->dma_params_tx;
dai->capture_dma_data = &ssi->dma_params_rx;
return 0;
}
......@@ -575,19 +561,26 @@ static int imx_ssi_probe(struct platform_device *pdev)
writel(0x0, ssi->base + SSI_SIER);
ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0;
ssi->dma_params_tx.dma_addr = res->start + SSI_STX0;
ssi->dma_params_rx.addr = res->start + SSI_SRX0;
ssi->dma_params_tx.addr = res->start + SSI_STX0;
ssi->dma_params_tx.maxburst = 6;
ssi->dma_params_rx.maxburst = 4;
ssi->dma_params_tx.burstsize = 6;
ssi->dma_params_rx.burstsize = 4;
ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
if (res)
ssi->dma_params_tx.dma = res->start;
if (res) {
imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
false);
}
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
if (res)
ssi->dma_params_rx.dma = res->start;
if (res) {
imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
false);
}
platform_set_drvdata(pdev, ssi);
......
......@@ -187,6 +187,7 @@
#include <linux/dmaengine.h>
#include <linux/platform_data/dma-imx.h>
#include <sound/dmaengine_pcm.h>
#include "imx-pcm.h"
struct imx_ssi {
......@@ -204,8 +205,10 @@ struct imx_ssi {
void (*ac97_reset) (struct snd_ac97 *ac97);
void (*ac97_warm_reset)(struct snd_ac97 *ac97);
struct imx_pcm_dma_params dma_params_rx;
struct imx_pcm_dma_params dma_params_tx;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct imx_dma_data filter_data_tx;
struct imx_dma_data filter_data_rx;
int enabled;
......
......@@ -28,7 +28,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/fsl/mxs-dma.h>
#include <sound/core.h>
#include <sound/initval.h>
......@@ -39,11 +38,6 @@
#include "mxs-pcm.h"
struct mxs_pcm_dma_data {
struct mxs_dma_data dma_data;
struct mxs_pcm_dma_params *dma_params;
};
static struct snd_pcm_hardware snd_mxs_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
......@@ -66,8 +60,7 @@ static struct snd_pcm_hardware snd_mxs_hardware = {
static bool filter(struct dma_chan *chan, void *param)
{
struct mxs_pcm_dma_data *pcm_dma_data = param;
struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
struct mxs_pcm_dma_params *dma_params = param;
if (!mxs_dma_is_apbx(chan))
return false;
......@@ -75,7 +68,7 @@ static bool filter(struct dma_chan *chan, void *param)
if (chan->chan_id != dma_params->chan_num)
return false;
chan->private = &pcm_dma_data->dma_data;
chan->private = &dma_params->dma_data;
return true;
}
......@@ -91,37 +84,11 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
static int snd_mxs_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct mxs_pcm_dma_data *pcm_dma_data;
int ret;
pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
if (pcm_dma_data == NULL)
return -ENOMEM;
pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
if (ret) {
kfree(pcm_dma_data);
return ret;
}
snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
snd_dmaengine_pcm_set_data(substream, pcm_dma_data);
return 0;
}
static int snd_mxs_close(struct snd_pcm_substream *substream)
{
struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
snd_dmaengine_pcm_close(substream);
kfree(pcm_dma_data);
return 0;
return snd_dmaengine_pcm_open_request_chan(substream, filter,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
}
static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
......@@ -137,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops mxs_pcm_ops = {
.open = snd_mxs_open,
.close = snd_mxs_close,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_mxs_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger,
......
......@@ -19,8 +19,10 @@
#ifndef _MXS_PCM_H
#define _MXS_PCM_H
#include <linux/fsl/mxs-dma.h>
struct mxs_pcm_dma_params {
int chan_irq;
struct mxs_dma_data dma_data;
int chan_num;
};
......
......@@ -753,9 +753,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
return ret;
}
saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
if (saif->dma_param.chan_irq < 0) {
ret = saif->dma_param.chan_irq;
saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
if (saif->dma_param.dma_data.chan_irq < 0) {
ret = saif->dma_param.dma_data.chan_irq;
dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
ret);
return ret;
......
......@@ -28,7 +28,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/tlv320aic23.h"
......
......@@ -36,7 +36,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/cx20442.h"
......
......@@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
return -ENODEV;
}
/* RX DMA request number, and port address configuration */
mcbsp->dma_data[1].name = "Audio Capture";
mcbsp->dma_data[1].dma_req = res->start;
mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
mcbsp->dma_req[1] = res->start;
mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
mcbsp->dma_data[1].maxburst = 4;
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
if (!res) {
......@@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
return -ENODEV;
}
/* TX DMA request number, and port address configuration */
mcbsp->dma_data[0].name = "Audio Playback";
mcbsp->dma_data[0].dma_req = res->start;
mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
mcbsp->dma_req[0] = res->start;
mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
mcbsp->dma_data[0].maxburst = 4;
mcbsp->fclk = clk_get(&pdev->dev, "fck");
if (IS_ERR(mcbsp->fclk)) {
......
......@@ -24,14 +24,14 @@
#ifndef __ASOC_MCBSP_H
#define __ASOC_MCBSP_H
#include "omap-pcm.h"
#ifdef CONFIG_ARCH_OMAP1
#define mcbsp_omap1() 1
#else
#define mcbsp_omap1() 0
#endif
#include <sound/dmaengine_pcm.h>
/* McBSP register numbers. Register address offset = num * reg_step */
enum {
/* Common registers */
......@@ -312,7 +312,8 @@ struct omap_mcbsp {
struct omap_mcbsp_platform_data *pdata;
struct omap_mcbsp_st_data *st_data;
struct omap_mcbsp_reg_cfg cfg_regs;
struct omap_pcm_dma_data dma_data[2];
struct snd_dmaengine_dai_dma_data dma_data[2];
unsigned int dma_req[2];
int dma_op_mode;
u16 max_tx_thres;
u16 max_rx_thres;
......
......@@ -34,7 +34,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#define N810_HEADSET_AMP_GPIO 10
#define N810_SPEAKER_AMP_GPIO 101
......
......@@ -34,7 +34,6 @@
#include "omap-dmic.h"
#include "omap-mcpdm.h"
#include "omap-pcm.h"
#include "../codecs/twl6040.h"
struct abe_twl6040 {
......
......@@ -39,8 +39,8 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "omap-pcm.h"
#include "omap-dmic.h"
struct omap_dmic {
......@@ -55,13 +55,9 @@ struct omap_dmic {
u32 ch_enabled;
bool active;
struct mutex mutex;
};
/*
* Stream DMA parameters
*/
static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
.name = "DMIC capture",
struct snd_dmaengine_dai_dma_data dma_data;
unsigned int dma_req;
};
static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
......@@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
mutex_unlock(&dmic->mutex);
snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params);
snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
return ret;
}
......@@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
struct omap_pcm_dma_data *dma_data;
struct snd_dmaengine_dai_dma_data *dma_data;
int channels;
dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
......@@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
/* packet size is threshold * channels */
dma_data = snd_soc_dai_get_dma_data(dai, substream);
dma_data->packet_size = dmic->threshold * channels;
dma_data->maxburst = dmic->threshold * channels;
return 0;
}
......@@ -476,7 +472,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_put_clk;
}
omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG;
dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
......@@ -484,7 +480,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_put_clk;
}
omap_dmic_dai_dma_params.dma_req = res->start;
dmic->dma_req = res->start;
dmic->dma_data.filter_data = &dmic->dma_req;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (!res) {
......@@ -493,19 +491,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
goto err_put_clk;
}
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), pdev->name)) {
dev_err(dmic->dev, "memory region already claimed\n");
ret = -ENODEV;
goto err_put_clk;
}
dmic->io_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!dmic->io_base) {
ret = -ENOMEM;
goto err_put_clk;
}
dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dmic->io_base))
return PTR_ERR(dmic->io_base);
ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
if (ret)
......
......@@ -32,15 +32,16 @@
#include <sound/soc.h>
#include <sound/asound.h>
#include <sound/asoundef.h>
#include <sound/dmaengine_pcm.h>
#include <video/omapdss.h>
#include "omap-pcm.h"
#include "omap-hdmi.h"
#define DRV_NAME "omap-hdmi-audio-dai"
struct hdmi_priv {
struct omap_pcm_dma_data dma_params;
struct snd_dmaengine_dai_dma_data dma_data;
unsigned int dma_req;
struct omap_dss_audio dss_audio;
struct snd_aes_iec958 iec;
struct snd_cea_861_aud_if cea;
......@@ -68,7 +69,7 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
return -ENODEV;
}
snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params);
snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
return 0;
}
......@@ -88,25 +89,20 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
struct snd_aes_iec958 *iec = &priv->iec;
struct snd_cea_861_aud_if *cea = &priv->cea;
struct omap_pcm_dma_data *dma_data;
int err = 0;
dma_data = snd_soc_dai_get_dma_data(dai, substream);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
dma_data->packet_size = 16;
priv->dma_data.maxburst = 16;
break;
case SNDRV_PCM_FORMAT_S24_LE:
dma_data->packet_size = 32;
priv->dma_data.maxburst = 32;
break;
default:
dev_err(dai->dev, "format not supported!\n");
return -EINVAL;
}
dma_data->data_type = 32;
/*
* fill the IEC-60958 channel status word
*/
......@@ -283,8 +279,7 @@ static int omap_hdmi_probe(struct platform_device *pdev)
return -ENODEV;
}
hdmi_data->dma_params.port_addr = hdmi_rsrc->start
+ OMAP_HDMI_AUDIO_DMA_PORT;
hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!hdmi_rsrc) {
......@@ -292,8 +287,9 @@ static int omap_hdmi_probe(struct platform_device *pdev)
return -ENODEV;
}
hdmi_data->dma_params.dma_req = hdmi_rsrc->start;
hdmi_data->dma_params.name = "HDMI playback";
hdmi_data->dma_req = hdmi_rsrc->start;
hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
/*
* TODO: We assume that there is only one DSS HDMI device. Future
......
......@@ -33,11 +33,11 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "mcbsp.h"
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
......@@ -62,24 +62,22 @@ enum {
* Stream DMA parameters. DMA request line and port address are set runtime
* since they are different between OMAP1 and later OMAPs
*/
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
unsigned int packet_size)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_pcm_dma_data *dma_data;
int words;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
/*
* Configure McBSP threshold based on either:
* packet_size, when the sDMA is in packet mode, or based on the
* period size in THRESHOLD mode, otherwise use McBSP threshold = 1
* for mono streams.
*/
if (dma_data->packet_size)
words = dma_data->packet_size;
if (packet_size)
words = packet_size;
else
words = 1;
......@@ -226,7 +224,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
{
struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
struct omap_pcm_dma_data *dma_data;
struct snd_dmaengine_dai_dma_data *dma_data;
int wlen, channels, wpf;
int pkt_size = 0;
unsigned int format, div, framesize, master;
......@@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
if (mcbsp->pdata->buffer_size) {
dma_data->set_threshold = omap_mcbsp_set_threshold;
if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
int period_words, max_thrsh;
int divider = 0;
......@@ -276,9 +273,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
/* Use packet mode for non mono streams */
pkt_size = channels;
}
omap_mcbsp_set_threshold(substream, pkt_size);
}
dma_data->packet_size = pkt_size;
dma_data->maxburst = pkt_size;
if (mcbsp->configured) {
/* McBSP already configured by another stream */
......
......@@ -39,11 +39,14 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "omap-mcpdm.h"
#include "omap-pcm.h"
#define OMAP44XX_MCPDM_L3_BASE 0x49032000
struct mcpdm_link_config {
u32 link_mask; /* channel mask for the direction */
u32 threshold; /* FIFO threshold */
};
struct omap_mcpdm {
struct device *dev;
......@@ -53,29 +56,22 @@ struct omap_mcpdm {
struct mutex mutex;
/* channel data */
u32 dn_channels;
u32 up_channels;
/* McPDM FIFO thresholds */
u32 dn_threshold;
u32 up_threshold;
/* Playback/Capture configuration */
struct mcpdm_link_config config[2];
/* McPDM dn offsets for rx1, and 2 channels */
u32 dn_rx_offset;
/* McPDM needs to be restarted due to runtime reconfiguration */
bool restart;
struct snd_dmaengine_dai_dma_data dma_data[2];
unsigned int dma_req[2];
};
/*
* Stream DMA parameters
*/
static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
{
.name = "Audio playback",
},
{
.name = "Audio capture",
},
};
static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
{
......@@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
{
u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl |= mcpdm->dn_channels | mcpdm->up_channels;
ctrl |= link_mask;
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
......@@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
{
u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels);
ctrl &= ~(link_mask);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
......@@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
}
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold);
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold);
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
......@@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
mutex_unlock(&mcpdm->mutex);
snd_soc_dai_set_dma_data(dai, substream,
&omap_mcpdm_dai_dma_params[substream->stream]);
&mcpdm->dma_data[substream->stream]);
return 0;
}
......@@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
if (omap_mcpdm_active(mcpdm)) {
omap_mcpdm_stop(mcpdm);
omap_mcpdm_close_streams(mcpdm);
mcpdm->config[0].link_mask = 0;
mcpdm->config[1].link_mask = 0;
}
}
......@@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
{
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
int stream = substream->stream;
struct omap_pcm_dma_data *dma_data;
struct snd_dmaengine_dai_dma_data *dma_data;
u32 threshold;
int channels;
int link_mask = 0;
......@@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
dma_data = snd_soc_dai_get_dma_data(dai, substream);
threshold = mcpdm->config[stream].threshold;
/* Configure McPDM channels, and DMA packet size */
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
mcpdm->dn_channels = link_mask << 3;
dma_data->packet_size =
(MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels;
link_mask <<= 3;
/* If capture is not running assume a stereo stream to come */
if (!mcpdm->config[!stream].link_mask)
mcpdm->config[!stream].link_mask = 0x3;
dma_data->maxburst =
(MCPDM_DN_THRES_MAX - threshold) * channels;
} else {
mcpdm->up_channels = link_mask << 0;
dma_data->packet_size = mcpdm->up_threshold * channels;
/* If playback is not running assume a stereo stream to come */
if (!mcpdm->config[!stream].link_mask)
mcpdm->config[!stream].link_mask = (0x3 << 3);
dma_data->maxburst = threshold * channels;
}
/* Check if we need to restart McPDM with this stream */
if (mcpdm->config[stream].link_mask &&
mcpdm->config[stream].link_mask != link_mask)
mcpdm->restart = true;
mcpdm->config[stream].link_mask = link_mask;
return 0;
}
......@@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
if (!omap_mcpdm_active(mcpdm)) {
omap_mcpdm_start(mcpdm);
omap_mcpdm_reg_dump(mcpdm);
} else if (mcpdm->restart) {
omap_mcpdm_stop(mcpdm);
omap_mcpdm_start(mcpdm);
mcpdm->restart = false;
omap_mcpdm_reg_dump(mcpdm);
}
return 0;
......@@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
pm_runtime_get_sync(mcpdm->dev);
omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler,
ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
0, "McPDM", (void *)mcpdm);
pm_runtime_put_sync(mcpdm->dev);
......@@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
}
/* Configure McPDM threshold values */
mcpdm->dn_threshold = 2;
mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3;
mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
MCPDM_UP_THRES_MAX - 3;
return ret;
}
......@@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
{
struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
free_irq(mcpdm->irq, (void *)mcpdm);
pm_runtime_disable(mcpdm->dev);
return 0;
......@@ -446,33 +470,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
if (res == NULL)
return -ENOMEM;
omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA;
omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA;
mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
if (!res)
return -ENODEV;
omap_mcpdm_dai_dma_params[0].dma_req = res->start;
mcpdm->dma_req[0] = res->start;
mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
if (!res)
return -ENODEV;
omap_mcpdm_dai_dma_params[1].dma_req = res->start;
mcpdm->dma_req[1] = res->start;
mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
if (res == NULL)
return -ENOMEM;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), "McPDM"))
return -EBUSY;
mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
if (!mcpdm->io_base)
return -ENOMEM;
mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mcpdm->io_base))
return PTR_ERR(mcpdm->io_base);
mcpdm->irq = platform_get_irq(pdev, 0);
if (mcpdm->irq < 0)
......
......@@ -32,8 +32,6 @@
#include <sound/dmaengine_pcm.h>
#include <sound/soc.h>
#include "omap-pcm.h"
#ifdef CONFIG_ARCH_OMAP1
#define pcm_omap1510() cpu_is_omap1510()
#else
......@@ -56,25 +54,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
.buffer_bytes_max = 128 * 1024,
};
static int omap_pcm_get_dma_buswidth(int num_bits)
{
int buswidth;
switch (num_bits) {
case 16:
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
break;
case 32:
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
break;
default:
buswidth = -EINVAL;
break;
}
return buswidth;
}
/* this may get called several times by oss emulation */
static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
......@@ -105,20 +84,9 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
if (err)
return err;
/* Override the *_dma addr_width if requested by the DAI driver */
if (dma_data->data_type) {
int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
config.dst_addr_width = buswidth;
else
config.src_addr_width = buswidth;
}
config.src_addr = dma_data->port_addr;
config.dst_addr = dma_data->port_addr;
config.src_maxburst = dma_data->packet_size;
config.dst_maxburst = dma_data->packet_size;
snd_dmaengine_pcm_set_config_from_dai_data(substream,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
&config);
return dmaengine_slave_config(chan, &config);
}
......@@ -129,37 +97,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
return 0;
}
static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_pcm_dma_data *dma_data;
int ret = 0;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* Configure McBSP internal buffer usage */
if (dma_data->set_threshold)
dma_data->set_threshold(substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
break;
default:
ret = -EINVAL;
}
if (ret == 0)
ret = snd_dmaengine_pcm_trigger(substream, cmd);
return ret;
}
static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
{
snd_pcm_uframes_t offset;
......@@ -175,20 +112,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
static int omap_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct omap_pcm_dma_data *dma_data;
struct snd_dmaengine_dai_dma_data *dma_data;
snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn,
&dma_data->dma_req);
}
static int omap_pcm_close(struct snd_pcm_substream *substream)
{
snd_dmaengine_pcm_close(substream);
return 0;
return snd_dmaengine_pcm_open_request_chan(substream,
omap_dma_filter_fn,
dma_data->filter_data);
}
static int omap_pcm_mmap(struct snd_pcm_substream *substream,
......@@ -204,11 +136,11 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops omap_pcm_ops = {
.open = omap_pcm_open,
.close = omap_pcm_close,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = omap_pcm_hw_params,
.hw_free = omap_pcm_hw_free,
.trigger = omap_pcm_trigger,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = omap_pcm_pointer,
.mmap = omap_pcm_mmap,
};
......
/*
* omap-pcm.h
*
* Copyright (C) 2008 Nokia Corporation
*
* Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
* Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* 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.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#ifndef __OMAP_PCM_H__
#define __OMAP_PCM_H__
struct snd_pcm_substream;
struct omap_pcm_dma_data {
char *name; /* stream identifier */
int dma_req; /* DMA request line */
unsigned long port_addr; /* transmit/receive register */
void (*set_threshold)(struct snd_pcm_substream *substream);
int data_type; /* 8, 16, 32 (bits) or 0 to let omap-pcm
* to decide the sDMA data type */
int packet_size; /* packet size only in PACKET mode */
};
#endif
......@@ -43,7 +43,6 @@
#include <sound/jack.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
struct omap_twl4030 {
int jack_detect; /* board can detect jack events */
......
......@@ -34,7 +34,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#define OMAP3_PANDORA_DAC_POWER_GPIO 118
#define OMAP3_PANDORA_AMP_POWER_GPIO 14
......@@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
int ret;
/*
* The PCM1773 DAC datasheet requires 1ms delay between switching
* VCC power on/off and /PD pin high/low
*/
if (SND_SOC_DAPM_EVENT_ON(event)) {
regulator_enable(omap3pandora_dac_reg);
ret = regulator_enable(omap3pandora_dac_reg);
if (ret) {
dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
return ret;
}
mdelay(1);
gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
} else {
......
......@@ -33,7 +33,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#include "../codecs/tlv320aic23.h"
#define CODEC_CLOCK 12000000
......
......@@ -37,7 +37,6 @@
#include <asm/mach-types.h>
#include "omap-mcbsp.h"
#include "omap-pcm.h"
#define RX51_TVOUT_SEL_GPIO 40
#define RX51_JACK_DETECT_GPIO 177
......
......@@ -118,9 +118,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct platform_device *pdev = to_platform_device(rtd->platform->dev);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct mmp_dma_data *dma_data;
struct mmp_dma_data dma_data;
struct resource *r;
int ret;
r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
if (!r)
......@@ -128,33 +127,12 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
snd_soc_set_runtime_hwparams(substream,
&mmp_pcm_hardware[substream->stream]);
dma_data = devm_kzalloc(&pdev->dev,
sizeof(struct mmp_dma_data), GFP_KERNEL);
if (dma_data == NULL)
return -ENOMEM;
dma_data->dma_res = r;
dma_data->ssp_id = cpu_dai->id;
dma_data.dma_res = r;
dma_data.ssp_id = cpu_dai->id;
ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
if (ret) {
devm_kfree(&pdev->dev, dma_data);
return ret;
}
snd_dmaengine_pcm_set_data(substream, dma_data);
return 0;
}
static int mmp_pcm_close(struct snd_pcm_substream *substream)
{
struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct platform_device *pdev = to_platform_device(rtd->platform->dev);
snd_dmaengine_pcm_close(substream);
devm_kfree(&pdev->dev, dma_data);
return 0;
return snd_dmaengine_pcm_open_request_chan(substream, filter,
&dma_data);
}
static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
......@@ -171,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
struct snd_pcm_ops mmp_pcm_ops = {
.open = mmp_pcm_open,
.close = mmp_pcm_close,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = mmp_pcm_hw_params,
.trigger = snd_dmaengine_pcm_trigger,
......
......@@ -3903,21 +3903,14 @@ void snd_soc_unregister_dais(struct device *dev, size_t count)
EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
/**
* snd_soc_register_platform - Register a platform with the ASoC core
*
* @platform: platform to register
* snd_soc_add_platform - Add a platform to the ASoC core
* @dev: The parent device for the platform
* @platform: The platform to add
* @platform_driver: The driver for the platform
*/
int snd_soc_register_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)
{
struct snd_soc_platform *platform;
dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
if (platform == NULL)
return -ENOMEM;
/* create platform component name */
platform->name = fmt_single_name(dev, &platform->id);
if (platform->name == NULL) {
......@@ -3940,30 +3933,76 @@ int snd_soc_register_platform(struct device *dev,
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_register_platform);
EXPORT_SYMBOL_GPL(snd_soc_add_platform);
/**
* snd_soc_unregister_platform - Unregister a platform from the ASoC core
* snd_soc_register_platform - Register a platform with the ASoC core
*
* @platform: platform to unregister
* @platform: platform to register
*/
void snd_soc_unregister_platform(struct device *dev)
int snd_soc_register_platform(struct device *dev,
const struct snd_soc_platform_driver *platform_drv)
{
struct snd_soc_platform *platform;
int ret;
list_for_each_entry(platform, &platform_list, list) {
if (dev == platform->dev)
goto found;
}
return;
dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
found:
platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
if (platform == NULL)
return -ENOMEM;
ret = snd_soc_add_platform(dev, platform, platform_drv);
if (ret)
kfree(platform);
return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_register_platform);
/**
* snd_soc_remove_platform - Remove a platform from the ASoC core
* @platform: the platform to remove
*/
void snd_soc_remove_platform(struct snd_soc_platform *platform)
{
mutex_lock(&client_mutex);
list_del(&platform->list);
mutex_unlock(&client_mutex);
dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name);
dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
platform->name);
kfree(platform->name);
}
EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
{
struct snd_soc_platform *platform;
list_for_each_entry(platform, &platform_list, list) {
if (dev == platform->dev)
return platform;
}
return NULL;
}
EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
/**
* snd_soc_unregister_platform - Unregister a platform from the ASoC core
*
* @platform: platform to unregister
*/
void snd_soc_unregister_platform(struct device *dev)
{
struct snd_soc_platform *platform;
platform = snd_soc_lookup_platform(dev);
if (!platform)
return;
snd_soc_remove_platform(platform);
kfree(platform);
}
EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
......
......@@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data {
dma_cookie_t cookie;
unsigned int pos;
void *data;
};
static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
......@@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
return substream->runtime->private_data;
}
/**
* snd_dmaengine_pcm_set_data - Set dmaengine substream private data
* @substream: PCM substream
* @data: Data to set
*/
void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
prtd->data = data;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
/**
* snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
* @substream: PCM substream
*
* Returns the data previously set with snd_dmaengine_pcm_set_data
*/
void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
return prtd->data;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
......@@ -118,10 +89,49 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
slave_config->src_addr_width = buswidth;
}
slave_config->device_fc = false;
return 0;
}
EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
/**
* snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
* using DAI DMA data.
* @substream: PCM substream
* @dma_data: DAI DMA data
* @slave_config: DMA slave configuration
*
* Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
* slave_id fields of the DMA slave config from the same fields of the DAI DMA
* data struct. The src and dst fields will be initialized depending on the
* direction of the substream. If the substream is a playback stream the dst
* fields will be initialized, if it is a capture stream the src fields will be
* initialized. The {dst,src}_addr_width field will only be initialized if the
* addr_width field of the DAI DMA data struct is not equal to
* DMA_SLAVE_BUSWIDTH_UNDEFINED.
*/
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 *slave_config)
{
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config->dst_addr = dma_data->addr;
slave_config->dst_maxburst = dma_data->maxburst;
if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
slave_config->dst_addr_width = dma_data->addr_width;
} else {
slave_config->src_addr = dma_data->addr;
slave_config->src_maxburst = dma_data->maxburst;
if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
slave_config->src_addr_width = dma_data->addr_width;
}
slave_config->slave_id = dma_data->slave_id;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
static void dmaengine_pcm_dma_complete(void *arg)
{
struct snd_pcm_substream *substream = arg;
......@@ -244,44 +254,48 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd,
dma_filter_fn filter_fn, void *filter_data)
/**
* snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
* @filter_fn: Filter function used to request the DMA channel
* @filter_data: Data passed to the DMA filter function
*
* Returns NULL or the requested DMA channel.
*
* This function request a DMA channel for usage with dmaengine PCM.
*/
struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
void *filter_data)
{
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_set(DMA_CYCLIC, mask);
prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
if (!prtd->dma_chan)
return -ENXIO;
return 0;
return dma_request_channel(mask, filter_fn, filter_data);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
/**
* snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
* @substream: PCM substream
* @filter_fn: Filter function used to request the DMA channel
* @filter_data: Data passed to the DMA filter function
* @chan: DMA channel to use for data transfers
*
* Returns 0 on success, a negative error code otherwise.
*
* This function will request a DMA channel using the passed filter function and
* data. The function should usually be called from the pcm open callback.
*
* Note that this function will use private_data field of the substream's
* runtime. So it is not availabe to your pcm driver implementation. If you need
* to keep additional data attached to a substream use
* snd_dmaengine_pcm_{set,get}_data.
* The function should usually be called from the pcm open callback. Note that
* this function will use private_data field of the substream's runtime. So it
* is not availabe to your pcm driver implementation.
*/
int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data)
struct dma_chan *chan)
{
struct dmaengine_pcm_runtime_data *prtd;
int ret;
if (!chan)
return -ENXIO;
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
......@@ -291,11 +305,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
if (!prtd)
return -ENOMEM;
ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data);
if (ret < 0) {
kfree(prtd);
return ret;
}
prtd->dma_chan = chan;
substream->runtime->private_data = prtd;
......@@ -303,6 +313,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
/**
* snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
* @substream: PCM substream
* @filter_fn: Filter function used to request the DMA channel
* @filter_data: Data passed to the DMA filter function
*
* Returns 0 on success, a negative error code otherwise.
*
* This function will request a DMA channel using the passed filter function and
* data. The function should usually be called from the pcm open callback. Note
* that this function will use private_data field of the substream's runtime. So
* it is not availabe to your pcm driver implementation.
*/
int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
dma_filter_fn filter_fn, void *filter_data)
{
return snd_dmaengine_pcm_open(substream,
snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
/**
* snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
* @substream: PCM substream
......@@ -311,11 +342,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dma_release_channel(prtd->dma_chan);
kfree(prtd);
return 0;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
/**
* snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
* @substream: PCM substream
*
* Releases the DMA channel associated with the PCM substream.
*/
int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
{
struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
dma_release_channel(prtd->dma_chan);
return snd_dmaengine_pcm_close(substream);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
MODULE_LICENSE("GPL");
/*
* Copyright (C) 2013, Analog Devices Inc.
* Author: Lars-Peter Clausen <lars@metafoo.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/dmaengine.h>
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_dma.h>
#include <sound/dmaengine_pcm.h>
struct dmaengine_pcm {
struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1];
const struct snd_dmaengine_pcm_config *config;
struct snd_soc_platform platform;
bool compat;
};
static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
{
return container_of(p, struct dmaengine_pcm, platform);
}
/**
* snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
* @substream: PCM substream
* @params: hw_params
* @slave_config: DMA slave config to prepare
*
* This function can be used as a generic prepare_slave_config callback for
* platforms which make use of the snd_dmaengine_dai_dma_data struct for their
* DAI DMA data. Internally the function will first call
* snd_hwparams_to_dma_slave_config to fill in the slave config based on the
* hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
* remaining fields based on the DAI DMA data.
*/
int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_dmaengine_dai_dma_data *dma_data;
int ret;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
if (ret)
return ret;
snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data,
slave_config);
return 0;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config);
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 dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct dma_slave_config slave_config;
int ret;
if (pcm->config->prepare_slave_config) {
ret = pcm->config->prepare_slave_config(substream, params,
&slave_config);
if (ret)
return ret;
ret = dmaengine_slave_config(chan, &slave_config);
if (ret)
return ret;
}
return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
}
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 dma_chan *chan = pcm->chan[substream->stream];
int ret;
ret = snd_soc_set_runtime_hwparams(substream,
pcm->config->pcm_hardware);
if (ret)
return ret;
return snd_dmaengine_pcm_open(substream, chan);
}
static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
struct snd_pcm_substream *substream)
{
if (!pcm->chan[substream->stream])
return NULL;
return pcm->chan[substream->stream]->device->dev;
}
static void dmaengine_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
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);
if (pcm->config->compat_request_channel)
return pcm->config->compat_request_channel(rtd, substream);
return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn,
snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
}
static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
const struct snd_dmaengine_pcm_config *config = pcm->config;
struct snd_pcm_substream *substream;
unsigned int i;
int ret;
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
substream = rtd->pcm->streams[i].substream;
if (!substream)
continue;
if (!pcm->chan[i] && pcm->compat) {
pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
substream);
}
if (!pcm->chan[i]) {
dev_err(rtd->platform->dev,
"Missing dma channel for stream: %d\n", i);
ret = -EINVAL;
goto err_free;
}
ret = snd_pcm_lib_preallocate_pages(substream,
SNDRV_DMA_TYPE_DEV,
dmaengine_dma_dev(pcm, substream),
config->prealloc_buffer_size,
config->pcm_hardware->buffer_bytes_max);
if (ret)
goto err_free;
}
return 0;
err_free:
dmaengine_pcm_free(rtd->pcm);
return ret;
}
static const struct snd_pcm_ops dmaengine_pcm_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 = snd_dmaengine_pcm_pointer,
};
static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
.ops = &dmaengine_pcm_ops,
.pcm_new = dmaengine_pcm_new,
.pcm_free = dmaengine_pcm_free,
.probe_order = SND_SOC_COMP_ORDER_LATE,
};
static const struct snd_pcm_ops dmaengine_no_residue_pcm_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 = snd_dmaengine_pcm_pointer_no_residue,
};
static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = {
.ops = &dmaengine_no_residue_pcm_ops,
.pcm_new = dmaengine_pcm_new,
.pcm_free = dmaengine_pcm_free,
.probe_order = SND_SOC_COMP_ORDER_LATE,
};
static const char * const dmaengine_pcm_dma_channel_names[] = {
[SNDRV_PCM_STREAM_PLAYBACK] = "tx",
[SNDRV_PCM_STREAM_CAPTURE] = "rx",
};
/**
* snd_dmaengine_pcm_register - Register a dmaengine based PCM device
* @dev: The parent device for the PCM device
* @config: Platform specific PCM configuration
* @flags: Platform specific quirks
*/
int snd_dmaengine_pcm_register(struct device *dev,
const struct snd_dmaengine_pcm_config *config, unsigned int flags)
{
struct dmaengine_pcm *pcm;
unsigned int i;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (!pcm)
return -ENOMEM;
pcm->config = config;
if (flags & SND_DMAENGINE_PCM_FLAG_COMPAT)
pcm->compat = true;
if (!(flags & SND_DMAENGINE_PCM_FLAG_NO_DT) && dev->of_node) {
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
pcm->chan[i] = of_dma_request_slave_channel(dev->of_node,
dmaengine_pcm_dma_channel_names[i]);
}
}
if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
return snd_soc_add_platform(dev, &pcm->platform,
&dmaengine_no_residue_pcm_platform);
else
return snd_soc_add_platform(dev, &pcm->platform,
&dmaengine_pcm_platform);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
/**
* snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device
* @dev: Parent device the PCM was register with
*
* Removes a dmaengine based PCM device previously registered with
* snd_dmaengine_pcm_register.
*/
void snd_dmaengine_pcm_unregister(struct device *dev)
{
struct snd_soc_platform *platform;
struct dmaengine_pcm *pcm;
unsigned int i;
platform = snd_soc_lookup_platform(dev);
if (!platform)
return;
pcm = soc_platform_to_pcm(platform);
for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
if (pcm->chan[i])
dma_release_channel(pcm->chan[i]);
}
snd_soc_remove_platform(platform);
kfree(pcm);
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
MODULE_LICENSE("GPL");
......@@ -64,21 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream)
if (ret)
return ret;
ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data);
if (ret)
return ret;
snd_dmaengine_pcm_set_data(substream, dma_data);
return 0;
}
static int spear_pcm_close(struct snd_pcm_substream *substream)
{
snd_dmaengine_pcm_close(substream);
return 0;
return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
dma_data);
}
static int spear_pcm_mmap(struct snd_pcm_substream *substream,
......@@ -93,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
static struct snd_pcm_ops spear_pcm_ops = {
.open = spear_pcm_open,
.close = spear_pcm_close,
.close = snd_dmaengine_pcm_close_release_chan,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = spear_pcm_hw_params,
.hw_free = spear_pcm_hw_free,
......
......@@ -2,7 +2,7 @@ config SND_SOC_TEGRA
tristate "SoC Audio for the Tegra System-on-Chip"
depends on ARCH_TEGRA && TEGRA20_APB_DMA
select REGMAP_MMIO
select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA
select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
help
Say Y or M here if you want support for SoC audio on Tegra.
......
......@@ -35,6 +35,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "tegra_asoc_utils.h"
#include "tegra20_ac97.h"
......@@ -389,14 +390,14 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
}
ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
ac97->capture_dma_data.wrap = 4;
ac97->capture_dma_data.width = 32;
ac97->capture_dma_data.req_sel = of_dma[1];
ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->capture_dma_data.maxburst = 4;
ac97->capture_dma_data.slave_id = of_dma[1];
ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
ac97->playback_dma_data.wrap = 4;
ac97->playback_dma_data.width = 32;
ac97->playback_dma_data.req_sel = of_dma[1];
ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
ac97->capture_dma_data.maxburst = 4;
ac97->capture_dma_data.slave_id = of_dma[0];
ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
if (ret) {
......
......@@ -85,8 +85,8 @@
struct tegra20_ac97 {
struct clk *clk_ac97;
struct tegra_pcm_dma_params capture_dma_data;
struct tegra_pcm_dma_params playback_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
int reset_gpio;
int sync_gpio;
......
......@@ -41,6 +41,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "tegra20_i2s.h"
......@@ -403,14 +404,14 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
}
i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
i2s->capture_dma_data.wrap = 4;
i2s->capture_dma_data.width = 32;
i2s->capture_dma_data.req_sel = dma_ch;
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = 4;
i2s->capture_dma_data.slave_id = dma_ch;
i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
i2s->playback_dma_data.wrap = 4;
i2s->playback_dma_data.width = 32;
i2s->playback_dma_data.req_sel = dma_ch;
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = 4;
i2s->playback_dma_data.slave_id = dma_ch;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
......
......@@ -155,8 +155,8 @@
struct tegra20_i2s {
struct snd_soc_dai_driver dai;
struct clk *clk_i2s;
struct tegra_pcm_dma_params capture_dma_data;
struct tegra_pcm_dma_params playback_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
};
......
......@@ -32,6 +32,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "tegra20_spdif.h"
......@@ -318,9 +319,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
}
spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
spdif->playback_dma_data.wrap = 4;
spdif->playback_dma_data.width = 32;
spdif->playback_dma_data.req_sel = dmareq->start;
spdif->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
spdif->capture_dma_data.maxburst = 4;
spdif->playback_dma_data.slave_id = dmareq->start;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
......
......@@ -462,8 +462,8 @@
struct tegra20_spdif {
struct clk *clk_spdif_out;
struct tegra_pcm_dma_params capture_dma_data;
struct tegra_pcm_dma_params playback_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
};
......
......@@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
}
int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
unsigned long *fiforeg,
unsigned long *reqsel)
dma_addr_t *fiforeg,
unsigned int *reqsel)
{
int channel;
u32 reg, val;
......@@ -178,8 +178,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
unsigned long *fiforeg,
unsigned long *reqsel)
dma_addr_t *fiforeg,
unsigned int *reqsel)
{
int channel;
u32 reg, val;
......
......@@ -451,15 +451,15 @@ enum tegra30_ahub_rxcif {
};
extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
unsigned long *fiforeg,
unsigned long *reqsel);
dma_addr_t *fiforeg,
unsigned int *reqsel);
extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
unsigned long *fiforeg,
unsigned long *reqsel);
dma_addr_t *fiforeg,
unsigned int *reqsel);
extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
......
......@@ -38,6 +38,7 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
#include "tegra30_ahub.h"
#include "tegra30_i2s.h"
......@@ -80,17 +81,17 @@ static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
&i2s->playback_dma_data.addr,
&i2s->playback_dma_data.req_sel);
i2s->playback_dma_data.wrap = 4;
i2s->playback_dma_data.width = 32;
&i2s->playback_dma_data.slave_id);
i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->playback_dma_data.maxburst = 4;
tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
i2s->playback_fifo_cif);
} else {
ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
&i2s->capture_dma_data.addr,
&i2s->capture_dma_data.req_sel);
i2s->capture_dma_data.wrap = 4;
i2s->capture_dma_data.width = 32;
&i2s->capture_dma_data.slave_id);
i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
i2s->capture_dma_data.maxburst = 4;
tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
i2s->capture_i2s_cif);
}
......
......@@ -231,10 +231,10 @@ struct tegra30_i2s {
struct clk *clk_i2s;
enum tegra30_ahub_txcif capture_i2s_cif;
enum tegra30_ahub_rxcif capture_fifo_cif;
struct tegra_pcm_dma_params capture_dma_data;
struct snd_dmaengine_dai_dma_data capture_dma_data;
enum tegra30_ahub_rxcif playback_i2s_cif;
enum tegra30_ahub_txcif playback_fifo_cif;
struct tegra_pcm_dma_params playback_dma_data;
struct snd_dmaengine_dai_dma_data playback_dma_data;
struct regmap *regmap;
};
......
......@@ -29,9 +29,7 @@
*
*/
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
......@@ -55,191 +53,24 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
.fifo_size = 4,
};
static int tegra_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct device *dev = rtd->platform->dev;
int ret;
/* Set HW params now that initialization is complete */
snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
ret = snd_dmaengine_pcm_open(substream, NULL, NULL);
if (ret) {
dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
return ret;
}
return 0;
}
static int tegra_pcm_close(struct snd_pcm_substream *substream)
{
snd_dmaengine_pcm_close(substream);
return 0;
}
static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct device *dev = rtd->platform->dev;
struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
struct tegra_pcm_dma_params *dmap;
struct dma_slave_config slave_config;
int ret;
dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
ret = snd_hwparams_to_dma_slave_config(substream, params,
&slave_config);
if (ret) {
dev_err(dev, "hw params config failed with err %d\n", ret);
return ret;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.dst_addr = dmap->addr;
slave_config.dst_maxburst = 4;
} else {
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_config.src_addr = dmap->addr;
slave_config.src_maxburst = 4;
}
slave_config.slave_id = dmap->req_sel;
ret = dmaengine_slave_config(chan, &slave_config);
if (ret < 0) {
dev_err(dev, "dma slave config failed with err %d\n", ret);
return ret;
}
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
return 0;
}
static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_set_runtime_buffer(substream, NULL);
return 0;
}
static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
runtime->dma_area,
runtime->dma_addr,
runtime->dma_bytes);
}
static struct snd_pcm_ops tegra_pcm_ops = {
.open = tegra_pcm_open,
.close = tegra_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = tegra_pcm_hw_params,
.hw_free = tegra_pcm_hw_free,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer,
.mmap = tegra_pcm_mmap,
};
static int tegra_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 = tegra_pcm_hardware.buffer_bytes_max;
buf->area = dma_alloc_writecombine(pcm->card->dev, size,
&buf->addr, GFP_KERNEL);
if (!buf->area)
return -ENOMEM;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = pcm->card->dev;
buf->private_data = NULL;
buf->bytes = size;
return 0;
}
static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
{
struct snd_pcm_substream *substream;
struct snd_dma_buffer *buf;
substream = pcm->streams[stream].substream;
if (!substream)
return;
buf = &substream->dma_buffer;
if (!buf->area)
return;
dma_free_writecombine(pcm->card->dev, buf->bytes,
buf->area, buf->addr);
buf->area = NULL;
}
static u64 tegra_dma_mask = DMA_BIT_MASK(32);
static int tegra_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 = &tegra_dma_mask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_PLAYBACK);
if (ret)
goto err;
}
if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
ret = tegra_pcm_preallocate_dma_buffer(pcm,
SNDRV_PCM_STREAM_CAPTURE);
if (ret)
goto err_free_play;
}
return 0;
err_free_play:
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
err:
return ret;
}
static void tegra_pcm_free(struct snd_pcm *pcm)
{
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
}
static struct snd_soc_platform_driver tegra_pcm_platform = {
.ops = &tegra_pcm_ops,
.pcm_new = tegra_pcm_new,
.pcm_free = tegra_pcm_free,
static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
.pcm_hardware = &tegra_pcm_hardware,
.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
.compat_filter_fn = NULL,
.prealloc_buffer_size = PAGE_SIZE * 8,
};
int tegra_pcm_platform_register(struct device *dev)
{
return snd_soc_register_platform(dev, &tegra_pcm_platform);
return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_DT |
SND_DMAENGINE_PCM_FLAG_COMPAT);
}
EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
void tegra_pcm_platform_unregister(struct device *dev)
{
snd_soc_unregister_platform(dev);
return snd_dmaengine_pcm_unregister(dev);
}
EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
......
......@@ -31,13 +31,6 @@
#ifndef __TEGRA_PCM_H__
#define __TEGRA_PCM_H__
struct tegra_pcm_dma_params {
unsigned long addr;
unsigned long wrap;
unsigned long width;
unsigned long req_sel;
};
int tegra_pcm_platform_register(struct device *dev);
void tegra_pcm_platform_unregister(struct device *dev);
......
......@@ -16,7 +16,7 @@ config SND_SOC_UX500_PLAT_MSP_I2S
config SND_SOC_UX500_PLAT_DMA
tristate "Platform - DB8500 (DMA)"
depends on SND_SOC_UX500
select SND_SOC_DMAENGINE_PCM
select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y if you want to enable the Ux500 platform-driver.
......
......@@ -28,28 +28,19 @@
#include "ux500_msp_i2s.h"
#include "ux500_pcm.h"
static struct snd_pcm_hardware ux500_pcm_hw_playback = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_RESUME |
SNDRV_PCM_INFO_PAUSE,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_U16_BE,
.rates = SNDRV_PCM_RATE_KNOT,
.rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
.rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
.channels_min = UX500_PLATFORM_MIN_CHANNELS,
.channels_max = UX500_PLATFORM_MAX_CHANNELS,
.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
.period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
.period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
.periods_min = UX500_PLATFORM_PERIODS_MIN,
.periods_max = UX500_PLATFORM_PERIODS_MAX,
};
#define UX500_PLATFORM_MIN_RATE 8000
#define UX500_PLATFORM_MAX_RATE 48000
#define UX500_PLATFORM_MIN_CHANNELS 1
#define UX500_PLATFORM_MAX_CHANNELS 8
static struct snd_pcm_hardware ux500_pcm_hw_capture = {
#define UX500_PLATFORM_PERIODS_BYTES_MIN 128
#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE)
#define UX500_PLATFORM_PERIODS_MIN 2
#define UX500_PLATFORM_PERIODS_MAX 48
#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE)
static const struct snd_pcm_hardware ux500_pcm_hw = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_RESUME |
......@@ -59,8 +50,8 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
SNDRV_PCM_FMTBIT_S16_BE |
SNDRV_PCM_FMTBIT_U16_BE,
.rates = SNDRV_PCM_RATE_KNOT,
.rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE,
.rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE,
.rate_min = UX500_PLATFORM_MIN_RATE,
.rate_max = UX500_PLATFORM_MAX_RATE,
.channels_min = UX500_PLATFORM_MIN_CHANNELS,
.channels_max = UX500_PLATFORM_MAX_CHANNELS,
.buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
......@@ -70,64 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
.periods_max = UX500_PLATFORM_PERIODS_MAX,
};
static void ux500_pcm_dma_hw_free(struct device *dev,
struct snd_pcm_substream *substream)
static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *buf = runtime->dma_buffer_p;
if (runtime->dma_area == NULL)
return;
if (buf != &substream->dma_buffer) {
dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
buf->addr);
kfree(runtime->dma_buffer_p);
}
snd_pcm_set_runtime_buffer(substream, NULL);
}
static int ux500_pcm_open(struct snd_pcm_substream *substream)
{
int stream_id = substream->pstr->stream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *dai = rtd->cpu_dai;
struct device *dev = dai->dev;
int ret;
struct ux500_msp_dma_params *dma_params;
u16 per_data_width, mem_data_width;
struct stedma40_chan_cfg *dma_cfg;
struct ux500_msp_dma_params *dma_params;
dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
snd_pcm_stream_str(substream));
dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__);
if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
snd_soc_set_runtime_hwparams(substream,
&ux500_pcm_hw_playback);
else
snd_soc_set_runtime_hwparams(substream,
&ux500_pcm_hw_capture);
/* ensure that buffer size is a multiple of period size */
ret = snd_pcm_hw_constraint_integer(runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0) {
dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
__func__, ret);
return ret;
}
dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
snd_pcm_stream_str(substream));
runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
ux500_pcm_hw_playback : ux500_pcm_hw_capture;
dma_params = snd_soc_dai_get_dma_data(dai, substream);
dma_cfg = dma_params->dma_cfg;
mem_data_width = STEDMA40_HALFWORD_WIDTH;
dma_params = snd_soc_dai_get_dma_data(dai, substream);
switch (dma_params->data_size) {
case 32:
per_data_width = STEDMA40_WORD_WIDTH;
......@@ -140,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
break;
default:
per_data_width = STEDMA40_WORD_WIDTH;
dev_warn(rtd->platform->dev,
"%s: Unknown data-size (%d)! Assuming 32 bits.\n",
__func__, dma_params->data_size);
}
dma_cfg = dma_params->dma_cfg;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dma_cfg->src_info.data_width = mem_data_width;
dma_cfg->dst_info.data_width = per_data_width;
......@@ -155,137 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
dma_cfg->dst_info.data_width = mem_data_width;
}
ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
if (ret) {
dev_dbg(dai->dev,
"%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
__func__, ret);
return ret;
}
snd_dmaengine_pcm_set_data(substream, dma_cfg);
return 0;
}
static int ux500_pcm_close(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *dai = rtd->cpu_dai;
dev_dbg(dai->dev, "%s: Enter\n", __func__);
snd_dmaengine_pcm_close(substream);
return 0;
}
static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_dma_buffer *buf = runtime->dma_buffer_p;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
int ret = 0;
int size;
dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
size = params_buffer_bytes(hw_params);
if (buf) {
if (buf->bytes >= size)
goto out;
ux500_pcm_dma_hw_free(NULL, substream);
}
if (substream->dma_buffer.area != NULL &&
substream->dma_buffer.bytes >= size) {
buf = &substream->dma_buffer;
} else {
buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
if (!buf)
goto nomem;
buf->dev.type = SNDRV_DMA_TYPE_DEV;
buf->dev.dev = NULL;
buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
GFP_KERNEL);
buf->bytes = size;
buf->private_data = NULL;
if (!buf->area)
goto free;
}
snd_pcm_set_runtime_buffer(substream, buf);
ret = 1;
out:
runtime->dma_bytes = size;
return ret;
free:
kfree(buf);
nomem:
return -ENOMEM;
return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
}
static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
ux500_pcm_dma_hw_free(NULL, substream);
return 0;
}
static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
return dma_mmap_coherent(NULL, vma, runtime->dma_area,
runtime->dma_addr, runtime->dma_bytes);
}
static struct snd_pcm_ops ux500_pcm_ops = {
.open = ux500_pcm_open,
.close = ux500_pcm_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = ux500_pcm_hw_params,
.hw_free = ux500_pcm_hw_free,
.trigger = snd_dmaengine_pcm_trigger,
.pointer = snd_dmaengine_pcm_pointer_no_residue,
.mmap = ux500_pcm_mmap
};
int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm *pcm = rtd->pcm;
dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
pcm->id);
pcm->info_flags = 0;
return 0;
}
static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
.ops = &ux500_pcm_ops,
.pcm_new = ux500_pcm_new,
static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
.pcm_hardware = &ux500_pcm_hw,
.compat_request_channel = ux500_pcm_request_chan,
.prealloc_buffer_size = 128 * 1024,
};
int ux500_pcm_register_platform(struct platform_device *pdev)
{
int ret;
ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv);
ret = snd_dmaengine_pcm_register(&pdev->dev,
&ux500_dmaengine_pcm_config,
SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
SND_DMAENGINE_PCM_FLAG_COMPAT |
SND_DMAENGINE_PCM_FLAG_NO_DT);
if (ret < 0) {
dev_err(&pdev->dev,
"%s: ERROR: Failed to register platform '%s' (%d)!\n",
......@@ -299,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
int ux500_pcm_unregister_platform(struct platform_device *pdev)
{
snd_soc_unregister_platform(&pdev->dev);
snd_dmaengine_pcm_unregister(&pdev->dev);
return 0;
}
EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
......@@ -18,20 +18,6 @@
#include <linux/workqueue.h>
#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
#define UX500_PLATFORM_MIN_RATE_CAPTURE 8000
#define UX500_PLATFORM_MAX_RATE_CAPTURE 48000
#define UX500_PLATFORM_MIN_CHANNELS 1
#define UX500_PLATFORM_MAX_CHANNELS 8
#define UX500_PLATFORM_PERIODS_BYTES_MIN 128
#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE)
#define UX500_PLATFORM_PERIODS_MIN 2
#define UX500_PLATFORM_PERIODS_MAX 48
#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE)
int ux500_pcm_register_platform(struct platform_device *pdev);
int ux500_pcm_unregister_platform(struct platform_device *pdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment