drivers/sh/clk/cpg.c

Source file repositories/reference/linux-study-clean/drivers/sh/clk/cpg.c

File Facts

System
Linux kernel
Corpus path
drivers/sh/clk/cpg.c
Extension
.c
Size
11025 bytes
Lines
481
Domain
Driver Families
Bucket
drivers/sh
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

if (!i) {
			pr_err("cpg: failed to enable %p[%d]\n",
			       clk->enable_reg, clk->enable_bit);
			return -ETIMEDOUT;
		}
	}
	return 0;
}

static void sh_clk_mstp_disable(struct clk *clk)
{
	sh_clk_write(sh_clk_read(clk) | (1 << clk->enable_bit), clk);
}

static struct sh_clk_ops sh_clk_mstp_clk_ops = {
	.enable		= sh_clk_mstp_enable,
	.disable	= sh_clk_mstp_disable,
	.recalc		= followparent_recalc,
};

int __init sh_clk_mstp_register(struct clk *clks, int nr)
{
	struct clk *clkp;
	int ret = 0;
	int k;

	for (k = 0; !ret && (k < nr); k++) {
		clkp = clks + k;
		clkp->ops = &sh_clk_mstp_clk_ops;
		ret |= clk_register(clkp);
	}

	return ret;
}

/*
 * Div/mult table lookup helpers
 */
static inline struct clk_div_table *clk_to_div_table(struct clk *clk)
{
	return clk->priv;
}

static inline struct clk_div_mult_table *clk_to_div_mult_table(struct clk *clk)
{
	return clk_to_div_table(clk)->div_mult_table;
}

/*
 * Common div ops
 */
static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
{
	return clk_rate_table_round(clk, clk->freq_table, rate);
}

static unsigned long sh_clk_div_recalc(struct clk *clk)
{
	struct clk_div_mult_table *table = clk_to_div_mult_table(clk);
	unsigned int idx;

	clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
			     table, clk->arch_flags ? &clk->arch_flags : NULL);

	idx = (sh_clk_read(clk) >> clk->enable_bit) & clk->div_mask;

	return clk->freq_table[idx].frequency;
}

static int sh_clk_div_set_rate(struct clk *clk, unsigned long rate)
{
	struct clk_div_table *dt = clk_to_div_table(clk);
	unsigned long value;
	int idx;

	idx = clk_rate_table_find(clk, clk->freq_table, rate);
	if (idx < 0)
		return idx;

	value = sh_clk_read(clk);
	value &= ~(clk->div_mask << clk->enable_bit);
	value |= (idx << clk->enable_bit);
	sh_clk_write(value, clk);

	/* XXX: Should use a post-change notifier */
	if (dt->kick)
		dt->kick(clk);

	return 0;
}

Annotation

Implementation Notes