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; }
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); }