drivers/media/cec/platform/sti/stih-cec.c

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

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/platform/sti/stih-cec.c
Extension
.c
Size
10196 bytes
Lines
398
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 stih_cec {
	struct cec_adapter	*adap;
	struct device		*dev;
	struct clk		*clk;
	void __iomem		*regs;
	int			irq;
	u32			irq_status;
	struct cec_notifier	*notifier;
};

static int stih_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
	struct stih_cec *cec = cec_get_drvdata(adap);

	if (enable) {
		/* The doc says (input TCLK_PERIOD * CEC_CLK_DIV) = 0.1ms */
		unsigned long clk_freq = clk_get_rate(cec->clk);
		u32 cec_clk_div = clk_freq / 10000;

		writel(cec_clk_div, cec->regs + CEC_CLK_DIV);

		/* Configuration of the durations activating a timeout */
		writel(CEC_SBIT_TOUT_47MS | (CEC_DBIT_TOUT_28MS << 4),
		       cec->regs + CEC_BIT_TOUT_THRESH);

		/* Configuration of the smallest allowed duration for pulses */
		writel(CEC_BIT_LPULSE_03MS | CEC_BIT_HPULSE_03MS,
		       cec->regs + CEC_BIT_PULSE_THRESH);

		/* Minimum received bit period threshold */
		writel(BIT(5) | BIT(7), cec->regs + CEC_TX_CTRL);

		/* Configuration of transceiver data arrays */
		writel(CEC_TX_ARRAY_EN | CEC_RX_ARRAY_EN | CEC_TX_STOP_ON_NACK,
		       cec->regs + CEC_DATA_ARRAY_CTRL);

		/* Configuration of the control bits for CEC Transceiver */
		writel(CEC_IN_FILTER_EN | CEC_EN | CEC_RX_RESET_EN,
		       cec->regs + CEC_CTRL);

		/* Clear logical addresses */
		writel(0, cec->regs + CEC_ADDR_TABLE);

		/* Clear the status register */
		writel(0x0, cec->regs + CEC_STATUS);

		/* Enable the interrupts */
		writel(CEC_TX_DONE_IRQ_EN | CEC_RX_DONE_IRQ_EN |
		       CEC_RX_SOM_IRQ_EN | CEC_RX_EOM_IRQ_EN |
		       CEC_ERROR_IRQ_EN,
		       cec->regs + CEC_IRQ_CTRL);

	} else {
		/* Clear logical addresses */
		writel(0, cec->regs + CEC_ADDR_TABLE);

		/* Clear the status register */
		writel(0x0, cec->regs + CEC_STATUS);

		/* Disable the interrupts */
		writel(0, cec->regs + CEC_IRQ_CTRL);
	}

	return 0;
}

static int stih_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr)
{
	struct stih_cec *cec = cec_get_drvdata(adap);
	u32 reg = readl(cec->regs + CEC_ADDR_TABLE);

	reg |= 1 << logical_addr;

	if (logical_addr == CEC_LOG_ADDR_INVALID)
		reg = 0;

	writel(reg, cec->regs + CEC_ADDR_TABLE);

	return 0;
}

static int stih_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
				  u32 signal_free_time, struct cec_msg *msg)
{
	struct stih_cec *cec = cec_get_drvdata(adap);
	int i;

	/* Copy message into registers */
	for (i = 0; i < msg->len; i++)
		writeb(msg->msg[i], cec->regs + CEC_TX_DATA_BASE + i);

Annotation

Implementation Notes