#include <sound/initval.h>
#include <sound/soc.h>
+#include <mach/asp.h>
+
#include "davinci-pcm.h"
#define DAVINCI_MCBSP_RCR_RWDLEN1(v) ((v) << 5)
#define DAVINCI_MCBSP_RCR_RFRLEN1(v) ((v) << 8)
#define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16)
+#define DAVINCI_MCBSP_RCR_RFIG (1 << 18)
#define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21)
#define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5)
DAVINCI_MCBSP_WORD_32,
};
-static struct davinci_pcm_dma_params davinci_i2s_pcm_out = {
- .name = "I2S PCM Stereo out",
-};
-
-static struct davinci_pcm_dma_params davinci_i2s_pcm_in = {
- .name = "I2S PCM Stereo in",
-};
-
struct davinci_mcbsp_dev {
+ /*
+ * dma_params must be first because rtd->dai->cpu_dai->private_data
+ * is cast to a pointer of an array of struct davinci_pcm_dma_params in
+ * davinci_pcm_open.
+ */
+ struct davinci_pcm_dma_params dma_params[2];
void __iomem *base;
+#define MOD_DSP_A 0
+#define MOD_DSP_B 1
+ int mode;
u32 pcr;
struct clk *clk;
- struct davinci_pcm_dma_params *dma_params[2];
};
static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev,
toggle_clock(dev, playback);
}
-static int davinci_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 davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
-
- cpu_dai->dma_data = dev->dma_params[substream->stream];
-
- return 0;
-}
-
#define DEFAULT_BITPERSAMPLE 16
static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
unsigned int pcr;
unsigned int srgr;
- unsigned int rcr;
- unsigned int xcr;
srgr = DAVINCI_MCBSP_SRGR_FSGM |
DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) |
DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1);
+ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
/* cpu is master */
return -EINVAL;
}
- rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1);
- xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1);
+ /* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
- case SND_SOC_DAIFMT_DSP_B:
- break;
case SND_SOC_DAIFMT_I2S:
/* Davinci doesn't support TRUE I2S, but some codecs will have
* the left and right channels contiguous. This allows
*/
fmt ^= SND_SOC_DAIFMT_NB_IF;
case SND_SOC_DAIFMT_DSP_A:
- rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
- xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+ dev->mode = MOD_DSP_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ dev->mode = MOD_DSP_B;
break;
default:
printk(KERN_ERR "%s:bad format\n", __func__);
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
dev->pcr = pcr;
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, pcr);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
return 0;
}
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
- struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = dai->private_data;
+ struct davinci_pcm_dma_params *dma_params =
+ &dev->dma_params[substream->stream];
struct snd_interval *i = NULL;
int mcbsp_word_length;
unsigned int rcr, xcr, srgr;
srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1);
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr);
+ rcr = DAVINCI_MCBSP_RCR_RFIG;
+ xcr = DAVINCI_MCBSP_XCR_XFIG;
+ if (dev->mode == MOD_DSP_B) {
+ rcr |= DAVINCI_MCBSP_RCR_RDATDLY(0);
+ xcr |= DAVINCI_MCBSP_XCR_XDATDLY(0);
+ } else {
+ rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1);
+ xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1);
+ }
/* Determine xfer data type */
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
return -EINVAL;
}
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- rcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG);
- rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
- DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
- davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+ dma_params->acnt = dma_params->data_type;
+ dma_params->fifo_level = 0;
- } else {
- xcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG);
- xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
- DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
+ rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(1);
+ xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(1);
+
+ rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) |
+ DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length);
+ xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) |
+ DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr);
+ else
+ davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr);
+ return 0;
+}
+static int davinci_i2s_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_mcbsp_dev *dev = dai->private_data;
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ davinci_mcbsp_stop(dev, playback);
+ if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) {
+ /* codec is master */
+ davinci_mcbsp_start(dev, substream);
}
return 0;
}
static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *dai)
{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = dai->private_data;
int ret = 0;
int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0)
+ return 0; /* return if codec is master */
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
default:
ret = -EINVAL;
}
-
return ret;
}
-static int davinci_i2s_probe(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static void davinci_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct davinci_mcbsp_dev *dev = dai->private_data;
+ int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
+ davinci_mcbsp_stop(dev, playback);
+}
+
+#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
+
+static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
+ .shutdown = davinci_i2s_shutdown,
+ .prepare = davinci_i2s_prepare,
+ .trigger = davinci_i2s_trigger,
+ .hw_params = davinci_i2s_hw_params,
+ .set_fmt = davinci_i2s_set_dai_fmt,
+
+};
+
+struct snd_soc_dai davinci_i2s_dai = {
+ .name = "davinci-i2s",
+ .id = 0,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = DAVINCI_I2S_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,},
+ .ops = &davinci_i2s_dai_ops,
+
+};
+EXPORT_SYMBOL_GPL(davinci_i2s_dai);
+
+static int davinci_i2s_probe(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
+ struct snd_platform_data *pdata = pdev->dev.platform_data;
struct davinci_mcbsp_dev *dev;
- struct resource *mem, *ioarea;
- struct evm_snd_platform_data *pdata;
+ struct resource *mem, *ioarea, *res;
int ret;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
goto err_release_region;
}
- cpu_dai->private_data = dev;
-
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
ret = -ENODEV;
clk_enable(dev->clk);
dev->base = (void __iomem *)IO_ADDRESS(mem->start);
- pdata = pdev->dev.platform_data;
- dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK] = &davinci_i2s_pcm_out;
- dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->channel = pdata->tx_dma_ch;
- dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]->dma_addr =
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr =
(dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG);
- dev->dma_params[SNDRV_PCM_STREAM_CAPTURE] = &davinci_i2s_pcm_in;
- dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->channel = pdata->rx_dma_ch;
- dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]->dma_addr =
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr =
(dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG);
+ /* first TX, then RX */
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENXIO;
+ goto err_free_mem;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (!res) {
+ dev_err(&pdev->dev, "no DMA resource\n");
+ ret = -ENXIO;
+ goto err_free_mem;
+ }
+ dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start;
+
+ davinci_i2s_dai.private_data = dev;
+ ret = snd_soc_register_dai(&davinci_i2s_dai);
+ if (ret != 0)
+ goto err_free_mem;
+
return 0;
err_free_mem:
return ret;
}
-static void davinci_i2s_remove(struct platform_device *pdev,
- struct snd_soc_dai *dai)
+static int davinci_i2s_remove(struct platform_device *pdev)
{
- struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct snd_soc_card *card = socdev->card;
- struct snd_soc_dai *cpu_dai = card->dai_link->cpu_dai;
- struct davinci_mcbsp_dev *dev = cpu_dai->private_data;
+ struct davinci_mcbsp_dev *dev = davinci_i2s_dai.private_data;
struct resource *mem;
+ snd_soc_unregister_dai(&davinci_i2s_dai);
clk_disable(dev->clk);
clk_put(dev->clk);
dev->clk = NULL;
-
kfree(dev);
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(mem->start, (mem->end - mem->start) + 1);
-}
-#define DAVINCI_I2S_RATES SNDRV_PCM_RATE_8000_96000
+ return 0;
+}
-static struct snd_soc_dai_ops davinci_i2s_dai_ops = {
- .startup = davinci_i2s_startup,
- .trigger = davinci_i2s_trigger,
- .hw_params = davinci_i2s_hw_params,
- .set_fmt = davinci_i2s_set_dai_fmt,
+static struct platform_driver davinci_mcbsp_driver = {
+ .probe = davinci_i2s_probe,
+ .remove = davinci_i2s_remove,
+ .driver = {
+ .name = "davinci-asp",
+ .owner = THIS_MODULE,
+ },
};
-struct snd_soc_dai davinci_i2s_dai = {
- .name = "davinci-i2s",
- .id = 0,
- .probe = davinci_i2s_probe,
- .remove = davinci_i2s_remove,
- .playback = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = DAVINCI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .capture = {
- .channels_min = 2,
- .channels_max = 2,
- .rates = DAVINCI_I2S_RATES,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,},
- .ops = &davinci_i2s_dai_ops,
-};
-EXPORT_SYMBOL_GPL(davinci_i2s_dai);
-
static int __init davinci_i2s_init(void)
{
- return snd_soc_register_dai(&davinci_i2s_dai);
+ return platform_driver_register(&davinci_mcbsp_driver);
}
module_init(davinci_i2s_init);
static void __exit davinci_i2s_exit(void)
{
- snd_soc_unregister_dai(&davinci_i2s_dai);
+ platform_driver_unregister(&davinci_mcbsp_driver);
}
module_exit(davinci_i2s_exit);