Hi All,
We have a new AM335x based design that utilizes a wm8737 codec. After reviewing a number of the related forum posts for new codec integration, the Sitara Linux Audio DAC Example, AM335x Audio Driver's Guide and a steep learning curve it appears much is in place. We are now at point when attempting arecord we see the following error
arecord: pcm_read:2031: read error: Input/output error
We also built the user land record app suggested in the AM335x Audio Driver's Guide and it fails with the same i/o error. The driver for the wm8737 has been part of the 3.1x kernel. The codec is configured for master / I2S mode and the pins are muxed and shown below. Probing the signals look generally correct, the wm8737 is in master mode, the I2C communication is functional and a register dump shows the codec is in the expected state.
At this point the focus is on the machine layer and am looking for some input on how to proceed with debugging this. I am not sure it I have the wiget routing correct. Any Input would be desired. Thanks, Tom
HW ==========================================
MCASP0 <--> wm8737
MCASP0_AHCLKR (out) <--> 12MHZ (input)
MCASP0_ACLKR (in) <--> MIC_BCLK (output)
MCASP0_FSR (in) <--> MIC_FRAME (output)
MCASP0_AXR1 (in) <--> MIC_DATA (output)
Device Tree ================================
sound {
compatible = "ti,wm8737-evm-audio";
ti,model = "AM335x-EVM";
ti,audio-codec = <&wm8737>;
ti,mcasp-controller = <&mcasp0>;
ti,codec-clock-rate = <12000000>;
ti,audio-routing =
"LINPUT1", "Line In",
"RINPUT1", "Line In";
clock-names = "mclk";
};
am335x_evm_audio_pins: am335x_evm_audio_pins {
pinctrl-single,pins = <
0x1ac ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (A14) mcasp0_ahclkx.mcasp0_ahclkx */
0x19c ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (C12) mcasp0_ahclkr.mcasp0_ahclkr */
0x190 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (A13) mcasp0_aclkx.mcasp0_aclkx */
0x194 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (B13) mcasp0_fsx.mcasp0_fsx */
0x1a0 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (B12) mcasp0_aclkr.mcasp0_aclkr */
0x1a4 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (C13) mcasp0_fsr.mcasp0_fsr */
0x198 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (D12) mcasp0_axr0.mcasp0_axr0 */
0x1a8 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (D13) mcasp0_axr1.mcasp0_axr1 */
/* GPIO I2C tranceiver enable */
0x28 ( PIN_OUTPUT | MUX_MODE7 ) /* (T11) gpmc_ad10.gpio0[26] */
>;
};
am335x_evm_audio_pins_sleep: am335x_evm_audio_pins_sleep {
pinctrl-single,pins = <
0x1ac ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (A14) mcasp0_ahclkx.mcasp0_ahclkx */
0x19c ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (C12) mcasp0_ahclkr.mcasp0_ahclkr */
0x190 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (A13) mcasp0_aclkx.mcasp0_aclkx */
0x194 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (B13) mcasp0_fsx.mcasp0_fsx */
0x1a0 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (B12) mcasp0_aclkr.mcasp0_aclkr */
0x1a4 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (C13) mcasp0_fsr.mcasp0_fsr */
0x198 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (D12) mcasp0_axr0.mcasp0_axr0 */
0x1a8 ( PIN_INPUT_PULLDOWN | MUX_MODE0 ) /* (D13) mcasp0_axr1.mcasp0_axr1 */
/* GPIO I2C tranceiver enable */
0x28 ( PIN_OUTPUT | MUX_MODE7 ) /* (T11) gpmc_ad10.gpio0[26] */
>;
};
&mcasp0 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&am335x_evm_audio_pins>;
pinctrl-1 = <&am335x_evm_audio_pins_sleep>;
status = "okay";
op-mode = <0>; /* MCASP_IIS_MODE */
tdm-slots = <2>;
/* 4 serializers */
serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
0 2 0 0
>;
tx-num-evt = <32>;
rx-num-evt = <32>;
};
MACHINE LAYER ================
/* add for wm8737 configure hw_params */
static struct snd_soc_ops wm8737_ops = {
.startup = evm_startup,
.shutdown = evm_shutdown,
// XXX conflicts with wm8737_hw_params in the driver .hw_params = wm8737_hw_params,
};
/* wm8737 widgets */
static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = {
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_LINE("Line In", NULL),
};
/* also added the following */
static int evm_wm8737_init(struct snd_soc_pcm_runtime *rtd) {
struct snd_soc_card *card = rtd->card;
struct snd_soc_codec *codec = rtd->codec;
struct device_node *np = card->dev->of_node;
int ret;
unsigned sysclk;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *soc_card = codec->card;
/* Add davinci-evm specific widgets */
snd_soc_dapm_new_controls(&card->dapm, wm8737_dapm_widgets,
ARRAY_SIZE(wm8737_dapm_widgets));
printk("TR_DBG: evm_wm8737_init of_node [%p]\n", np);
if (np) {
ret = snd_soc_of_parse_audio_routing(card, "ti,audio-routing");
if (ret)
return ret;
} else {
/* Set up davinci-evm specific audio path audio_map */
snd_soc_dapm_add_routes(&card->dapm, audio_map,
ARRAY_SIZE(audio_map));
}
snd_soc_dapm_nc_pin(&codec->dapm, "LINPUT1");
snd_soc_dapm_nc_pin(&codec->dapm, "RINPUT1");
/* wm8737 moved clock init to here since the hw_params conflicted with the wm8737 driver */
#if 1
sysclk = ((struct snd_soc_card_drvdata_davinci *)
snd_soc_card_get_drvdata(soc_card))->sysclk;
printk("TR_DBG: evm_wm8737_init sysclk [%u]\n", sysclk);
ret = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0) {
dev_err(codec_dai->platform->dev, "TR_DBG evm_wm8737_init failed to set codec_dai clock: %d.\n",ret);
return ret;
}
ret = snd_soc_dai_set_sysclk(cpu_dai, 0, sysclk, SND_SOC_CLOCK_OUT);
if (ret < 0) {
dev_err(codec_dai->platform->dev, "TR_DBG evm_wm8737_init failed to set cpu_dai clock: %d.\n",ret);
return ret;
}
#endif
}