sound/soc/au1x/ac97c.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/au1x/ac97c.c
Extension
.c
Size
8445 bytes
Lines
347
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 (!tmo) {
			pr_debug("ac97rd timeout #1\n");
			goto next;
		}

		WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);

		/* stupid errata: data is only valid for 21us, so
		 * poll, Forrest, poll...
		 */
		tmo = 0x10000;
		while ((RD(ctx, AC97_STATUS) & STAT_CP) && --tmo)
			asm volatile ("nop");
		data = RD(ctx, AC97_CMDRESP);

		if (!tmo)
			pr_debug("ac97rd timeout #2\n");

next:
		mutex_unlock(&ctx->lock);
	} while (--retry && !tmo);

	pr_debug("AC97RD %04x %04lx %d\n", r, data, retry);

	return retry ? data & 0xffff : 0xffff;
}

static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
				 unsigned short v)
{
	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
	unsigned int tmo, retry;

	retry = AC97_RW_RETRIES;
	do {
		mutex_lock(&ctx->lock);

		for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
			udelay(21);
		if (!tmo) {
			pr_debug("ac97wr timeout #1\n");
			goto next;
		}

		WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));

		for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
			udelay(21);
		if (!tmo)
			pr_debug("ac97wr timeout #2\n");
next:
		mutex_unlock(&ctx->lock);
	} while (--retry && !tmo);

	pr_debug("AC97WR %04x %04x %d\n", r, v, retry);
}

static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
{
	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);

	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
	msleep(20);
	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
	WR(ctx, AC97_CONFIG, ctx->cfg);
}

static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
{
	struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
	int i;

	WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
	msleep(500);
	WR(ctx, AC97_CONFIG, ctx->cfg);

	/* wait for codec ready */
	i = 50;
	while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
		msleep(20);
	if (!i)
		printk(KERN_ERR "ac97c: codec not ready after cold reset\n");
}

/* AC97 controller operations */
static struct snd_ac97_bus_ops ac97c_bus_ops = {
	.read		= au1xac97c_ac97_read,
	.write		= au1xac97c_ac97_write,
	.reset		= au1xac97c_ac97_cold_reset,
	.warm_reset	= au1xac97c_ac97_warm_reset,

Annotation

Implementation Notes