drivers/media/cec/platform/meson/ao-cec.c

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

File Facts

System
Linux kernel
Corpus path
drivers/media/cec/platform/meson/ao-cec.c
Extension
.c
Size
18616 bytes
Lines
729
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 meson_ao_cec_device {
	struct platform_device		*pdev;
	void __iomem			*base;
	struct clk			*core;
	spinlock_t			cec_reg_lock;
	struct cec_notifier		*notify;
	struct cec_adapter		*adap;
	struct cec_msg			rx_msg;
};

#define writel_bits_relaxed(mask, val, addr) \
	writel_relaxed((readl_relaxed(addr) & ~(mask)) | (val), addr)

static inline int meson_ao_cec_wait_busy(struct meson_ao_cec_device *ao_cec)
{
	ktime_t timeout = ktime_add_us(ktime_get(), 5000);

	while (readl_relaxed(ao_cec->base + CEC_RW_REG) & CEC_RW_BUS_BUSY) {
		if (ktime_compare(ktime_get(), timeout) > 0)
			return -ETIMEDOUT;
	}

	return 0;
}

static void meson_ao_cec_read(struct meson_ao_cec_device *ao_cec,
			     unsigned long address, u8 *data,
			     int *res)
{
	unsigned long flags;
	u32 reg = FIELD_PREP(CEC_RW_ADDR, address);
	int ret = 0;

	if (res && *res)
		return;

	spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);

	ret = meson_ao_cec_wait_busy(ao_cec);
	if (ret)
		goto read_out;

	writel_relaxed(reg, ao_cec->base + CEC_RW_REG);

	ret = meson_ao_cec_wait_busy(ao_cec);
	if (ret)
		goto read_out;

	*data = FIELD_GET(CEC_RW_RD_DATA,
			  readl_relaxed(ao_cec->base + CEC_RW_REG));

read_out:
	spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);

	if (res)
		*res = ret;
}

static void meson_ao_cec_write(struct meson_ao_cec_device *ao_cec,
			       unsigned long address, u8 data,
			       int *res)
{
	unsigned long flags;
	u32 reg = FIELD_PREP(CEC_RW_ADDR, address) |
		  FIELD_PREP(CEC_RW_WR_DATA, data) |
		  CEC_RW_WRITE_EN;
	int ret = 0;

	if (res && *res)
		return;

	spin_lock_irqsave(&ao_cec->cec_reg_lock, flags);

	ret = meson_ao_cec_wait_busy(ao_cec);
	if (ret)
		goto write_out;

	writel_relaxed(reg, ao_cec->base + CEC_RW_REG);

write_out:
	spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags);

	if (res)
		*res = ret;
}

static inline void meson_ao_cec_irq_setup(struct meson_ao_cec_device *ao_cec,
				      bool enable)
{
	u32 cfg = CEC_INTR_TX | CEC_INTR_RX;

Annotation

Implementation Notes