sound/soc/atmel/mchp-spdiftx.c

Source file repositories/reference/linux-study-clean/sound/soc/atmel/mchp-spdiftx.c

File Facts

System
Linux kernel
Corpus path
sound/soc/atmel/mchp-spdiftx.c
Extension
.c
Size
23543 bytes
Lines
904
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 mchp_spdiftx_mixer_control {
	unsigned char				ch_stat[SPDIFTX_CS_BITS / 8];
	unsigned char				user_data[SPDIFTX_UD_BITS / 8];
	spinlock_t				lock; /* exclusive access to control data */
};

struct mchp_spdiftx_dev {
	struct mchp_spdiftx_mixer_control	control;
	struct snd_dmaengine_dai_dma_data	playback;
	struct device				*dev;
	struct regmap				*regmap;
	struct clk				*pclk;
	struct clk				*gclk;
	unsigned int				fmt;
	unsigned int				suspend_irq;
};

static inline int mchp_spdiftx_is_running(struct mchp_spdiftx_dev *dev)
{
	u32 mr;

	regmap_read(dev->regmap, SPDIFTX_MR, &mr);
	return !!(mr & SPDIFTX_MR_TXEN_ENABLE);
}

static void mchp_spdiftx_channel_status_write(struct mchp_spdiftx_dev *dev)
{
	struct mchp_spdiftx_mixer_control *ctrl = &dev->control;
	u32 val;
	int i;

	for (i = 0; i < ARRAY_SIZE(ctrl->ch_stat) / 4; i++) {
		val = (ctrl->ch_stat[(i * 4) + 0] << 0) |
		      (ctrl->ch_stat[(i * 4) + 1] << 8) |
		      (ctrl->ch_stat[(i * 4) + 2] << 16) |
		      (ctrl->ch_stat[(i * 4) + 3] << 24);

		regmap_write(dev->regmap, SPDIFTX_CH1S(i), val);
	}
}

static void mchp_spdiftx_user_data_write(struct mchp_spdiftx_dev *dev)
{
	struct mchp_spdiftx_mixer_control *ctrl = &dev->control;
	u32 val;
	int i;

	for (i = 0; i < ARRAY_SIZE(ctrl->user_data) / 4; i++) {
		val = (ctrl->user_data[(i * 4) + 0] << 0) |
		      (ctrl->user_data[(i * 4) + 1] << 8) |
		      (ctrl->user_data[(i * 4) + 2] << 16) |
		      (ctrl->user_data[(i * 4) + 3] << 24);

		regmap_write(dev->regmap, SPDIFTX_CH1UD(i), val);
	}
}

static irqreturn_t mchp_spdiftx_interrupt(int irq, void *dev_id)
{
	struct mchp_spdiftx_dev *dev = dev_id;
	struct mchp_spdiftx_mixer_control *ctrl = &dev->control;
	u32 sr, imr, pending, idr = 0;

	regmap_read(dev->regmap, SPDIFTX_ISR, &sr);
	regmap_read(dev->regmap, SPDIFTX_IMR, &imr);
	pending = sr & imr;

	if (!pending)
		return IRQ_NONE;

	if (pending & SPDIFTX_IR_TXUDR) {
		dev_warn(dev->dev, "underflow detected\n");
		idr |= SPDIFTX_IR_TXUDR;
	}

	if (pending & SPDIFTX_IR_TXOVR) {
		dev_warn(dev->dev, "overflow detected\n");
		idr |= SPDIFTX_IR_TXOVR;
	}

	if (pending & SPDIFTX_IR_UDRDY) {
		spin_lock(&ctrl->lock);
		mchp_spdiftx_user_data_write(dev);
		spin_unlock(&ctrl->lock);
		idr |= SPDIFTX_IR_UDRDY;
	}

	if (pending & SPDIFTX_IR_CSRDY) {
		spin_lock(&ctrl->lock);
		mchp_spdiftx_channel_status_write(dev);

Annotation

Implementation Notes