sound/soc/loongson/loongson1_ac97.c

Source file repositories/reference/linux-study-clean/sound/soc/loongson/loongson1_ac97.c

File Facts

System
Linux kernel
Corpus path
sound/soc/loongson/loongson1_ac97.c
Extension
.c
Size
12006 bytes
Lines
399
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

struct ls1x_ac97 {
	void __iomem *reg_base;
	struct regmap *regmap;
	dma_addr_t tx_dma_base;
	dma_addr_t rx_dma_base;
	struct snd_dmaengine_dai_dma_data capture_dma_data;
	struct snd_dmaengine_dai_dma_data playback_dma_data;
};

static struct ls1x_ac97 *ls1x_ac97;

static const struct regmap_config ls1x_ac97_regmap_config = {
	.reg_bits = 32,
	.val_bits = 32,
	.reg_stride = 4,
};

static void ls1x_ac97_reset(struct snd_ac97 *ac97)
{
	int val;

	regmap_write(ls1x_ac97->regmap, AC97_CSR, CSR_RST_FORCE);
	regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_CSR, val,
				 !(val & CSR_RESUME), 0, LS1X_AC97_TIMEOUT);
}

static void ls1x_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
{
	int tmp, ret;

	tmp = FIELD_PREP(CODEC_ADR, reg) | FIELD_PREP(CODEC_DAT, val);
	regmap_write(ls1x_ac97->regmap, AC97_CRAC, tmp);
	ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, tmp,
				       (tmp & CW_DONE), 0, LS1X_AC97_TIMEOUT);
	if (ret)
		pr_err("timeout on AC97 write! %d\n", ret);

	regmap_read(ls1x_ac97->regmap, AC97_INT_CW_CLR, &ret);
}

static unsigned short ls1x_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{
	int val, ret;

	val = CODEC_WR | FIELD_PREP(CODEC_ADR, reg);
	regmap_write(ls1x_ac97->regmap, AC97_CRAC, val);
	ret = regmap_read_poll_timeout(ls1x_ac97->regmap, AC97_INTRAW, val,
				       (val & CR_DONE), 0, LS1X_AC97_TIMEOUT);
	if (ret) {
		pr_err("timeout on AC97 read! %d\n", ret);
		return ret;
	}

	regmap_read(ls1x_ac97->regmap, AC97_INT_CR_CLR, &ret);
	regmap_read(ls1x_ac97->regmap, AC97_CRAC, &ret);

	return (ret & CODEC_DAT);
}

static void ls1x_ac97_init(struct snd_ac97 *ac97)
{
	writel(0, ls1x_ac97->reg_base + AC97_INTRAW);
	writel(0, ls1x_ac97->reg_base + AC97_INTM);

	/* Config output channels */
	regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0,
			   R_DMA_EN | R_FIFO_THRES | R_CH_EN |
			   L_DMA_EN | L_FIFO_THRES | L_CH_EN,
			   R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
			   L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);

	/* Config inputs channel */
	regmap_update_bits(ls1x_ac97->regmap, AC97_ICC,
			   M_DMA_EN | M_FIFO_THRES | M_CH_EN |
			   R_DMA_EN | R_FIFO_THRES | R_CH_EN |
			   L_DMA_EN | L_FIFO_THRES | L_CH_EN,
			   M_DMA_EN | M_FIFO_THRES_FULL | M_CH_EN |
			   R_DMA_EN | R_FIFO_THRES_EMPTY | R_CH_EN |
			   L_DMA_EN | L_FIFO_THRES_EMPTY | L_CH_EN);

	if (ac97->ext_id & AC97_EI_VRA) {
		regmap_update_bits(ls1x_ac97->regmap, AC97_OCC0, R_VSR | L_VSR, R_VSR | L_VSR);
		regmap_update_bits(ls1x_ac97->regmap, AC97_ICC, M_VSR, M_VSR);
	}
}

static struct snd_ac97_bus_ops ls1x_ac97_ops = {
	.reset	= ls1x_ac97_reset,
	.write	= ls1x_ac97_write,
	.read	= ls1x_ac97_read,

Annotation

Implementation Notes