sound/arm/aaci.c

Source file repositories/reference/linux-study-clean/sound/arm/aaci.c

File Facts

System
Linux kernel
Corpus path
sound/arm/aaci.c
Extension
.c
Size
24587 bytes
Lines
1068
Domain
Driver Families
Bucket
sound/arm
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 (v == reg) {
			v = readl(aaci->base + AACI_SL2RX) >> 4;
			break;
		} else if (--retries) {
			dev_warn(&aaci->dev->dev,
				 "ac97 read back fail.  retry\n");
			continue;
		} else {
			dev_warn(&aaci->dev->dev,
				"wrong ac97 register read back (%x != %x)\n",
				v, reg);
			v = ~0;
		}
	} while (retries);
	return v;
}

static inline void
aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
{
	u32 val;
	int timeout = 5000;

	do {
		udelay(1);
		val = readl(aacirun->base + AACI_SR);
	} while (val & mask && timeout--);
}



/*
 * Interrupt support.
 */
static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
{
	if (mask & ISR_ORINTR) {
		dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel);
		writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR);
	}

	if (mask & ISR_RXTOINTR) {
		dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel);
		writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR);
	}

	if (mask & ISR_RXINTR) {
		struct aaci_runtime *aacirun = &aaci->capture;
		bool period_elapsed = false;
		void *ptr;

		if (!aacirun->substream || !aacirun->start) {
			dev_warn(&aaci->dev->dev, "RX interrupt???\n");
			writel(0, aacirun->base + AACI_IE);
			return;
		}

		scoped_guard(spinlock, &aacirun->lock) {
			ptr = aacirun->ptr;
			do {
				unsigned int len = aacirun->fifo_bytes;
				u32 val;

				if (aacirun->bytes <= 0) {
					aacirun->bytes += aacirun->period;
					period_elapsed = true;
				}
				if (!(aacirun->cr & CR_EN))
					break;

				val = readl(aacirun->base + AACI_SR);
				if (!(val & SR_RXHF))
					break;
				if (!(val & SR_RXFF))
					len >>= 1;

				aacirun->bytes -= len;

				/* reading 16 bytes at a time */
				for( ; len > 0; len -= 16) {
					asm(
					    "ldmia	%1, {r0, r1, r2, r3}\n\t"
					    "stmia	%0!, {r0, r1, r2, r3}"
					    : "+r" (ptr)
					    : "r" (aacirun->fifo)
					    : "r0", "r1", "r2", "r3", "cc");

					if (ptr >= aacirun->end)
						ptr = aacirun->start;
				}

Annotation

Implementation Notes