Hello,
I've been working with Grant Likely exploring an existing issue with resetting the AC97 system on the pcm030 board. The easiest way to produce the problem is by power cycling the board and seeing if the AC97 and wm9712 codec show up in /sys/bus/ac97.
I wanted to share with you folks to make sure there's not something else going on that I should be looking at, and if the results I'm seeing seem to make sense.
A bit of background for those not familiar with this area of the code:
When the board powers up, a reset() message is sent to the wm9712 codec driver which then calls the AC97 driver to perform a cold reset. The AC97 driver performs the cold reset by yanking the reset line on the AC97 link. The AC97 driver also calls warm_reset() after the cold reset is complete. Earlier the warm_reset() call was added in the AC97 cold_reset() routine to attempt to solve this bug, but it appears to not completely solve the issue. After the reset the wm9712 driver attempts to read a register. If the register value is verified the driver assumes the reset was a success, otherwise it flags an error.
The code for the routines we're using is included here for reference.
------- code snippets ------- static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) { if (try_warm && soc_ac97_ops.warm_reset) { soc_ac97_ops.warm_reset(codec->ac97); if (ac97_read(codec, 0) == wm9712_reg[0]) return 1; }
soc_ac97_ops.reset(codec->ac97); if (ac97_read(codec, 0) != wm9712_reg[0]) goto err; return 0;
err: printk(KERN_ERR "WM9712 AC97 reset failed\n"); return -EIO; }
static void psc_ac97_cold_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
/* Do a cold reset */ out_8(®s->op1, MPC52xx_PSC_OP_RES); udelay(10); out_8(®s->op0, MPC52xx_PSC_OP_RES); udelay(50);
psc_ac97_warm_reset(ac97); }
static void psc_ac97_warm_reset(struct snd_ac97 *ac97) { struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
out_be32(®s->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR); udelay(3); out_be32(®s->sicr, psc_dma->sicr); } ------- end code snippets -------
I've explored the following possibilities: 1. SDATAOUT or SYNC lines were non-zero during reset, putting the codec chip into a test mode. 2. Perhaps the cold_reset is not necessary and the warm_reset is all that is needed 3. The delay between the cold reset and the warm reset was not long enough.
Possibility #1
I added some test code to force the pcm030 board to use gpio instead of the ac97 to perform the reset. This way the SDATAOUT and the SYNC signals can be forced to 0 while resetting. What I discovered is that this didn't seem to make a difference. I don't know if these signals might contain uninitialized values on power up. Should I still consider this as a potential problem, or is this pretty much a non-issue?
Possibility #2
I tried taking out the cold reset code in the AC97 driver in hopes that perhaps the hardware would come up in a good state on its own. This didn't work at all. I put the cold reset code back in.
Possibility #3
I stumbled upon this when I added a printk to make sure I correctly understood the flow of control. With the printk in place, the problem would go away. So instead I increased the length of time in the udelay() call right before the call to warm_reset(). I've empirically found that delaying 1ms (udelay(50) -> udelay(1000)) seems to avoid the problem. I'm not sure why this delay is necessary, or if it makes sense for the hardware to need this much time to come out of the cold reset.
Thanks for your help.
Cheers, - John