[alsa-devel] AC97 on pcm030 board with WM9712 codec

John Bonesio bones at secretlab.ca
Tue Jul 21 01:29:11 CEST 2009


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(&regs->op1, MPC52xx_PSC_OP_RES);
	udelay(10);
	out_8(&regs->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(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
	udelay(3);
	out_be32(&regs->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



More information about the Alsa-devel mailing list