Skip to content

Commit

Permalink
ASoC: ti: davinci-mcasp: Fix DIT mode support
Browse files Browse the repository at this point in the history
[ Upstream commit bbdd3f4 ]

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>
Link: https://lore.kernel.org/r/20210705194249.2385-2-peter.ujfalusi@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
ujfalusi authored and gregkh committed Sep 18, 2021
1 parent 47a0982 commit a022ed4
Showing 1 changed file with 129 additions and 21 deletions.
150 changes: 129 additions & 21 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 @@ -842,10 +861,16 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
u8 tx_ser = 0;
u8 rx_ser = 0;
u8 slots = mcasp->tdm_slots;
u8 max_active_serializers = (channels + slots - 1) / slots;
u8 max_rx_serializers, max_tx_serializers;
u8 max_active_serializers, max_rx_serializers, max_tx_serializers;
int active_serializers, numevt;
u32 reg;

/* In DIT mode we only allow maximum of one serializers for now */
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
max_active_serializers = 1;
else
max_active_serializers = (channels + slots - 1) / slots;

/* Default configuration */
if (mcasp->version < MCASP_VERSION_3)
mcasp_set_bits(mcasp, DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT);
Expand Down Expand Up @@ -1031,16 +1056,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 +1076,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 +1107,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 +1259,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 +1626,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 +1756,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 +1977,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 a022ed4

Please sign in to comment.