|
@@ -49,6 +49,8 @@ struct omap_mcbsp_data {
|
|
|
*/
|
|
|
int active;
|
|
|
int configured;
|
|
|
+ unsigned int in_freq;
|
|
|
+ int clk_div;
|
|
|
};
|
|
|
|
|
|
#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
|
|
@@ -257,7 +259,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
|
|
|
int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
|
|
|
unsigned long port;
|
|
|
- unsigned int format;
|
|
|
+ unsigned int format, div, framesize, master;
|
|
|
|
|
|
if (cpu_class_is_omap1()) {
|
|
|
dma = omap1_dma_reqs[bus_id][substream->stream];
|
|
@@ -294,28 +296,19 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
|
|
|
format = mcbsp_data->fmt & SND_SOC_DAIFMT_FORMAT_MASK;
|
|
|
wpf = channels = params_channels(params);
|
|
|
- switch (channels) {
|
|
|
- case 2:
|
|
|
- if (format == SND_SOC_DAIFMT_I2S) {
|
|
|
- /* Use dual-phase frames */
|
|
|
- regs->rcr2 |= RPHASE;
|
|
|
- regs->xcr2 |= XPHASE;
|
|
|
- /* Set 1 word per (McBSP) frame for phase1 and phase2 */
|
|
|
- wpf--;
|
|
|
- regs->rcr2 |= RFRLEN2(wpf - 1);
|
|
|
- regs->xcr2 |= XFRLEN2(wpf - 1);
|
|
|
- }
|
|
|
- case 1:
|
|
|
- case 4:
|
|
|
- /* Set word per (McBSP) frame for phase1 */
|
|
|
- regs->rcr1 |= RFRLEN1(wpf - 1);
|
|
|
- regs->xcr1 |= XFRLEN1(wpf - 1);
|
|
|
- break;
|
|
|
- default:
|
|
|
- /* Unsupported number of channels */
|
|
|
- return -EINVAL;
|
|
|
+ if (channels == 2 && format == SND_SOC_DAIFMT_I2S) {
|
|
|
+ /* Use dual-phase frames */
|
|
|
+ regs->rcr2 |= RPHASE;
|
|
|
+ regs->xcr2 |= XPHASE;
|
|
|
+ /* Set 1 word per (McBSP) frame for phase1 and phase2 */
|
|
|
+ wpf--;
|
|
|
+ regs->rcr2 |= RFRLEN2(wpf - 1);
|
|
|
+ regs->xcr2 |= XFRLEN2(wpf - 1);
|
|
|
}
|
|
|
|
|
|
+ regs->rcr1 |= RFRLEN1(wpf - 1);
|
|
|
+ regs->xcr1 |= XFRLEN1(wpf - 1);
|
|
|
+
|
|
|
switch (params_format(params)) {
|
|
|
case SNDRV_PCM_FORMAT_S16_LE:
|
|
|
/* Set word lengths */
|
|
@@ -330,15 +323,30 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
|
|
|
+ /* In McBSP master modes, FRAME (i.e. sample rate) is generated
|
|
|
+ * by _counting_ BCLKs. Calculate frame size in BCLKs */
|
|
|
+ master = mcbsp_data->fmt & SND_SOC_DAIFMT_MASTER_MASK;
|
|
|
+ if (master == SND_SOC_DAIFMT_CBS_CFS) {
|
|
|
+ div = mcbsp_data->clk_div ? mcbsp_data->clk_div : 1;
|
|
|
+ framesize = (mcbsp_data->in_freq / div) / params_rate(params);
|
|
|
+
|
|
|
+ if (framesize < wlen * channels) {
|
|
|
+ printk(KERN_ERR "%s: not enough bandwidth for desired rate and "
|
|
|
+ "channels\n", __func__);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ framesize = wlen * channels;
|
|
|
+
|
|
|
/* Set FS period and length in terms of bit clock periods */
|
|
|
switch (format) {
|
|
|
case SND_SOC_DAIFMT_I2S:
|
|
|
- regs->srgr2 |= FPER(wlen * channels - 1);
|
|
|
- regs->srgr1 |= FWID(wlen - 1);
|
|
|
+ regs->srgr2 |= FPER(framesize - 1);
|
|
|
+ regs->srgr1 |= FWID((framesize >> 1) - 1);
|
|
|
break;
|
|
|
case SND_SOC_DAIFMT_DSP_A:
|
|
|
case SND_SOC_DAIFMT_DSP_B:
|
|
|
- regs->srgr2 |= FPER(wlen * channels - 1);
|
|
|
+ regs->srgr2 |= FPER(framesize - 1);
|
|
|
regs->srgr1 |= FWID(0);
|
|
|
break;
|
|
|
}
|
|
@@ -454,6 +462,7 @@ static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai,
|
|
|
if (div_id != OMAP_MCBSP_CLKGDV)
|
|
|
return -ENODEV;
|
|
|
|
|
|
+ mcbsp_data->clk_div = div;
|
|
|
regs->srgr1 |= CLKGDV(div - 1);
|
|
|
|
|
|
return 0;
|
|
@@ -554,6 +563,8 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
|
|
|
struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
|
|
|
int err = 0;
|
|
|
|
|
|
+ mcbsp_data->in_freq = freq;
|
|
|
+
|
|
|
switch (clk_id) {
|
|
|
case OMAP_MCBSP_SYSCLK_CLK:
|
|
|
regs->srgr2 |= CLKSM;
|
|
@@ -598,13 +609,13 @@ static struct snd_soc_dai_ops omap_mcbsp_dai_ops = {
|
|
|
.id = (link_id), \
|
|
|
.playback = { \
|
|
|
.channels_min = 1, \
|
|
|
- .channels_max = 4, \
|
|
|
+ .channels_max = 16, \
|
|
|
.rates = OMAP_MCBSP_RATES, \
|
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
|
|
|
}, \
|
|
|
.capture = { \
|
|
|
.channels_min = 1, \
|
|
|
- .channels_max = 4, \
|
|
|
+ .channels_max = 16, \
|
|
|
.rates = OMAP_MCBSP_RATES, \
|
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE, \
|
|
|
}, \
|