aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/pxa/pxa2xx-i2s.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/pxa/pxa2xx-i2s.c')
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c137
1 files changed, 73 insertions, 64 deletions
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 6b8f655d1ad..c0d648d3339 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -17,17 +17,17 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/io.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
#include <mach/hardware.h>
-#include <mach/dma.h>
#include <mach/audio.h>
-#include "pxa2xx-pcm.h"
#include "pxa2xx-i2s.h"
/*
@@ -80,28 +80,29 @@ struct pxa_i2s_port {
};
static struct pxa_i2s_port pxa_i2s;
static struct clk *clk_i2s;
-
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
- .name = "I2S PCM Stereo out",
- .dev_addr = __PREG(SADR),
- .drcmr = &DRCMR(3),
- .dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG |
- DCMD_BURST32 | DCMD_WIDTH4,
+static int clk_ena = 0;
+
+static unsigned long pxa2xx_i2s_pcm_stereo_out_req = 3;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
+ .addr = __PREG(SADR),
+ .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .maxburst = 32,
+ .filter_data = &pxa2xx_i2s_pcm_stereo_out_req,
};
-static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
- .name = "I2S PCM Stereo in",
- .dev_addr = __PREG(SADR),
- .drcmr = &DRCMR(2),
- .dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC |
- DCMD_BURST32 | DCMD_WIDTH4,
+static unsigned long pxa2xx_i2s_pcm_stereo_in_req = 2;
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
+ .addr = __PREG(SADR),
+ .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .maxburst = 32,
+ .filter_data = &pxa2xx_i2s_pcm_stereo_in_req,
};
static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
if (IS_ERR(clk_i2s))
return PTR_ERR(clk_i2s);
@@ -162,18 +163,20 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct snd_dmaengine_dai_dma_data *dma_data;
- BUG_ON(IS_ERR(clk_i2s));
- clk_enable(clk_i2s);
- dai->private_data = dai;
+ if (WARN_ON(IS_ERR(clk_i2s)))
+ return -EINVAL;
+ clk_prepare_enable(clk_i2s);
+ clk_ena = 1;
pxa_i2s_wait();
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
+ dma_data = &pxa2xx_i2s_pcm_stereo_out;
else
- cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
+ dma_data = &pxa2xx_i2s_pcm_stereo_in;
+
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* is port used by another stream */
if (!(SACR0 & SACR0_ENB)) {
@@ -256,9 +259,9 @@ static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
SACR0 &= ~SACR0_ENB;
pxa_i2s_wait();
- if (dai->private_data != NULL) {
- clk_disable(clk_i2s);
- dai->private_data = NULL;
+ if (clk_ena) {
+ clk_disable_unprepare(clk_i2s);
+ clk_ena = 0;
}
}
}
@@ -297,11 +300,40 @@ static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
#define pxa2xx_i2s_resume NULL
#endif
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+ clk_i2s = clk_get(dai->dev, "I2SCLK");
+ if (IS_ERR(clk_i2s))
+ return PTR_ERR(clk_i2s);
+
+ /*
+ * PXA Developer's Manual:
+ * If SACR0[ENB] is toggled in the middle of a normal operation,
+ * the SACR0[RST] bit must also be set and cleared to reset all
+ * I2S controller registers.
+ */
+ SACR0 = SACR0_RST;
+ SACR0 = 0;
+ /* Make sure RPL and REC are disabled */
+ SACR1 = SACR1_DRPL | SACR1_DREC;
+ /* Along with FIFO servicing */
+ SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+ return 0;
+}
+
+static int pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+ clk_put(clk_i2s);
+ clk_i2s = ERR_PTR(-ENOENT);
+ return 0;
+}
+
#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
-static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
.startup = pxa2xx_i2s_startup,
.shutdown = pxa2xx_i2s_shutdown,
.trigger = pxa2xx_i2s_trigger,
@@ -310,9 +342,9 @@ static struct snd_soc_dai_ops pxa_i2s_dai_ops = {
.set_sysclk = pxa2xx_i2s_set_dai_sysclk,
};
-struct snd_soc_dai pxa_i2s_dai = {
- .name = "pxa2xx-i2s",
- .id = 0,
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+ .probe = pxa2xx_i2s_probe,
+ .remove = pxa2xx_i2s_remove,
.suspend = pxa2xx_i2s_suspend,
.resume = pxa2xx_i2s_resume,
.playback = {
@@ -329,49 +361,25 @@ struct snd_soc_dai pxa_i2s_dai = {
.symmetric_rates = 1,
};
-EXPORT_SYMBOL_GPL(pxa_i2s_dai);
+static const struct snd_soc_component_driver pxa_i2s_component = {
+ .name = "pxa-i2s",
+};
-static int pxa2xx_i2s_probe(struct platform_device *dev)
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
{
- int ret;
-
- clk_i2s = clk_get(&dev->dev, "I2SCLK");
- if (IS_ERR(clk_i2s))
- return PTR_ERR(clk_i2s);
-
- pxa_i2s_dai.dev = &dev->dev;
- pxa_i2s_dai.private_data = NULL;
- ret = snd_soc_register_dai(&pxa_i2s_dai);
- if (ret != 0)
- clk_put(clk_i2s);
-
- /*
- * PXA Developer's Manual:
- * If SACR0[ENB] is toggled in the middle of a normal operation,
- * the SACR0[RST] bit must also be set and cleared to reset all
- * I2S controller registers.
- */
- SACR0 = SACR0_RST;
- SACR0 = 0;
- /* Make sure RPL and REC are disabled */
- SACR1 = SACR1_DRPL | SACR1_DREC;
- /* Along with FIFO servicing */
- SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
-
- return ret;
+ return snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+ &pxa_i2s_dai, 1);
}
-static int __devexit pxa2xx_i2s_remove(struct platform_device *dev)
+static int pxa2xx_i2s_drv_remove(struct platform_device *pdev)
{
- snd_soc_unregister_dai(&pxa_i2s_dai);
- clk_put(clk_i2s);
- clk_i2s = ERR_PTR(-ENOENT);
+ snd_soc_unregister_component(&pdev->dev);
return 0;
}
static struct platform_driver pxa2xx_i2s_driver = {
- .probe = pxa2xx_i2s_probe,
- .remove = __devexit_p(pxa2xx_i2s_remove),
+ .probe = pxa2xx_i2s_drv_probe,
+ .remove = pxa2xx_i2s_drv_remove,
.driver = {
.name = "pxa2xx-i2s",
@@ -397,3 +405,4 @@ module_exit(pxa2xx_i2s_exit);
MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");