[PATCH 2/3] ASoC: AC97: S3C: Add controller driver

Mark Brown broonie at opensource.wolfsonmicro.com
Tue Jan 26 05:47:23 EST 2010


On Tue, Jan 26, 2010 at 02:51:40PM +0900, jassisinghbrar at gmail.com wrote:

This looks good overall, just a few smallish issues:

> +static void s3c_ac97_activate(struct snd_ac97 *ac97)
> +{
> +	u32 ac_glbctrl, stat;
> +
> +	stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7;
> +	switch (stat) {
> +	case S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE:
> +		return;
> +	case S3C_AC97_GLBSTAT_MAINSTATE_READY:
> +	case S3C_AC97_GLBSTAT_MAINSTATE_INIT:
> +		break;
> +	default:
> +		s3c_ac97_cold_reset(ac97);
> +		s3c_ac97_warm_reset(ac97);
> +		break;
> +	}

This automatic cold and warm reset looks a bit fishy - obviously if this
code path ever gets hit in normal operation then it's going to seriously
disrupt things since it'll reset the CODEC registers.  A warm reset by
itself wouldn't be a problem but I'd rather see explicit cold resets in
the callers where that's required.

> +	ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +	ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON;
> +	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +	msleep(1);

This also looks a bit odd, ACLINKON sounds like bringing up the link
which is what a warm reset does.

> +	INIT_COMPLETION(s3c_ac97.done);
> +
> +	if (!wait_for_completion_timeout(&s3c_ac97.done, HZ))
> +		printk(KERN_ERR "AC97: Unable to activate!");

This looks racy - the INIT_COMPLETION() happens after all the hardware
configuration which suggests that if you're unlucky the event which
should trigger the completion will have happened before the init.  A
bunch of interrupts arriving at an inconvenient time could trigger this,
for example.

The same idiom appears in the register reads and writes.

> +	if (addr != reg)
> +		printk(KERN_ERR "s3c-ac97: req addr = %02x,"
> +				" rep addr = %02x\n", reg, addr);

Please don't split error messages over multiple lines, it makes grepping
for them harder.

> +static irqreturn_t s3c_ac97_irq(int irq, void *dev_id)
> +{
> +	u32 ac_glbctrl, ac_glbstat;
> +
> +	ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT);
> +
> +	if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) {
> +
> +		ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +		ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE;
> +		writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +
> +		ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +		ac_glbctrl |= (1<<30); /* Clear interrupt */
> +		writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
> +
> +		complete(&s3c_ac97.done);
> +	}
> +
> +	return IRQ_HANDLED;
> +}

You should only be returning IRQ_HANDLED if you actually handled an
interrupt here.

> +#define S3C_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
> +		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
> +		SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
> +		SNDRV_PCM_RATE_48000)

SNDRV_PCM_RATE_8000_48000.

> +		.capture = {
> +			.stream_name = "AC97 Capture",
> +			/* NOTE: If the codec ouputs just one slot,
> +			 * it *seems* our AC97 controller reads the only
> +			 * valid slot(if either 3 or 4) for PCM-In.
> +			 * For such cases, we record Mono.
> +			 */

This seems like unsurprising behaviour for an AC97 controller - the slot
validity information is there for just this purpose.  I'd just remove
the comment as a result.

> +		.capture = {
> +			.stream_name = "AC97 Mic Capture",
> +			.channels_min = 1,
> +			/* NOTE: If the codec(like WM9713) can't ouput just
> +			 * one slot, it *seems* our AC97 controller reads
> +			 * two slots(if one of them is Slot-6) for MIC also.
> +			 * For such cases, we record Stereo.
> +			 */

Similarly here.

> +	if (ac97_pdata->cfg_gpio(pdev)) {
> +		dev_err(&pdev->dev, "Unable to configure gpio\n");
> +		ret = -EINVAL;
> +		goto lb3;
> +	}

Should really check for the function being non-NULL here.

> +lb5:
> +	free_irq(irq_res->start, NULL);

Perhaps a better name than 'lb' - err, or fail or something.  lb means
nothing to me at least.

> +	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +	if (irq_res)
> +		free_irq(irq_res->start, NULL);

This should never get called if the resources aren't allocated.



More information about the linux-arm-kernel mailing list