diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index 32ee3f895967..d9bc3fa7bb22 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -762,16 +762,19 @@ static u8 da850_iis_serializer_direction[] = { }; static struct snd_platform_data da850_evm_snd_data = { - .tx_dma_offset = 0x2000, - .rx_dma_offset = 0x2000, - .op_mode = DAVINCI_MCASP_IIS_MODE, - .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction), - .tdm_slots = 2, - .serial_dir = da850_iis_serializer_direction, - .asp_chan_q = EVENTQ_0, - .version = MCASP_VERSION_2, - .txnumevt = 1, - .rxnumevt = 1, + .tx_dma_offset = 0x2000, + .rx_dma_offset = 0x2000, + .op_mode = DAVINCI_MCASP_IIS_MODE, + .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction), + .tdm_slots = 2, + .serial_dir = da850_iis_serializer_direction, + .asp_chan_q = EVENTQ_0, + .ram_chan_q = EVENTQ_1, + .version = MCASP_VERSION_2, + .txnumevt = 1, + .rxnumevt = 1, + .sram_size_playback = SZ_8K, + .sram_size_capture = SZ_8K, }; static const short da850_evm_mcasp_pins[] __initconst = { @@ -1509,6 +1512,7 @@ static __init void da850_evm_init(void) pr_warning("da850_evm_init: mcasp mux setup failed: %d\n", ret); + da850_evm_snd_data.sram_pool = sram_get_gen_pool(); da8xx_register_mcasp(0, &da850_evm_snd_data); ret = davinci_cfg_reg_list(da850_lcdcntl_pins); diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index d0c5825876f8..8db5ae03b6e3 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -16,12 +16,13 @@ #ifndef __DAVINCI_ASP_H #define __DAVINCI_ASP_H +#include + struct snd_platform_data { u32 tx_dma_offset; u32 rx_dma_offset; int asp_chan_q; /* event queue number for ASP channel */ int ram_chan_q; /* event queue number for RAM channel */ - unsigned int codec_fmt; /* * Allowing this is more efficient and eliminates left and right swaps * caused by underruns, but will swap the left and right channels @@ -30,6 +31,7 @@ struct snd_platform_data { unsigned enable_channel_combine:1; unsigned sram_size_playback; unsigned sram_size_capture; + struct gen_pool *sram_pool; /* * If McBSP peripheral gets the clock from an external pin, diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 6fac5af13298..d55e6477bff0 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -71,6 +71,11 @@ static int evm_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; + /* set the CPU system clock */ + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT); + if (ret < 0) + return ret; + return 0; } diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 714e51e5be5b..55e2bf652bef 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -199,6 +199,7 @@ #define ACLKXE BIT(5) #define TX_ASYNC BIT(6) #define ACLKXPOL BIT(7) +#define ACLKXDIV_MASK 0x1f /* * DAVINCI_MCASP_ACLKRCTL_REG Receive Clock Control Register Bits @@ -207,6 +208,7 @@ #define ACLKRE BIT(5) #define RX_ASYNC BIT(6) #define ACLKRPOL BIT(7) +#define ACLKRDIV_MASK 0x1f /* * DAVINCI_MCASP_AHCLKXCTL_REG - High Frequency Transmit Clock Control @@ -215,6 +217,7 @@ #define AHCLKXDIV(val) (val) #define AHCLKXPOL BIT(14) #define AHCLKXE BIT(15) +#define AHCLKXDIV_MASK 0xfff /* * DAVINCI_MCASP_AHCLKRCTL_REG - High Frequency Receive Clock Control @@ -223,6 +226,7 @@ #define AHCLKRDIV(val) (val) #define AHCLKRPOL BIT(14) #define AHCLKRE BIT(15) +#define AHCLKRDIV_MASK 0xfff /* * DAVINCI_MCASP_XRSRCTL_BASE_REG - Serializer Control Register Bits @@ -473,6 +477,23 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); void __iomem *base = dev->base; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_B: + case SND_SOC_DAIFMT_AC97: + mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + break; + default: + /* configure a full-word SYNC pulse (LRCLK) */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); + + /* make 1st data bit occur one ACLK cycle after the frame sync */ + mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, FSXDLY(1)); + mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1)); + break; + } + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* codec is clock and frame slave */ @@ -482,8 +503,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, mcasp_set_bits(base + DAVINCI_MCASP_ACLKRCTL_REG, ACLKRE); mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, AFSRE); - mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, - ACLKX | AHCLKX | AFSX); + mcasp_set_bits(base + DAVINCI_MCASP_PDIR_REG, ACLKX | AFSX); break; case SND_SOC_DAIFMT_CBM_CFS: /* codec is clock master and frame slave */ @@ -554,59 +574,75 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } -static int davinci_config_channel_size(struct davinci_audio_dev *dev, - int channel_size) +static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - u32 fmt = 0; - u32 mask, rotate; + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); - switch (channel_size) { - case DAVINCI_AUDIO_WORD_8: - fmt = 0x03; - rotate = 6; - mask = 0x000000ff; + switch (div_id) { + case 0: /* MCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, + AHCLKXDIV(div - 1), AHCLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, + AHCLKRDIV(div - 1), AHCLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_12: - fmt = 0x05; - rotate = 5; - mask = 0x00000fff; + case 1: /* BCLK divider */ + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKXCTL_REG, + ACLKXDIV(div - 1), ACLKXDIV_MASK); + mcasp_mod_bits(dev->base + DAVINCI_MCASP_ACLKRCTL_REG, + ACLKRDIV(div - 1), ACLKRDIV_MASK); break; - case DAVINCI_AUDIO_WORD_16: - fmt = 0x07; - rotate = 4; - mask = 0x0000ffff; - break; - - case DAVINCI_AUDIO_WORD_20: - fmt = 0x09; - rotate = 3; - mask = 0x000fffff; - break; - - case DAVINCI_AUDIO_WORD_24: - fmt = 0x0B; - rotate = 2; - mask = 0x00ffffff; - break; - - case DAVINCI_AUDIO_WORD_28: - fmt = 0x0D; - rotate = 1; - mask = 0x0fffffff; - break; - - case DAVINCI_AUDIO_WORD_32: - fmt = 0x0F; - rotate = 0; - mask = 0xffffffff; + case 2: /* BCLK/LRCLK ratio */ + dev->bclk_lrclk_ratio = div; break; default: return -EINVAL; } + return 0; +} + +static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai); + + if (dir == SND_SOC_CLOCK_OUT) { + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_set_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); + } else { + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, AHCLKRE); + mcasp_clr_bits(dev->base + DAVINCI_MCASP_PDIR_REG, AHCLKX); + } + + return 0; +} + +static int davinci_config_channel_size(struct davinci_audio_dev *dev, + int word_length) +{ + u32 fmt; + u32 rotate = (32 - word_length) / 4; + u32 mask = (1ULL << word_length) - 1; + + /* + * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() + * callback, take it into account here. That allows us to for example + * send 32 bits per channel to the codec, while only 16 of them carry + * audio payload. + * The clock ratio is given for a full period of data (both left and + * right channels), so it has to be divided by 2. + */ + if (dev->bclk_lrclk_ratio) + word_length = dev->bclk_lrclk_ratio / 2; + + /* mapping of the XSSZ bit-field as described in the datasheet */ + fmt = (word_length >> 1) - 1; + mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXSSZ(fmt), RXSSZ(0x0F)); mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, @@ -709,8 +745,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) if (stream == SNDRV_PCM_STREAM_PLAYBACK) { /* bit stream is MSB first with no delay */ /* DSP_B mode */ - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG, - AHCLKXE); mcasp_set_reg(dev->base + DAVINCI_MCASP_TXTDM_REG, mask); mcasp_set_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXORD); @@ -720,14 +754,10 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "playback tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); } else { /* bit stream is MSB first with no delay */ /* DSP_B mode */ mcasp_set_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXORD); - mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG, - AHCLKRE); mcasp_set_reg(dev->base + DAVINCI_MCASP_RXTDM_REG, mask); if ((dev->tdm_slots >= 2) && (dev->tdm_slots <= 32)) @@ -736,8 +766,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) else printk(KERN_ERR "capture tdm slot %d not supported\n", dev->tdm_slots); - - mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); } } @@ -800,19 +828,27 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_U8: case SNDRV_PCM_FORMAT_S8: dma_params->data_type = 1; - word_length = DAVINCI_AUDIO_WORD_8; + word_length = 8; break; case SNDRV_PCM_FORMAT_U16_LE: case SNDRV_PCM_FORMAT_S16_LE: dma_params->data_type = 2; - word_length = DAVINCI_AUDIO_WORD_16; + word_length = 16; break; + case SNDRV_PCM_FORMAT_U24_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + dma_params->data_type = 3; + word_length = 24; + break; + + case SNDRV_PCM_FORMAT_U24_LE: + case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_U32_LE: case SNDRV_PCM_FORMAT_S32_LE: dma_params->data_type = 4; - word_length = DAVINCI_AUDIO_WORD_32; + word_length = 32; break; default: @@ -880,13 +916,18 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { .trigger = davinci_mcasp_trigger, .hw_params = davinci_mcasp_hw_params, .set_fmt = davinci_mcasp_set_dai_fmt, - + .set_clkdiv = davinci_mcasp_set_clkdiv, + .set_sysclk = davinci_mcasp_set_sysclk, }; #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ SNDRV_PCM_FMTBIT_U8 | \ SNDRV_PCM_FMTBIT_S16_LE | \ SNDRV_PCM_FMTBIT_U16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_U24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_U24_3LE | \ SNDRV_PCM_FMTBIT_S32_LE | \ SNDRV_PCM_FMTBIT_U32_LE) @@ -1089,7 +1130,6 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dev->tdm_slots = pdata->tdm_slots; dev->num_serializer = pdata->num_serializer; dev->serial_dir = pdata->serial_dir; - dev->codec_fmt = pdata->codec_fmt; dev->version = pdata->version; dev->txnumevt = pdata->txnumevt; dev->rxnumevt = pdata->rxnumevt; @@ -1098,6 +1138,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_playback; dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + mem->start); @@ -1115,6 +1156,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) dma_data = &dev->dma_params[SNDRV_PCM_STREAM_CAPTURE]; dma_data->asp_chan_q = pdata->asp_chan_q; dma_data->ram_chan_q = pdata->ram_chan_q; + dma_data->sram_pool = pdata->sram_pool; dma_data->sram_size = pdata->sram_size_capture; dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + mem->start); diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 0de9ed6ce038..0edd3b5a37fd 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h @@ -23,26 +23,14 @@ #include "davinci-pcm.h" -#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_96000 +#define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 #define DAVINCI_MCASP_I2S_DAI 0 #define DAVINCI_MCASP_DIT_DAI 1 -enum { - DAVINCI_AUDIO_WORD_8 = 0, - DAVINCI_AUDIO_WORD_12, - DAVINCI_AUDIO_WORD_16, - DAVINCI_AUDIO_WORD_20, - DAVINCI_AUDIO_WORD_24, - DAVINCI_AUDIO_WORD_32, - DAVINCI_AUDIO_WORD_28, /* This is only valid for McASP */ -}; - struct davinci_audio_dev { struct davinci_pcm_dma_params dma_params[2]; void __iomem *base; - int sample_rate; struct device *dev; - unsigned int codec_fmt; /* McASP specific data */ int tdm_slots; @@ -50,6 +38,7 @@ struct davinci_audio_dev { u8 num_serializer; u8 *serial_dir; u8 version; + u8 bclk_lrclk_ratio; /* McASP FIFO related */ u8 txnumevt; diff --git a/sound/soc/davinci/davinci-pcm.c b/sound/soc/davinci/davinci-pcm.c index 93ea3bf567e1..afab81f844ae 100644 --- a/sound/soc/davinci/davinci-pcm.c +++ b/sound/soc/davinci/davinci-pcm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,6 @@ #include #include -#include #include "davinci-pcm.h" @@ -67,13 +67,9 @@ static struct snd_pcm_hardware pcm_hardware_playback = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME| SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -90,13 +86,9 @@ static struct snd_pcm_hardware pcm_hardware_capture = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_BATCH), .formats = DAVINCI_PCM_FMTBITS, - .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | - SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_KNOT), + .rates = SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT, .rate_min = 8000, - .rate_max = 96000, + .rate_max = 192000, .channels_min = 2, .channels_max = 384, .buffer_bytes_max = 128 * 1024, @@ -259,7 +251,9 @@ static void davinci_pcm_dma_irq(unsigned link, u16 ch_status, void *data) } } -static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, +#ifdef CONFIG_GENERIC_ALLOCATOR +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, struct snd_pcm_hardware *ppcm) { struct snd_dma_buffer *buf = &substream->dma_buffer; @@ -271,9 +265,10 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; ppcm->period_bytes_max = size; - iram_virt = sram_alloc(size, &iram_phys); + iram_virt = (void *)gen_pool_alloc(sram_pool, size); if (!iram_virt) goto exit1; + iram_phys = gen_pool_virt_to_phys(sram_pool, (unsigned)iram_virt); iram_dma = kzalloc(sizeof(*iram_dma), GFP_KERNEL); if (!iram_dma) goto exit2; @@ -285,11 +280,33 @@ static int allocate_sram(struct snd_pcm_substream *substream, unsigned size, return 0; exit2: if (iram_virt) - sram_free(iram_virt, size); + gen_pool_free(sram_pool, (unsigned)iram_virt, size); exit1: return -ENOMEM; } +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ + struct davinci_runtime_data *prtd = substream->runtime->private_data; + struct gen_pool *sram_pool = prtd->params->sram_pool; + + gen_pool_free(sram_pool, (unsigned) iram_dma->area, iram_dma->bytes); +} +#else +static int allocate_sram(struct snd_pcm_substream *substream, + struct gen_pool *sram_pool, unsigned size, + struct snd_pcm_hardware *ppcm) +{ + return 0; +} + +static void davinci_free_sram(struct snd_pcm_substream *substream, + struct snd_dma_buffer *iram_dma) +{ +} +#endif + /* * Only used with ping/pong. * This is called after runtime->dma_addr, period_bytes and data_type are valid @@ -676,7 +693,7 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) ppcm = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? &pcm_hardware_playback : &pcm_hardware_capture; - allocate_sram(substream, params->sram_size, ppcm); + allocate_sram(substream, params->sram_pool, params->sram_size, ppcm); snd_soc_set_runtime_hwparams(substream, ppcm); /* ensure that buffer size is a multiple of period size */ ret = snd_pcm_hw_constraint_integer(runtime, @@ -819,7 +836,7 @@ static void davinci_pcm_free(struct snd_pcm *pcm) buf->area = NULL; iram_dma = buf->private_data; if (iram_dma) { - sram_free(iram_dma->area, iram_dma->bytes); + davinci_free_sram(substream, iram_dma); kfree(iram_dma); } } diff --git a/sound/soc/davinci/davinci-pcm.h b/sound/soc/davinci/davinci-pcm.h index fc4d01cdd8c9..b6ef7039dd09 100644 --- a/sound/soc/davinci/davinci-pcm.h +++ b/sound/soc/davinci/davinci-pcm.h @@ -12,6 +12,7 @@ #ifndef _DAVINCI_PCM_H #define _DAVINCI_PCM_H +#include #include #include @@ -20,6 +21,7 @@ struct davinci_pcm_dma_params { unsigned short acnt; dma_addr_t dma_addr; /* device physical address for DMA */ unsigned sram_size; + struct gen_pool *sram_pool; /* SRAM gen_pool for ping pong */ enum dma_event_q asp_chan_q; /* event queue number for ASP channel */ enum dma_event_q ram_chan_q; /* event queue number for RAM channel */ unsigned char data_type; /* xfer data type */