drivers/media/cec/platform/stm32/stm32-cec.c

Source file repositories/reference/linux-study-clean/drivers/media/cec/platform/stm32/stm32-cec.c

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/platform/stm32/stm32-cec.c
Extension
.c
Size
9012 bytes
Lines
376
Domain
Driver Families
Bucket
drivers/media
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 stm32_cec {
	struct cec_adapter	*adap;
	struct device		*dev;
	struct clk		*clk_cec;
	struct clk		*clk_hdmi_cec;
	struct reset_control	*rstc;
	struct regmap		*regmap;
	int			irq;
	u32			irq_status;
	struct cec_msg		rx_msg;
	struct cec_msg		tx_msg;
	int			tx_cnt;
};

static void cec_hw_init(struct stm32_cec *cec)
{
	regmap_update_bits(cec->regmap, CEC_CR, TXEOM | TXSOM | CECEN, 0);

	regmap_update_bits(cec->regmap, CEC_IER, ALL_TX_IT | ALL_RX_IT,
			   ALL_TX_IT | ALL_RX_IT);

	regmap_update_bits(cec->regmap, CEC_CFGR, FULL_CFG, FULL_CFG);
}

static void stm32_tx_done(struct stm32_cec *cec, u32 status)
{
	if (status & (TXERR | TXUDR)) {
		cec_transmit_done(cec->adap, CEC_TX_STATUS_ERROR,
				  0, 0, 0, 1);
		return;
	}

	if (status & ARBLST) {
		cec_transmit_done(cec->adap, CEC_TX_STATUS_ARB_LOST,
				  1, 0, 0, 0);
		return;
	}

	if (status & TXACKE) {
		cec_transmit_done(cec->adap, CEC_TX_STATUS_NACK,
				  0, 1, 0, 0);
		return;
	}

	if (cec->irq_status & TXBR) {
		/* send next byte */
		if (cec->tx_cnt < cec->tx_msg.len)
			regmap_write(cec->regmap, CEC_TXDR,
				     cec->tx_msg.msg[cec->tx_cnt++]);

		/* TXEOM is set to command transmission of the last byte */
		if (cec->tx_cnt == cec->tx_msg.len)
			regmap_update_bits(cec->regmap, CEC_CR, TXEOM, TXEOM);
	}

	if (cec->irq_status & TXEND)
		cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0, 0);
}

static void stm32_rx_done(struct stm32_cec *cec, u32 status)
{
	if (cec->irq_status & (RXACKE | RXOVR)) {
		cec->rx_msg.len = 0;
		return;
	}

	if (cec->irq_status & RXBR) {
		u32 val;

		regmap_read(cec->regmap, CEC_RXDR, &val);
		cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
	}

	if (cec->irq_status & RXEND) {
		cec_received_msg(cec->adap, &cec->rx_msg);
		cec->rx_msg.len = 0;
	}
}

static irqreturn_t stm32_cec_irq_thread(int irq, void *arg)
{
	struct stm32_cec *cec = arg;

	if (cec->irq_status & ALL_TX_IT)
		stm32_tx_done(cec, cec->irq_status);

	if (cec->irq_status & ALL_RX_IT)
		stm32_rx_done(cec, cec->irq_status);

	cec->irq_status = 0;

Annotation

Implementation Notes