mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-22 20:23:57 +08:00
ASoC: atmel_ssc_dai: if not provided, default to sensible dividers
When this driver masters BCLK and/or LRCLK, and noone has stated differently, assume that all the bits of a frame are used. This relieves the cpu dai users from the duty to fill in the dividers for the common case. Signed-off-by: Peter Rosin <peda@axentia.se> Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
28549313da
commit
a85787edaa
@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
|
||||
ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST));
|
||||
/* Clear the SSC dividers */
|
||||
ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0;
|
||||
ssc_p->forced_divider = 0;
|
||||
}
|
||||
spin_unlock_irq(&ssc_p->lock);
|
||||
|
||||
@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
|
||||
else
|
||||
if (div != ssc_p->cmr_div)
|
||||
return -EBUSY;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV);
|
||||
break;
|
||||
|
||||
case ATMEL_SSC_TCMR_PERIOD:
|
||||
ssc_p->tcmr_period = div;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD);
|
||||
break;
|
||||
|
||||
case ATMEL_SSC_RCMR_PERIOD:
|
||||
ssc_p->rcmr_period = div;
|
||||
ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is the cpu-dai master of the frame clock? */
|
||||
static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p)
|
||||
{
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Is the cpu-dai master of the bit clock? */
|
||||
static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p)
|
||||
{
|
||||
switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure the SSC.
|
||||
*/
|
||||
@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
u32 tfmr, rfmr, tcmr, rcmr;
|
||||
int ret;
|
||||
int fslen, fslen_ext;
|
||||
u32 cmr_div;
|
||||
u32 tcmr_period;
|
||||
u32 rcmr_period;
|
||||
|
||||
/*
|
||||
* Currently, there is only one set of dma params for
|
||||
@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
else
|
||||
dir = 1;
|
||||
|
||||
/*
|
||||
* If the cpu dai should provide BCLK, but noone has provided the
|
||||
* divider needed for that to work, fall back to something sensible.
|
||||
*/
|
||||
cmr_div = ssc_p->cmr_div;
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) &&
|
||||
atmel_ssc_cbs(ssc_p)) {
|
||||
int bclk_rate = snd_soc_params_to_bclk(params);
|
||||
|
||||
if (bclk_rate < 0) {
|
||||
dev_err(dai->dev, "unable to calculate cmr_div: %d\n",
|
||||
bclk_rate);
|
||||
return bclk_rate;
|
||||
}
|
||||
|
||||
cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the cpu dai should provide LRCLK, but noone has provided the
|
||||
* dividers needed for that to work, fall back to something sensible.
|
||||
*/
|
||||
tcmr_period = ssc_p->tcmr_period;
|
||||
rcmr_period = ssc_p->rcmr_period;
|
||||
if (atmel_ssc_cfs(ssc_p)) {
|
||||
int frame_size = snd_soc_params_to_frame_size(params);
|
||||
|
||||
if (frame_size < 0) {
|
||||
dev_err(dai->dev,
|
||||
"unable to calculate tx/rx cmr_period: %d\n",
|
||||
frame_size);
|
||||
return frame_size;
|
||||
}
|
||||
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD)))
|
||||
tcmr_period = frame_size / 2 - 1;
|
||||
if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD)))
|
||||
rcmr_period = frame_size / 2 - 1;
|
||||
}
|
||||
|
||||
dma_params = ssc_p->dma_params[dir];
|
||||
|
||||
channels = params_channels(params);
|
||||
@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
fslen_ext = (bits - 1) / 16;
|
||||
fslen = (bits - 1) % 16;
|
||||
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(RCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, START_DELAY)
|
||||
| SSC_BF(TCMR_START, SSC_START_FALLING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
* MCK divider, and the BCLK signal is output
|
||||
* on the SSC TK line.
|
||||
*/
|
||||
rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period)
|
||||
rcmr = SSC_BF(RCMR_PERIOD, rcmr_period)
|
||||
| SSC_BF(RCMR_STTDLY, 1)
|
||||
| SSC_BF(RCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(RCMR_CKI, SSC_CKI_RISING)
|
||||
@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
| SSC_BF(RFMR_LOOP, 0)
|
||||
| SSC_BF(RFMR_DATLEN, (bits - 1));
|
||||
|
||||
tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period)
|
||||
tcmr = SSC_BF(TCMR_PERIOD, tcmr_period)
|
||||
| SSC_BF(TCMR_STTDLY, 1)
|
||||
| SSC_BF(TCMR_START, SSC_START_RISING_RF)
|
||||
| SSC_BF(TCMR_CKI, SSC_CKI_FALLING)
|
||||
@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
/* set SSC clock mode register */
|
||||
ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div);
|
||||
ssc_writel(ssc_p->ssc->regs, CMR, cmr_div);
|
||||
|
||||
/* set receive clock mode and format */
|
||||
ssc_writel(ssc_p->ssc->regs, RCMR, rcmr);
|
||||
|
@ -113,6 +113,7 @@ struct atmel_ssc_info {
|
||||
unsigned short cmr_div;
|
||||
unsigned short tcmr_period;
|
||||
unsigned short rcmr_period;
|
||||
unsigned int forced_divider;
|
||||
struct atmel_pcm_dma_params *dma_params[2];
|
||||
struct atmel_ssc_state ssc_state;
|
||||
unsigned long mck_rate;
|
||||
|
Loading…
Reference in New Issue
Block a user