Hello All,
We are getting I/O read error while reading audio data using McASP0.
We have developed a custom board for our client which is having adv 7611 decoder chip from analog devices. We have ad7611 is connected to McASP0 via FPGA. I did all the relevant changes in my kernel to add support of I2S audio as below:
1. In board file (arch/arm/mach-omap2/board-ti8148evm.c):
static u8 ti8148_iis_serializer_direction[] = {
#if 0
TX_MODE, RX_MODE, INACTIVE_MODE, INACTIVE_MODE,
#else
RX_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
#endif
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE, INACTIVE_MODE,
};
static struct snd_platform_data ti8148_evm_snd_data = {
#if 0
.tx_dma_offset = 0x46800000,
.rx_dma_offset = 0x46800000,
#else
.tx_dma_offset = 0x46000000,
.rx_dma_offset = 0x46000000,
#endif
.op_mode = DAVINCI_MCASP_IIS_MODE,
.num_serializer = ARRAY_SIZE(ti8148_iis_serializer_direction),
.tdm_slots = 2,
.serial_dir = ti8148_iis_serializer_direction,
#if 0
.asp_chan_q = EVENTQ_2,
#else
.asp_chan_q = EVENTQ_0,
#endif
.version = MCASP_VERSION_2,
#if 0
.txnumevt = 1,
.rxnumevt = 1,
#else
.txnumevt = 0,
.rxnumevt = 1,
#endif
};
2. In device file (arch/arm/mach-omap2/devices.c):
static struct resource ti81xx_mcasp_resource[] = {
#if 0
{
.name = "mcasp",
.start = TI81XX_ASP2_BASE,
.end = TI81XX_ASP2_BASE + (SZ_1K * 12) - 1,
.flags = IORESOURCE_MEM,
},
/* TX event */
{
.start = TI81XX_DMA_MCASP2_AXEVT,
.end = TI81XX_DMA_MCASP2_AXEVT,
.flags = IORESOURCE_DMA,
},
/* RX event */
{
.start = TI81XX_DMA_MCASP2_AREVT,
.end = TI81XX_DMA_MCASP2_AREVT,
.flags = IORESOURCE_DMA,
},
#else
{
.name = "mcasp",
.start = TI81XX_ASP0_BASE,
.end = TI81XX_ASP0_BASE + (SZ_1K * 12) - 1,
.flags = IORESOURCE_MEM,
},
/* TX event */
{
.start = TI81XX_DMA_MCASP0_AXEVT,
.end = TI81XX_DMA_MCASP0_AXEVT,
.flags = IORESOURCE_DMA,
},
/* RX event */
{
.start = TI81XX_DMA_MCASP0_AREVT,
.end = TI81XX_DMA_MCASP0_AREVT,
.flags = IORESOURCE_DMA,
},
#endif
void __init ti81xx_register_mcasp(int id, struct snd_platform_data *pdata)
{
if (machine_is_ti8168evm() || machine_is_ti8148evm()) {
#if 0
ti81xx_mcasp_device.id = 2;
#else
ti81xx_mcasp_device.id = id;
#endif
ti81xx_mcasp_device.resource = ti81xx_mcasp_resource;
ti81xx_mcasp_device.num_resources = ARRAY_SIZE(ti81xx_mcasp_resource);
} else if (machine_is_dm385evm()) {
ti81xx_mcasp_device.id = 1;
ti81xx_mcasp_device.resource = dm385_mcasp_resource;
ti81xx_mcasp_device.num_resources = ARRAY_SIZE(dm385_mcasp_resource);
} else {
pr_err("%s: platform not supported\n", __func__);
return;
}
ti81xx_mcasp_device.dev.platform_data = pdata;
platform_device_register(&ti81xx_mcasp_device);
}
3. In a platform file (sound/soc/davinci/davinci-evm.c):
#if 0
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
#else
#define AUDIO_FORMAT (SND_SOC_DAIFMT_I2S | \
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_NB_IF)
#endif
I updated evm_hw_params as below as per my requirements (as i had just a dummy decoder driver which is doing nothing except glue)
static int evm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int ret;
/* set cpu DAI configuration */
ret = snd_soc_dai_set_fmt(cpu_dai, AD7611_AUDIO_FORMAT);
if (ret < 0)
return ret;
/* Set rx clock */
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, 0, SND_SOC_CLOCK_IN);
return 0;
}
static struct snd_soc_dai_link ti81xx_evm_dai[] = {
#if 0
{
.name = "TLV320AIC3X",
.stream_name = "AIC3X",
.codec_dai_name = "tlv320aic3x-hifi",
.codec_name = "tlv320aic3x-codec.1-0018",
.platform_name = "davinci-pcm-audio",
.init = evm_aic3x_init,
.ops = &evm_ops,
},
#endif
{
.name = "ad7611",
.stream_name = "AD7611",
.cpu_dai_name = "davinci-mcasp.0",
.platform_name = "davinci-pcm-audio",
.codec_dai_name = "ad7611-codec-dai",
.codec_name = "ad7611-codec.1-004c",
.ops = &evm_ops,
}
}
static void ti81xx_evm_dai_fixup(void)
{
if (machine_is_ti8168evm() || machine_is_ti8148evm()) {
#if 0
ti81xx_evm_dai[0].cpu_dai_name = "davinci-mcasp.2";
#else
ti81xx_evm_dai[0].cpu_dai_name = "davinci-mcasp.0";
#endif
} else if (machine_is_dm385evm()) {
ti81xx_evm_dai[0].cpu_dai_name = "davinci-mcasp.1";
} else {
ti81xx_evm_dai[0].cpu_dai_name = NULL;
}
}
4. In mac-asp driver (sound/soc/davinci/davinci-mcasp.c):
We added support of I2S in function davinci_mcasp_set_dai_fmt as below:
#if 1
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
mcasp_set_bits(base + DAVINCI_MCASP_RXFMT_REG, FSRDLY(1));
mcasp_set_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
mcasp_set_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
break;
case SND_SOC_DAIFMT_DSP_B:
mcasp_clr_bits(base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR);
mcasp_clr_bits(base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR);
break;
default:
return -EINVAL;
}
mcasp_clr_bits(base + DAVINCI_MCASP_ACLKXCTL_REG, TX_ASYNC);
#endif
And added below function to set cpu dai clock
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);
printk("###HRV: %s called\n", __func__);
if (clk_id == 0) {
/* Set RX clock */
if (dir == SND_SOC_CLOCK_IN) {
mcasp_clr_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRE);
} else {
mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKRE);
mcasp_set_bits(dev->base +
DAVINCI_MCASP_AHCLKRCTL_REG,
AHCLKXDIV(0x0c));
}
} else {
/* Set TX clock */
if (dir == SND_SOC_CLOCK_OUT) {
mcasp_set_bits(dev->base + DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXE);
mcasp_set_bits(dev->base +
DAVINCI_MCASP_AHCLKXCTL_REG,
AHCLKXDIV(0x0c));
} else {
return -EINVAL;
}
}
return 0;
}
Do you missing any changes in software ?
We are able to see bit-clock and word clock along with the data on via of processor. So FPGA is doing nothing... it just bypasses whatever is available from the AD7611 decoder chip. And we configuring AD7611 using i2c. and it shows audio packet detection and other read-only registers which confirms AD7611 is configured correctly.
So can anyone help me in resolving my issue ?
Regards,
Hitesh