diff options
Diffstat (limited to 'sound/soc/davinci')
-rw-r--r-- | sound/soc/davinci/Kconfig | 10 | ||||
-rw-r--r-- | sound/soc/davinci/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-evm.c | 33 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-i2s.c | 257 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-pcm.c | 32 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-sffsdr.c | 161 |
6 files changed, 409 insertions, 86 deletions
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 8f7e3383490..b502741692d 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig @@ -17,3 +17,13 @@ config SND_DAVINCI_SOC_EVM help Say Y if you want to add support for SoC audio on TI DaVinci EVM platform. + +config SND_DAVINCI_SOC_SFFSDR + tristate "SoC Audio support for SFFSDR" + depends on SND_DAVINCI_SOC && MACH_DAVINCI_SFFSDR + select SND_DAVINCI_SOC_I2S + select SND_SOC_PCM3008 + select SFFSDR_FPGA + help + Say Y if you want to add support for SoC audio on + Lyrtech SFFSDR board. diff --git a/sound/soc/davinci/Makefile b/sound/soc/davinci/Makefile index ca772e5b463..ca8bae1fc3f 100644 --- a/sound/soc/davinci/Makefile +++ b/sound/soc/davinci/Makefile @@ -7,5 +7,7 @@ obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o # DAVINCI Machine Support snd-soc-evm-objs := davinci-evm.o +snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o +obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 9e6062cd6b5..54851f31856 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -26,8 +26,9 @@ #include "davinci-pcm.h" #include "davinci-i2s.h" -#define EVM_CODEC_CLOCK 22579200 +#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \ + SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF) static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -35,22 +36,34 @@ static int evm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int ret = 0; + unsigned sysclk; + + /* ASP1 on DM355 EVM is clocked by an external oscillator */ + if (machine_is_davinci_dm355_evm()) + sysclk = 27000000; + + /* ASP0 in DM6446 EVM is clocked by U55, as configured by + * board-dm644x-evm.c using GPIOs from U18. There are six + * options; here we "know" we use a 48 KHz sample rate. + */ + else if (machine_is_davinci_evm()) + sysclk = 12288000; + + else + return -EINVAL; /* set codec DAI configuration */ - ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBM_CFM); + ret = snd_soc_dai_set_fmt(codec_dai, AUDIO_FORMAT); if (ret < 0) return ret; /* set cpu DAI configuration */ - ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBM_CFM | - SND_SOC_DAIFMT_IB_NF); + ret = snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT); if (ret < 0) return ret; /* set the codec system clock */ - ret = snd_soc_dai_set_sysclk(codec_dai, 0, EVM_CODEC_CLOCK, - SND_SOC_CLOCK_OUT); + ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT); if (ret < 0) return ret; @@ -128,8 +141,9 @@ static struct snd_soc_dai_link evm_dai = { }; /* davinci-evm audio machine driver */ -static struct snd_soc_machine snd_soc_machine_evm = { +static struct snd_soc_card snd_soc_card_evm = { .name = "DaVinci EVM", + .platform = &davinci_soc_platform, .dai_link = &evm_dai, .num_links = 1, }; @@ -142,8 +156,7 @@ static struct aic3x_setup_data evm_aic3x_setup = { /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { - .machine = &snd_soc_machine_evm, - .platform = &davinci_soc_platform, + .card = &snd_soc_card_evm, .codec_dev = &soc_codec_dev_aic3x, .codec_data = &evm_aic3x_setup, }; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index abb5fedb0b1..0fee779e3c7 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -59,6 +59,7 @@ #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) #define DAVINCI_MCBSP_PCR_FSRP (1 << 2) #define DAVINCI_MCBSP_PCR_FSXP (1 << 3) +#define DAVINCI_MCBSP_PCR_SCLKME (1 << 7) #define DAVINCI_MCBSP_PCR_CLKRM (1 << 8) #define DAVINCI_MCBSP_PCR_CLKXM (1 << 9) #define DAVINCI_MCBSP_PCR_FSRM (1 << 10) @@ -110,16 +111,59 @@ static void davinci_mcbsp_start(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_platform *platform = socdev->card->platform; u32 w; + int ret; /* Start the sample generator and enable transmitter/receiver */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_GRST, 1); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Stop the DMA to avoid data loss */ + /* while the transmitter is out of reset to handle XSYNCERR */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_STOP); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA stop failed\n"); + } + + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); - else + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* wait for any unexpected frame sync error to occur */ + udelay(100); + + /* Disable the transmitter to clear any outstanding XSYNCERR */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 0); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + /* Restart the DMA */ + if (platform->pcm_ops->trigger) { + ret = platform->pcm_ops->trigger(substream, + SNDRV_PCM_TRIGGER_START); + if (ret < 0) + printk(KERN_DEBUG "Playback DMA start failed\n"); + } + /* Enable the transmitter */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_XRST, 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + + } else { + + /* Enable the reciever */ + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SPCR_RRST, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } + /* Start frame sync */ w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -144,7 +188,8 @@ static void davinci_mcbsp_stop(struct snd_pcm_substream *substream) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); } -static int davinci_i2s_startup(struct snd_pcm_substream *substream) +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; @@ -155,61 +200,138 @@ static int davinci_i2s_startup(struct snd_pcm_substream *substream) return 0; } +#define DEFAULT_BITPERSAMPLE 16 + static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcbsp_dev *dev = cpu_dai->private_data; - u32 w; + 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); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM | - DAVINCI_MCBSP_PCR_CLKXM | - DAVINCI_MCBSP_PCR_CLKRM); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, - DAVINCI_MCBSP_SRGR_FSGM); + /* cpu is master */ + pcr = DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | + DAVINCI_MCBSP_PCR_CLKRM; + break; + case SND_SOC_DAIFMT_CBM_CFS: + /* McBSP CLKR pin is the input for the Sample Rate Generator. + * McBSP FSR and FSX are driven by the Sample Rate Generator. */ + pcr = DAVINCI_MCBSP_PCR_SCLKME | + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM; break; case SND_SOC_DAIFMT_CBM_CFM: - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, 0); + /* codec is master */ + pcr = 0; break; default: + printk(KERN_ERR "%s:bad master\n", __func__); return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_IB_NF: - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + rcr = DAVINCI_MCBSP_RCR_RFRLEN1(1); + xcr = DAVINCI_MCBSP_XCR_XFIG | DAVINCI_MCBSP_XCR_XFRLEN1(1); + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: break; - case SND_SOC_DAIFMT_NB_IF: - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + case SND_SOC_DAIFMT_I2S: + /* Davinci doesn't support TRUE I2S, but some codecs will have + * the left and right channels contiguous. This allows + * dsp_a mode to be used with an inverted normal frame clk. + * If your codec is master and does not have contiguous + * channels, then you will have sound on only one channel. + * Try using a different mode, or codec as slave. + * + * The TLV320AIC33 is an example of a codec where this works. + * It has a variable bit clock frequency allowing it to have + * valid data on every bit clock. + * + * The TLV320AIC23 is an example of a codec where this does not + * work. It has a fixed bit clock frequency with progressively + * more empty bit clock slots between channels as the sample + * rate is lowered. + */ + fmt ^= SND_SOC_DAIFMT_NB_IF; + case SND_SOC_DAIFMT_DSP_A: + rcr |= DAVINCI_MCBSP_RCR_RDATDLY(1); + xcr |= DAVINCI_MCBSP_XCR_XDATDLY(1); + break; + default: + printk(KERN_ERR "%s:bad format\n", __func__); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP); break; case SND_SOC_DAIFMT_IB_IF: - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_PCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_PCR_CLKXP | - DAVINCI_MCBSP_PCR_CLKRP | - DAVINCI_MCBSP_PCR_FSXP | - DAVINCI_MCBSP_PCR_FSRP, 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_PCR_REG, w); + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ + pcr |= (DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); break; - case SND_SOC_DAIFMT_NB_NF: + case SND_SOC_DAIFMT_NB_IF: + /* CLKRP Receive clock polarity, + * 1 - sampled on rising edge of CLKR + * valid on rising edge + * CLKXP Transmit clock polarity, + * 1 - clocked on falling edge of CLKX + * valid on rising edge + * FSRP Receive frame sync pol, 1 - active low + * FSXP Transmit frame sync pol, 1 - active low + */ + pcr |= (DAVINCI_MCBSP_PCR_CLKXP | DAVINCI_MCBSP_PCR_CLKRP | + DAVINCI_MCBSP_PCR_FSXP | DAVINCI_MCBSP_PCR_FSRP); + break; + case SND_SOC_DAIFMT_IB_NF: + /* CLKRP Receive clock polarity, + * 0 - sampled on falling edge of CLKR + * valid on falling edge + * CLKXP Transmit clock polarity, + * 0 - clocked on rising edge of CLKX + * valid on falling edge + * FSRP Receive frame sync pol, 0 - active high + * FSXP Transmit frame sync pol, 0 - active high + */ break; default: return -EINVAL; } - + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); + 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; } static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) + 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; @@ -219,25 +341,20 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, u32 w; /* general line settings */ - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, - DAVINCI_MCBSP_SPCR_RINTM(3) | - DAVINCI_MCBSP_SPCR_XINTM(3) | - DAVINCI_MCBSP_SPCR_FREE); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, - DAVINCI_MCBSP_RCR_RFRLEN1(1) | - DAVINCI_MCBSP_RCR_RDATDLY(1)); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, - DAVINCI_MCBSP_XCR_XFRLEN1(1) | - DAVINCI_MCBSP_XCR_XDATDLY(1) | - DAVINCI_MCBSP_XCR_XFIG); + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w |= DAVINCI_MCBSP_SPCR_RINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } else { + w |= DAVINCI_MCBSP_SPCR_XINTM(3) | DAVINCI_MCBSP_SPCR_FREE; + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, w); + } i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); + w = DAVINCI_MCBSP_SRGR_FSGM; MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SRGR_REG); MOD_REG_BIT(w, DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1), 1); davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, w); @@ -260,20 +377,24 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_RCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, w); - w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); - MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); - davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } else { + w = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_XCR_REG); + MOD_REG_BIT(w, DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length), 1); + davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, w); + } return 0; } -static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd) +static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) { int ret = 0; @@ -299,8 +420,8 @@ static int davinci_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev; struct resource *mem, *ioarea; struct evm_snd_platform_data *pdata; @@ -361,8 +482,8 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); - struct snd_soc_machine *machine = socdev->machine; - struct snd_soc_dai *cpu_dai = machine->dai_link[pdev->id].cpu_dai; + struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[pdev->id].cpu_dai; struct davinci_mcbsp_dev *dev = cpu_dai->private_data; struct resource *mem; @@ -381,7 +502,6 @@ static void davinci_i2s_remove(struct platform_device *pdev, struct snd_soc_dai davinci_i2s_dai = { .name = "davinci-i2s", .id = 0, - .type = SND_SOC_DAI_I2S, .probe = davinci_i2s_probe, .remove = davinci_i2s_remove, .playback = { @@ -397,13 +517,24 @@ struct snd_soc_dai davinci_i2s_dai = { .ops = { .startup = davinci_i2s_startup, .trigger = davinci_i2s_trigger, - .hw_params = davinci_i2s_hw_params,}, - .dai_ops = { + .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, }, }; EXPORT_SYMBOL_GPL(davinci_i2s_dai); +static int __init davinci_i2s_init(void) +{ + return snd_soc_register_dai(&davinci_i2s_dai); +} +module_init(davinci_i2s_init); + +static void __exit davinci_i2s_exit(void) +{ + snd_soc_unregister_dai(&davinci_i2s_dai); +} +module_exit(davinci_i2s_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI I2S (McBSP) SoC Interface"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 76feaa65737..366049d8578 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -14,6 +14,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/dma-mapping.h> +#include <linux/kernel.h> #include <sound/core.h> #include <sound/pcm.h> @@ -24,13 +25,6 @@ #include "davinci-pcm.h" -#define DAVINCI_PCM_DEBUG 0 -#if DAVINCI_PCM_DEBUG -#define DPRINTK(x...) printk(KERN_DEBUG x) -#else -#define DPRINTK(x...) -#endif - static struct snd_pcm_hardware davinci_pcm_hardware = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -78,8 +72,8 @@ static void davinci_pcm_enqueue_dma(struct snd_pcm_substream *substream) dma_offset = prtd->period * period_size; dma_pos = runtime->dma_addr + dma_offset; - DPRINTK("audio_set_dma_params_play channel = %d dma_ptr = %x " - "period_size=%x\n", lch, dma_pos, period_size); + pr_debug("davinci_pcm: audio_set_dma_params_play channel = %d " + "dma_ptr = %x period_size=%x\n", lch, dma_pos, period_size); data_type = prtd->params->data_type; count = period_size / data_type; @@ -112,7 +106,7 @@ static void davinci_pcm_dma_irq(int lch, u16 ch_status, void *data) struct snd_pcm_substream *substream = data; struct davinci_runtime_data *prtd = substream->runtime->private_data; - DPRINTK("lch=%d, status=0x%x\n", lch, ch_status); + pr_debug("davinci_pcm: lch=%d, status=0x%x\n", lch, ch_status); if (unlikely(ch_status != DMA_COMPLETE)) return; @@ -218,7 +212,7 @@ davinci_pcm_pointer(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) count = src - runtime->dma_addr; else - count = dst - runtime->dma_addr;; + count = dst - runtime->dma_addr; spin_unlock(&prtd->lock); @@ -316,8 +310,8 @@ static int davinci_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) buf->area = dma_alloc_writecombine(pcm->card->dev, size, &buf->addr, GFP_KERNEL); - DPRINTK("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", - (void *) buf->area, (void *) buf->addr, size); + pr_debug("davinci_pcm: preallocate_dma_buffer: area=%p, addr=%p, " + "size=%d\n", (void *) buf->area, (void *) buf->addr, size); if (!buf->area) return -ENOMEM; @@ -384,6 +378,18 @@ struct snd_soc_platform davinci_soc_platform = { }; EXPORT_SYMBOL_GPL(davinci_soc_platform); +static int __init davinci_soc_platform_init(void) +{ + return snd_soc_register_platform(&davinci_soc_platform); +} +module_init(davinci_soc_platform_init); + +static void __exit davinci_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&davinci_soc_platform); +} +module_exit(davinci_soc_platform_exit); + MODULE_AUTHOR("Vladimir Barinov"); MODULE_DESCRIPTION("TI DAVINCI PCM DMA module"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/davinci/davinci-sffsdr.c b/sound/soc/davinci/davinci-sffsdr.c new file mode 100644 index 00000000000..4935d1bcbd8 --- /dev/null +++ b/sound/soc/davinci/davinci-sffsdr.c @@ -0,0 +1,161 @@ +/* + * ASoC driver for Lyrtech SFFSDR board. + * + * Author: Hugo Villeneuve + * Copyright (C) 2008 Lyrtech inc + * + * Based on ASoC driver for TI DAVINCI EVM platform, original copyright follow: + * Copyright: (C) 2007 MontaVista Software, Inc., <source@mvista.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. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> + +#include <asm/dma.h> +#include <asm/mach-types.h> +#include <asm/plat-sffsdr/sffsdr-fpga.h> + +#include <mach/mcbsp.h> +#include <mach/edma.h> + +#include "../codecs/pcm3008.h" +#include "davinci-pcm.h" +#include "davinci-i2s.h" + +static int sffsdr_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; + int fs; + int ret = 0; + + /* Set cpu DAI configuration: + * CLKX and CLKR are the inputs for the Sample Rate Generator. + * FSX and FSR are outputs, driven by the sample Rate Generator. */ + ret = snd_soc_dai_set_fmt(cpu_dai, + SND_SOC_DAIFMT_RIGHT_J | + SND_SOC_DAIFMT_CBM_CFS | + SND_SOC_DAIFMT_IB_NF); + if (ret < 0) + return ret; + + /* Fsref can be 32000, 44100 or 48000. */ + fs = params_rate(params); + + pr_debug("sffsdr_hw_params: rate = %d Hz\n", fs); + + return sffsdr_fpga_set_codec_fs(fs); +} + +static struct snd_soc_ops sffsdr_ops = { + .hw_params = sffsdr_hw_params, +}; + +/* davinci-sffsdr digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link sffsdr_dai = { + .name = "PCM3008", /* Codec name */ + .stream_name = "PCM3008 HiFi", + .cpu_dai = &davinci_i2s_dai, + .codec_dai = &pcm3008_dai, + .ops = &sffsdr_ops, +}; + +/* davinci-sffsdr audio machine driver */ +static struct snd_soc_card snd_soc_sffsdr = { + .name = "DaVinci SFFSDR", + .platform = &davinci_soc_platform, + .dai_link = &sffsdr_dai, + .num_links = 1, +}; + +/* sffsdr audio private data */ +static struct pcm3008_setup_data sffsdr_pcm3008_setup = { + .dem0_pin = GPIO(45), + .dem1_pin = GPIO(46), + .pdad_pin = GPIO(47), + .pdda_pin = GPIO(38), +}; + +/* sffsdr audio subsystem */ +static struct snd_soc_device sffsdr_snd_devdata = { + .card = &snd_soc_sffsdr, + .codec_dev = &soc_codec_dev_pcm3008, + .codec_data = &sffsdr_pcm3008_setup, +}; + +static struct resource sffsdr_snd_resources[] = { + { + .start = DAVINCI_MCBSP_BASE, + .end = DAVINCI_MCBSP_BASE + SZ_8K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct evm_snd_platform_data sffsdr_snd_data = { + .tx_dma_ch = DAVINCI_DMA_MCBSP_TX, + .rx_dma_ch = DAVINCI_DMA_MCBSP_RX, +}; + +static struct platform_device *sffsdr_snd_device; + +static int __init sffsdr_init(void) +{ + int ret; + + if (!machine_is_sffsdr()) + return -EINVAL; + + sffsdr_snd_device = platform_device_alloc("soc-audio", 0); + if (!sffsdr_snd_device) { + printk(KERN_ERR "platform device allocation failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(sffsdr_snd_device, &sffsdr_snd_devdata); + sffsdr_snd_devdata.dev = &sffsdr_snd_device->dev; + sffsdr_snd_device->dev.platform_data = &sffsdr_snd_data; + + ret = platform_device_add_resources(sffsdr_snd_device, + sffsdr_snd_resources, + ARRAY_SIZE(sffsdr_snd_resources)); + if (ret) { + printk(KERN_ERR "platform device add ressources failed\n"); + goto error; + } + + ret = platform_device_add(sffsdr_snd_device); + if (ret) + goto error; + + return ret; + +error: + platform_device_put(sffsdr_snd_device); + return ret; +} + +static void __exit sffsdr_exit(void) +{ + platform_device_unregister(sffsdr_snd_device); +} + +module_init(sffsdr_init); +module_exit(sffsdr_exit); + +MODULE_AUTHOR("Hugo Villeneuve"); +MODULE_DESCRIPTION("Lyrtech SFFSDR ASoC driver"); +MODULE_LICENSE("GPL"); |