sound/soc/au1x/psc-ac97.c

Source file repositories/reference/linux-study-clean/sound/soc/au1x/psc-ac97.c

File Facts

System
Linux kernel
Corpus path
sound/soc/au1x/psc-ac97.c
Extension
.c
Size
12662 bytes
Lines
487
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (stype == SNDRV_PCM_STREAM_PLAYBACK) {
			r &= ~PSC_AC97CFG_TXSLOT_MASK;
			r |= PSC_AC97CFG_TXSLOT_ENA(3);
			r |= PSC_AC97CFG_TXSLOT_ENA(4);
		} else {
			r &= ~PSC_AC97CFG_RXSLOT_MASK;
			r |= PSC_AC97CFG_RXSLOT_ENA(3);
			r |= PSC_AC97CFG_RXSLOT_ENA(4);
		}

		/* do we need to poke the hardware? */
		if (!(r ^ ro))
			goto out;

		/* ac97 engine is about to be disabled */
		mutex_lock(&pscdata->lock);

		/* disable AC97 device controller first... */
		__raw_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
		wmb(); /* drain writebuffer */

		/* ...wait for it... */
		t = 100;
		while ((__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) && --t)
			msleep(1);

		if (!t)
			printk(KERN_ERR "PSC-AC97: can't disable!\n");

		/* ...write config... */
		__raw_writel(r, AC97_CFG(pscdata));
		wmb(); /* drain writebuffer */

		/* ...enable the AC97 controller again... */
		__raw_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata));
		wmb(); /* drain writebuffer */

		/* ...and wait for ready bit */
		t = 100;
		while ((!(__raw_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && --t)
			msleep(1);

		if (!t)
			printk(KERN_ERR "PSC-AC97: can't enable!\n");

		mutex_unlock(&pscdata->lock);

		pscdata->cfg = r;
		pscdata->rate = params_rate(params);
	}

out:
	return 0;
}

static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
				int cmd, struct snd_soc_dai *dai)
{
	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
	int ret, stype = substream->stream;

	ret = 0;

	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
		__raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata));
		wmb(); /* drain writebuffer */
		__raw_writel(AC97PCR_START(stype), AC97_PCR(pscdata));
		wmb(); /* drain writebuffer */
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		__raw_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata));
		wmb(); /* drain writebuffer */

		while (__raw_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype))
			asm volatile ("nop");

		__raw_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata));
		wmb(); /* drain writebuffer */

		break;
	default:
		ret = -EINVAL;
	}
	return ret;
}

static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream,

Annotation

Implementation Notes