drivers/clk/ingenic/tcu.c

Source file repositories/reference/linux-study-clean/drivers/clk/ingenic/tcu.c

File Facts

System
Linux kernel
Corpus path
drivers/clk/ingenic/tcu.c
Extension
.c
Size
13115 bytes
Lines
500
Domain
Driver Families
Bucket
drivers/clk
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 ingenic_soc_info {
	unsigned int num_channels;
	bool has_ost;
	bool has_tcu_clk;
	bool allow_missing_tcu_clk;
};

struct ingenic_tcu_clk_info {
	struct clk_init_data init_data;
	u8 gate_bit;
	u8 tcsr_reg;
};

struct ingenic_tcu_clk {
	struct clk_hw hw;
	unsigned int idx;
	struct ingenic_tcu *tcu;
	const struct ingenic_tcu_clk_info *info;
};

struct ingenic_tcu {
	const struct ingenic_soc_info *soc_info;
	struct regmap *map;
	struct clk *clk;

	struct clk_hw_onecell_data *clocks;
};

static struct ingenic_tcu *ingenic_tcu;

static inline struct ingenic_tcu_clk *to_tcu_clk(struct clk_hw *hw)
{
	return container_of(hw, struct ingenic_tcu_clk, hw);
}

static int ingenic_tcu_enable(struct clk_hw *hw)
{
	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
	struct ingenic_tcu *tcu = tcu_clk->tcu;

	regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));

	return 0;
}

static void ingenic_tcu_disable(struct clk_hw *hw)
{
	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
	struct ingenic_tcu *tcu = tcu_clk->tcu;

	regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));
}

static int ingenic_tcu_is_enabled(struct clk_hw *hw)
{
	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
	unsigned int value;

	regmap_read(tcu_clk->tcu->map, TCU_REG_TSR, &value);

	return !(value & BIT(info->gate_bit));
}

static bool ingenic_tcu_enable_regs(struct clk_hw *hw)
{
	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
	struct ingenic_tcu *tcu = tcu_clk->tcu;
	bool enabled = false;

	/*
	 * According to the programming manual, a timer channel's registers can
	 * only be accessed when the channel's stop bit is clear.
	 */
	enabled = !!ingenic_tcu_is_enabled(hw);
	regmap_write(tcu->map, TCU_REG_TSCR, BIT(info->gate_bit));

	return enabled;
}

static void ingenic_tcu_disable_regs(struct clk_hw *hw)
{
	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
	struct ingenic_tcu *tcu = tcu_clk->tcu;

	regmap_write(tcu->map, TCU_REG_TSSR, BIT(info->gate_bit));

Annotation

Implementation Notes