drivers/clocksource/ingenic-sysost.c

Source file repositories/reference/linux-study-clean/drivers/clocksource/ingenic-sysost.c

File Facts

System
Linux kernel
Corpus path
drivers/clocksource/ingenic-sysost.c
Extension
.c
Size
13464 bytes
Lines
546
Domain
Driver Families
Bucket
drivers/clocksource
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;
};

struct ingenic_ost_clk_info {
	struct clk_init_data init_data;
	u8 ostccr_reg;
};

struct ingenic_ost_clk {
	struct clk_hw hw;
	unsigned int idx;
	struct ingenic_ost *ost;
	const struct ingenic_ost_clk_info *info;
};

struct ingenic_ost {
	void __iomem *base;
	const struct ingenic_soc_info *soc_info;
	struct clk *clk, *percpu_timer_clk, *global_timer_clk;
	struct clock_event_device cevt;
	struct clocksource cs;
	char name[20];

	struct clk_hw_onecell_data *clocks;
};

static struct ingenic_ost *ingenic_ost;

static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw)
{
	return container_of(hw, struct ingenic_ost_clk, hw);
}

static unsigned long ingenic_ost_percpu_timer_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
	const struct ingenic_ost_clk_info *info = ost_clk->info;
	unsigned int prescale;

	prescale = readl(ost_clk->ost->base + info->ostccr_reg);

	prescale = FIELD_GET(OSTCCR_PRESCALE1_MASK, prescale);

	return parent_rate >> (prescale * 2);
}

static unsigned long ingenic_ost_global_timer_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	struct ingenic_ost_clk *ost_clk = to_ost_clk(hw);
	const struct ingenic_ost_clk_info *info = ost_clk->info;
	unsigned int prescale;

	prescale = readl(ost_clk->ost->base + info->ostccr_reg);

	prescale = FIELD_GET(OSTCCR_PRESCALE2_MASK, prescale);

	return parent_rate >> (prescale * 2);
}

static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate)
{
	u8 prescale;

	for (prescale = 0; prescale < 2; prescale++)
		if ((rate >> (prescale * 2)) <= req_rate)
			return prescale;

	return 2; /* /16 divider */
}

static int ingenic_ost_determine_rate(struct clk_hw *hw,
				      struct clk_rate_request *req)
{
	unsigned long rate = req->best_parent_rate;
	u8 prescale;

	if (req->rate > rate) {
		req->rate = rate;

		return 0;
	}

	prescale = ingenic_ost_get_prescale(rate, req->rate);

	req->rate = rate >> (prescale * 2);

	return 0;

Annotation

Implementation Notes