Skip to content

Commit

Permalink
ASoC: ti: davinci-mcasp: Fix DIT mode support
Browse files Browse the repository at this point in the history
The DIT mode support has not been tested due to lack of platform where it
can be tested.
To be able to use the McASP on OMAP4/5 (only supporting DIT mode) we need
to have DIT mode working in the McASP driver on a know platform.
After hacking around (on BBW, mcasp1.axr1 can be routed out for this) it
appeared that DIT mode is broken.

This patch fixes it up and 16/24 bit audio works along with passthrough,
but I have only tested with DTS example and test files.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@gmail.com>
  • Loading branch information
ujfalusi authored and intel-lab-lkp committed Jul 4, 2021
1 parent fd96f1a commit 085675d
Showing 1 changed file with 122 additions and 20 deletions.
142 changes: 122 additions & 20 deletions sound/soc/ti/davinci-mcasp.c
Expand Up @@ -83,6 +83,8 @@ struct davinci_mcasp {
struct snd_pcm_substream *substreams[2];
unsigned int dai_fmt;

u32 iec958_status;

/* Audio can not be enabled due to missing parameter(s) */
bool missing_audio_param;

Expand Down Expand Up @@ -757,6 +759,9 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);

if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
return 0;

dev_dbg(mcasp->dev,
"%s() tx_mask 0x%08x rx_mask 0x%08x slots %d width %d\n",
__func__, tx_mask, rx_mask, slots, slot_width);
Expand Down Expand Up @@ -827,6 +832,20 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, RXROT(rx_rotate),
RXROT(7));
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXMASK_REG, mask);
} else {
/*
* according to the TRM it should be TXROT=0, this one works:
* 16 bit to 23-8 (TXROT=6, rotate 24 bits)
* 24 bit to 23-0 (TXROT=0, rotate 0 bits)
*
* TXROT = 0 only works with 24bit samples
*/
tx_rotate = (sample_width / 4 + 2) & 0x7;

mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(tx_rotate),
TXROT(7));
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSSZ(15),
TXSSZ(0x0F));
}

mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, mask);
Expand All @@ -841,7 +860,7 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
int i;
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 slots = mcasp->tdm_slots;
u8 slots = mcasp->op_mode == DAVINCI_MCASP_DIT_MODE ? 384 : mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
u8 max_rx_serializers, max_tx_serializers;
int active_serializers, numevt;
Expand Down Expand Up @@ -1031,16 +1050,18 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
unsigned int rate)
{
u32 cs_value = 0;
u8 *cs_bytes = (u8*) &cs_value;
u8 *cs_bytes = (u8 *)&mcasp->iec958_status;

/* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0
and LSB first */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXROT(6) | TXSSZ(15));
if (!mcasp->dat_port)
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);
else
mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, TXSEL);

/* Set TX frame synch : DIT Mode, 1 bit width, internal, rising edge */
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, AFSXE | FSXMOD(0x180));

mcasp_set_reg(mcasp, DAVINCI_MCASP_TXMASK_REG, 0xFFFF);

/* Set the TX tdm : for all the slots */
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, 0xFFFFFFFF);

Expand All @@ -1049,16 +1070,8 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,

mcasp_clr_bits(mcasp, DAVINCI_MCASP_XEVTCTL_REG, TXDATADMADIS);

/* Only 44100 and 48000 are valid, both have the same setting */
mcasp_set_bits(mcasp, DAVINCI_MCASP_AHCLKXCTL_REG, AHCLKXDIV(3));

/* Enable the DIT */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);

/* Set S/PDIF channel status bits */
cs_bytes[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
cs_bytes[1] = IEC958_AES1_CON_PCM_CODER;

cs_bytes[3] &= ~IEC958_AES3_CON_FS;
switch (rate) {
case 22050:
cs_bytes[3] |= IEC958_AES3_CON_FS_22050;
Expand Down Expand Up @@ -1088,12 +1101,15 @@ static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp,
cs_bytes[3] |= IEC958_AES3_CON_FS_192000;
break;
default:
printk(KERN_WARNING "unsupported sampling rate: %d\n", rate);
dev_err(mcasp->dev, "unsupported sampling rate: %d\n", rate);
return -EINVAL;
}

mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, cs_value);
mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, cs_value);
mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRA_REG, mcasp->iec958_status);
mcasp_set_reg(mcasp, DAVINCI_MCASP_DITCSRB_REG, mcasp->iec958_status);

/* Enable the DIT */
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN);

return 0;
}
Expand Down Expand Up @@ -1237,12 +1253,18 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
int slots = mcasp->tdm_slots;
int rate = params_rate(params);
int sbits = params_width(params);
unsigned int bclk_target;

if (mcasp->slot_width)
sbits = mcasp->slot_width;

if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
bclk_target = rate * sbits * slots;
else
bclk_target = rate * 128;

davinci_mcasp_calc_clk_div(mcasp, mcasp->sysclk_freq,
rate * sbits * slots, true);
bclk_target, true);
}

ret = mcasp_common_hw_param(mcasp, substream->stream,
Expand Down Expand Up @@ -1598,13 +1620,90 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
.set_tdm_slot = davinci_mcasp_set_tdm_slot,
};

static int davinci_mcasp_iec958_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
uinfo->count = 1;

return 0;
}

static int davinci_mcasp_iec958_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uctl)
{
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);

memcpy(uctl->value.iec958.status, &mcasp->iec958_status,
sizeof(mcasp->iec958_status));

return 0;
}

static int davinci_mcasp_iec958_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uctl)
{
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);

memcpy(&mcasp->iec958_status, uctl->value.iec958.status,
sizeof(mcasp->iec958_status));

return 0;
}

static int davinci_mcasp_iec958_con_mask_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);

memset(ucontrol->value.iec958.status, 0xff, sizeof(mcasp->iec958_status));
return 0;
}

static const struct snd_kcontrol_new davinci_mcasp_iec958_ctls[] = {
{
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_VOLATILE),
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
.info = davinci_mcasp_iec958_info,
.get = davinci_mcasp_iec958_get,
.put = davinci_mcasp_iec958_put,
}, {
.access = SNDRV_CTL_ELEM_ACCESS_READ,
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
.info = davinci_mcasp_iec958_info,
.get = davinci_mcasp_iec958_con_mask_get,
},
};

static void davinci_mcasp_init_iec958_status(struct davinci_mcasp *mcasp)
{
unsigned char *cs = (u8 *)&mcasp->iec958_status;

cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
cs[1] = IEC958_AES1_CON_PCM_CODER;
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
}

static int davinci_mcasp_dai_probe(struct snd_soc_dai *dai)
{
struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai);

dai->playback_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK];
dai->capture_dma_data = &mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE];

if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) {
davinci_mcasp_init_iec958_status(mcasp);
snd_soc_add_dai_controls(dai, davinci_mcasp_iec958_ctls,
ARRAY_SIZE(davinci_mcasp_iec958_ctls));
}

return 0;
}

Expand Down Expand Up @@ -1651,7 +1750,8 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
.channels_min = 1,
.channels_max = 384,
.rates = DAVINCI_MCASP_RATES,
.formats = DAVINCI_MCASP_PCM_FMTS,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE,
},
.ops = &davinci_mcasp_dai_ops,
},
Expand Down Expand Up @@ -1871,6 +1971,8 @@ static int davinci_mcasp_get_config(struct davinci_mcasp *mcasp,
} else {
mcasp->tdm_slots = pdata->tdm_slots;
}
} else {
mcasp->tdm_slots = 32;
}

mcasp->num_serializer = pdata->num_serializer;
Expand Down

0 comments on commit 085675d

Please sign in to comment.