Esempio n. 1
0
static struct clk * __init create_mux_common(struct clockgen *cg,
					     struct mux_hwclock *hwc,
					     const struct clk_ops *ops,
					     unsigned long min_rate,
					     unsigned long max_rate,
					     unsigned long pct80_rate,
					     const char *fmt, int idx)
{
	struct clk_init_data init = {};
	struct clk *clk;
	const struct clockgen_pll_div *div;
	const char *parent_names[NUM_MUX_PARENTS];
	char name[32];
	int i, j;

	snprintf(name, sizeof(name), fmt, idx);

	for (i = 0, j = 0; i < NUM_MUX_PARENTS; i++) {
		unsigned long rate;

		hwc->clksel_to_parent[i] = -1;

		div = get_pll_div(cg, hwc, i);
		if (!div)
			continue;

		rate = clk_get_rate(div->clk);

		if (hwc->info->clksel[i].flags & CLKSEL_80PCT &&
		    rate > pct80_rate)
			continue;
		if (rate < min_rate)
			continue;
		if (rate > max_rate)
			continue;

		parent_names[j] = div->name;
		hwc->parent_to_clksel[j] = i;
		hwc->clksel_to_parent[i] = j;
		j++;
	}

	init.name = name;
	init.ops = ops;
	init.parent_names = parent_names;
	init.num_parents = hwc->num_parents = j;
	init.flags = 0;
	hwc->hw.init = &init;
	hwc->cg = cg;

	clk = clk_register(NULL, &hwc->hw);
	if (IS_ERR(clk)) {
		pr_err("%s: Couldn't register %s: %ld\n", __func__, name,
		       PTR_ERR(clk));
		kfree(hwc);
		return NULL;
	}

	return clk;
}
Esempio n. 2
0
static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
{
	struct mux_hwclock *hwc;
	const struct clockgen_pll_div *div;
	unsigned long plat_rate, min_rate;
	u64 pct80_rate;
	u32 clksel;

	hwc = kzalloc(sizeof(*hwc), GFP_KERNEL);
	if (!hwc)
		return NULL;

	if (cg->info.flags & CG_VER3)
		hwc->reg = cg->regs + 0x70000 + 0x20 * idx;
	else
		hwc->reg = cg->regs + 0x20 * idx;

	hwc->info = cg->info.cmux_groups[cg->info.cmux_to_group[idx]];

	/*
	 * Find the rate for the default clksel, and treat it as the
	 * maximum rated core frequency.  If this is an incorrect
	 * assumption, certain clock options (possibly including the
	 * default clksel) may be inappropriately excluded on certain
	 * chips.
	 */
	clksel = (cg_in(cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT;
	div = get_pll_div(cg, hwc, clksel);
	if (!div) {
		kfree(hwc);
		return NULL;
	}

	pct80_rate = clk_get_rate(div->clk);
	pct80_rate *= 8;
	do_div(pct80_rate, 10);

	plat_rate = clk_get_rate(cg->pll[PLATFORM_PLL].div[PLL_DIV1].clk);

	if (cg->info.flags & CG_CMUX_GE_PLAT)
		min_rate = plat_rate;
	else
		min_rate = plat_rate / 2;

	return create_mux_common(cg, hwc, &cmux_ops, min_rate,
				 pct80_rate, "cg-cmux%d", idx);
}