drivers/media/rc/ir-hix5hd2.c

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

File Facts

System
Linux kernel
Corpus path
drivers/media/rc/ir-hix5hd2.c
Extension
.c
Size
9846 bytes
Lines
405
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 hix5hd2_soc_data {
	u32 clk_reg;
	u32 flags;
};

static const struct hix5hd2_soc_data hix5hd2_data = {
	.clk_reg = 0x48,
};

static const struct hix5hd2_soc_data hi3796cv300_data = {
	.clk_reg = 0x60,
	.flags = HIX5HD2_FLAG_EXTRA_ENABLE,
};

struct hix5hd2_ir_priv {
	int			irq;
	void __iomem		*base;
	struct device		*dev;
	struct rc_dev		*rdev;
	struct regmap		*regmap;
	struct clk		*clock;
	unsigned long		rate;
	const struct hix5hd2_soc_data *socdata;
};

static int hix5hd2_ir_clk_enable(struct hix5hd2_ir_priv *dev, bool on)
{
	u32 clk_reg = dev->socdata->clk_reg;
	u32 val;
	int ret = 0;

	if (dev->regmap) {
		regmap_read(dev->regmap, clk_reg, &val);
		if (on) {
			val &= ~IR_CLK_RESET;
			val |= IR_CLK_ENABLE;
		} else {
			val &= ~IR_CLK_ENABLE;
			val |= IR_CLK_RESET;
		}
		regmap_write(dev->regmap, clk_reg, val);
	} else {
		if (on)
			ret = clk_prepare_enable(dev->clock);
		else
			clk_disable_unprepare(dev->clock);
	}
	return ret;
}

static inline void hix5hd2_ir_enable(struct hix5hd2_ir_priv *priv)
{
	u32 val = IR_ENABLE_EN;

	if (priv->socdata->flags & HIX5HD2_FLAG_EXTRA_ENABLE)
		val |= IR_ENABLE_EN_EXTRA;

	writel_relaxed(val, priv->base + IR_ENABLE);
}

static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv)
{
	int timeout = 10000;
	u32 val, rate;

	hix5hd2_ir_enable(priv);

	while (readl_relaxed(priv->base + IR_BUSY)) {
		if (timeout--) {
			udelay(1);
		} else {
			dev_err(priv->dev, "IR_BUSY timeout\n");
			return -ETIMEDOUT;
		}
	}

	/* Now only support raw mode, with symbol start from low to high */
	rate = DIV_ROUND_CLOSEST(priv->rate, 1000000);
	val = IR_CFG_SYMBOL_MAXWIDTH & IR_CFG_WIDTH_MASK << IR_CFG_WIDTH_SHIFT;
	val |= IR_CFG_SYMBOL_FMT & IR_CFG_FORMAT_MASK << IR_CFG_FORMAT_SHIFT;
	val |= (IR_CFG_INT_THRESHOLD - 1) & IR_CFG_INT_LEVEL_MASK
	       << IR_CFG_INT_LEVEL_SHIFT;
	val |= IR_CFG_MODE_RAW;
	val |= (rate - 1) & IR_CFG_FREQ_MASK << IR_CFG_FREQ_SHIFT;
	writel_relaxed(val, priv->base + IR_CONFIG);

	writel_relaxed(0x00, priv->base + IR_INTM);
	/* write arbitrary value to start  */
	writel_relaxed(0x01, priv->base + IR_START);
	return 0;

Annotation

Implementation Notes