We are trying to bring up TLV320AIC3100 Audio Codec for our custom board with i.MX8MP MPU from NXP. Our DT configuration for the CODEC is based on many others posted on this forum as can be seen below:
/
reg_audio_pwr: regulator-audio-pwr {
compatible = "regulator-fixed";
regulator-name = "audio-pwr";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
enable-active-high;
regulator-always-on;
};
reg_audio_pwr_1v8: regulator-audio-pwr {
compatible = "regulator-fixed";
regulator-name = "audio-pwr";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
enable-active-high;
regulator-always-on;
};
vdd_input: vdd_input {
compatible = "regulator-fixed";
regulator-name = "vdd_input";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
enable-active-high;
regulator-always-on;
};
sound-tlv320aic31xx {
compatible = "simple-audio-card";
simple-audio-card,name = "tlv320aic31xx-Codec";
simple-audio-card,format = "i2s";
simple-audio-card,frame-master = <&dailink_master>;//Which one is master
simple-audio-card,bitclock-master = <&dailink_master>;//which one is master
simple-audio-card,mclk-fs = <256>;//Multiplication rate between stream rate and codec mclk
simple-audio-card,widgets =
"Speaker", "External Speaker",
"Headphone", "Headphone Jack";
simple-audio-card,routing =
"External Speaker", "SPK",
"Headphone Jack", "HPL",
"Headphone Jack", "HPR";
dailink_master:simple-audio-card,cpu {
sound-dai = <&sai3>;
};
thecodec:simple-audio-card,codec {
sound-dai = <&tlv320aic3100>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>;
};
};
&i2c5 {
clock-frequency = <100000>; /* Lower clock speed for external bus. */
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c5>;
status = "okay";
tlv320aic3100: tlv320aic31xx@18 {
pinctrl-0 = <&pinctrl_dac_rst>;
pinctrl-names= "default";
compatible = "ti,tlv320aic3100";
#sound-dai-cells =<0>;
reg = <0x18>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>;
clock-names = "mclk1";
reset-gpios = <&gpio4 29 GPIO_ACTIVE_LOW>;
HPVDD-supply = <®_audio_pwr>;
SPRVDD-supply = <&vdd_input>;
SPLVDD-supply = <&vdd_input>;
AVDD-supply = <®_audio_pwr>;
IOVDD-supply = <®_audio_pwr>;
DVDD-supply = <®_audio_pwr_1v8>;
};
};
&sai3 {
#sound-dai-cells=<0>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_sai3>;
assigned-clocks = <&clk IMX8MP_CLK_SAI3>;
assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
assigned-clock-rates = <12288000>;
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_IPG>, <&clk IMX8MP_CLK_DUMMY>,
<&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>, <&clk IMX8MP_CLK_DUMMY>,
<&clk IMX8MP_CLK_DUMMY>;
clock-names = "bus", "mclk0", "mclk1", "mclk2", "mclk3";
fsl,sai-synchronous-rx;
status = "okay";
};
&iomuxc {
pinctrl_dac_rst: dacrstgrp {
fsl,pins = <
MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29 0x19 //DAC RST TODO
>;
};
pinctrl_sai3: sai3grp {
fsl,pins = <
MX8MP_IOMUXC_SAI3_TXFS__AUDIOMIX_SAI3_TX_SYNC 0xd6
MX8MP_IOMUXC_SAI3_TXC__AUDIOMIX_SAI3_TX_BCLK 0xd6
MX8MP_IOMUXC_SAI3_RXD__AUDIOMIX_SAI3_RX_DATA00 0xd6
MX8MP_IOMUXC_SAI3_TXD__AUDIOMIX_SAI3_TX_DATA00 0xd6
MX8MP_IOMUXC_SAI3_MCLK__AUDIOMIX_SAI3_MCLK 0xd6
>;
};
};
It seems like we are getting some kind of parsing error for the dai-links. We are receiving dai-links parsing error for the simple-card.c driver. We've patched the driver to see some logs, it seems like issue is based on this part of the driver:
static int __simple_for_each_link(struct asoc_simple_priv *priv,
struct link_info *li,
int (*func_noml)(struct asoc_simple_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top),
int (*func_dpcm)(struct asoc_simple_priv *priv,
struct device_node *np,
struct device_node *codec,
struct link_info *li, bool is_top))
{
struct device *dev = simple_priv_to_dev(priv);
struct device_node *top = dev->of_node;
struct device_node *node;
uintptr_t dpcm_selectable = (uintptr_t)of_device_get_match_data(dev);
bool is_top = 0;
int ret = 0;
printk("Entering __simple_for_each_link\n");
/* Check if it has dai-link */
node = of_get_child_by_name(top, PREFIX "dai-link");
if (!node) {
node = of_node_get(top);
is_top = 1;
printk("No Dai-Link?\n");
}
/* loop for all dai-link */
do {
struct asoc_simple_data adata;
struct device_node *codec;
struct device_node *plat;
struct device_node *np;
int num = of_get_child_count(node);
printk("Inside do-while loop\n");
/* get codec */
codec = of_get_child_by_name(node, is_top ?
PREFIX "codec" : "codec");
if (!codec) {
ret = -ENODEV;
goto error;
}
/* get platform */
plat = of_get_child_by_name(node, is_top ?
PREFIX "plat" : "plat");
/* get convert-xxx property */
memset(&adata, 0, sizeof(adata));
for_each_child_of_node(node, np)
simple_parse_convert(dev, np, &adata);
/* loop for all CPU/Codec node */
for_each_child_of_node(node, np) {
printk("Inside for_each_child_of_node loop\n");
if (plat == np)
continue;
/*
* It is DPCM
* if it has many CPUs,
* or has convert-xxx property
*/
if (dpcm_selectable &&
(num > 2 || asoc_simple_is_convert_required(&adata))) {
/*
* np
* |1(CPU)|0(Codec) li->cpu
* CPU |Pass |return
* Codec |return|Pass
*/
if (li->cpu != (np == codec))
ret = func_dpcm(priv, np, codec, li, is_top);
/* else normal sound */
} else {
/*
* np
* |1(CPU)|0(Codec) li->cpu
* CPU |Pass |return
* Codec |return|return
*/
if (li->cpu && (np != codec))
ret = func_noml(priv, np, codec, li, is_top);
}
if (ret < 0) {
of_node_put(codec);
of_node_put(plat);
of_node_put(np);
goto error;
}
}
of_node_put(codec);
node = of_get_next_child(top, node);
} while (!is_top && node);
error:
of_node_put(node);
printk("Exiting __simple_for_each_link with ret: %d\n", ret);
return ret;
}
We've enabled the driver from the kernel config: here is the boot log with patched driver:
imx8mp-lpddr4-evk login: [ 14.563842] probing for the TLV320AIC [ 14.567547] Entering __simple_for_each_link [ 14.571790] No Dai-Link? [ 14.574337] Inside do-while loop [ 14.577629] Inside for_each_child_of_node loop [ 14.582111] Inside for_each_child_of_node loop [ 14.586592] Exiting __simple_for_each_link with ret: 0 [ 14.591763] Entering __simple_for_each_link [ 14.595972] No Dai-Link? [ 14.598509] Inside do-while loop [ 14.601772] Inside for_each_child_of_node loop [ 14.606235] Inside for_each_child_of_node loop [ 14.610715] Exiting __simple_for_each_link with ret: 0 [ 14.615960] Entering __simple_for_each_link [ 14.620193] No Dai-Link? [ 14.622730] Inside do-while loop [ 14.625987] Inside for_each_child_of_node loop [ 14.630481] Exiting __simple_for_each_link with ret: -517 [ 14.635887] li->cpu val:1 ret val:-517 [ 14.639641] parsing error occured on dai links parsing link [ 14.645324] parse error: -517
With the i2cdetect command, we can see 0x18 area is populated, but when we observe the i2c bus when this command is used, we can't see 0x18, we see output below which is not 0x18:

We don't see any movements for the MCLK, and our SAI interface is observed as deferred from the console:
root@imx8mp-lpddr4-evk:~# cat /sys/kernel/debug/devices_deferred 30c30000.sai sound-bt-sco asoc-simple-card: parse error sound-tlv320aic31xx asoc-simple-card: parse error 30c20000.sai
Both nodes seemed to be deferred, interface and codec. Is the issue due to the interface or codec configration. How can we debug this issue? Any idea is appreciated! Thank you in advance!
Best Regards!
