drivers/media/rc/meson-ir-tx.c

Source file repositories/reference/linux-study-clean/drivers/media/rc/meson-ir-tx.c

File Facts

System
Linux kernel
Corpus path
drivers/media/rc/meson-ir-tx.c
Extension
.c
Size
9317 bytes
Lines
389
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_irtx {
	struct device *dev;
	void __iomem *reg_base;
	u32 *buf;
	unsigned int buf_len;
	unsigned int buf_head;
	unsigned int carrier;
	unsigned int duty_cycle;
	/* Locks buf */
	spinlock_t lock;
	struct completion completion;
	unsigned long clk_rate;
};

static void meson_irtx_set_mod(struct meson_irtx *ir)
{
	unsigned int cnt = DIV_ROUND_CLOSEST(ir->clk_rate, ir->carrier);
	unsigned int pulse_cnt = DIV_ROUND_CLOSEST(cnt * ir->duty_cycle, 100);
	unsigned int space_cnt = cnt - pulse_cnt;

	dev_dbg(ir->dev, "F_mod = %uHz, T_mod = %luns, duty_cycle = %u%%\n",
		ir->carrier, NSEC_PER_SEC / ir->clk_rate * cnt,
		100 * pulse_cnt / cnt);

	writel(IRB_MOD_COUNT(pulse_cnt, space_cnt),
	       ir->reg_base + IRB_ADDR1);
}

static void meson_irtx_setup(struct meson_irtx *ir, unsigned int clk_nr)
{
	/*
	 * Disable the TX, set modulator clock tick and set initialize
	 * output to be high. Set up carrier frequency and duty cycle. Then
	 * unset initialize output. Enable FIFO interrupt, set FIFO interrupt
	 * threshold. Finally, enable the transmitter back.
	 */
	writel(~IRB_ENABLE & (IRB_MOD_CLK(clk_nr) | IRB_INIT_HIGH),
	       ir->reg_base + IRB_ADDR0);
	meson_irtx_set_mod(ir);
	writel(readl(ir->reg_base + IRB_ADDR0) & ~IRB_INIT_HIGH,
	       ir->reg_base + IRB_ADDR0);
	writel(IRB_FIFO_IRQ_ENABLE | MIRTX_FIFO_THD,
	       ir->reg_base + IRB_ADDR3);
	writel(readl(ir->reg_base + IRB_ADDR0) | IRB_ENABLE,
	       ir->reg_base + IRB_ADDR0);
}

static u32 meson_irtx_prepare_pulse(struct meson_irtx *ir, unsigned int time)
{
	unsigned int delay;
	unsigned int tb = IRB_TB_MOD_CLK;
	unsigned int tb_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, ir->carrier);

	delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;

	return ((IRB_WRITE_FIFO | IRB_MOD_ENABLE) | tb | delay);
}

static u32 meson_irtx_prepare_space(struct meson_irtx *ir, unsigned int time)
{
	unsigned int delay;
	unsigned int tb = IRB_TB_100US;
	unsigned int tb_us = 100;

	if (time <= IRB_MAX_DELAY) {
		tb = IRB_TB_1US;
		tb_us = 1;
	} else if (time <= 10 * IRB_MAX_DELAY) {
		tb = IRB_TB_10US;
		tb_us = 10;
	} else if (time <= 100 * IRB_MAX_DELAY) {
		tb = IRB_TB_100US;
		tb_us = 100;
	}

	delay = (DIV_ROUND_CLOSEST(time, tb_us) - 1) & IRB_DELAY_MASK;

	return ((IRB_WRITE_FIFO & ~IRB_MOD_ENABLE) | tb | delay);
}

static void meson_irtx_send_buffer(struct meson_irtx *ir)
{
	unsigned int nr = 0;
	unsigned int max_fifo_level = IRB_FIFO_LEN - MIRTX_FIFO_THD;

	while (ir->buf_head < ir->buf_len && nr < max_fifo_level) {
		writel(ir->buf[ir->buf_head], ir->reg_base + IRB_ADDR2);

		ir->buf_head++;
		nr++;

Annotation

Implementation Notes