Esempio n. 1
0
static void __init cpg_mstp_clocks_init(struct device_node *np)
{
	struct mstp_clock_group *group;
	const char *idxname;
	struct clk **clks;
	unsigned int i;

	group = kzalloc(sizeof(*group), GFP_KERNEL);
	clks = kmalloc_array(MSTP_MAX_CLOCKS, sizeof(*clks), GFP_KERNEL);
	if (group == NULL || clks == NULL) {
		kfree(group);
		kfree(clks);
		return;
	}

	spin_lock_init(&group->lock);
	group->data.clks = clks;

	group->smstpcr = of_iomap(np, 0);
	group->mstpsr = of_iomap(np, 1);

	if (group->smstpcr == NULL) {
		pr_err("%s: failed to remap SMSTPCR\n", __func__);
		kfree(group);
		kfree(clks);
		return;
	}

	if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks"))
		group->width_8bit = true;

	for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
		clks[i] = ERR_PTR(-ENOENT);

	if (of_find_property(np, "clock-indices", &i))
		idxname = "clock-indices";
	else
		idxname = "renesas,clock-indices";

	for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
		const char *parent_name;
		const char *name;
		u32 clkidx;
		int ret;

		/* Skip clocks with no name. */
		ret = of_property_read_string_index(np, "clock-output-names",
						    i, &name);
		if (ret < 0 || strlen(name) == 0)
			continue;

		parent_name = of_clk_get_parent_name(np, i);
		ret = of_property_read_u32_index(np, idxname, i, &clkidx);
		if (parent_name == NULL || ret < 0)
			break;

		if (clkidx >= MSTP_MAX_CLOCKS) {
			pr_err("%s: invalid clock %pOFn %s index %u\n",
			       __func__, np, name, clkidx);
			continue;
		}

		clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
						       clkidx, group);
		if (!IS_ERR(clks[clkidx])) {
			group->data.clk_num = max(group->data.clk_num,
						  clkidx + 1);
			/*
			 * Register a clkdev to let board code retrieve the
			 * clock by name and register aliases for non-DT
			 * devices.
			 *
			 * FIXME: Remove this when all devices that require a
			 * clock will be instantiated from DT.
			 */
			clk_register_clkdev(clks[clkidx], name, NULL);
		} else {
			pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
			       __func__, np, name, PTR_ERR(clks[clkidx]));
		}
	}

	of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
}
Esempio n. 2
0
/**
 * of_ti_dpll_setup - Setup function for OMAP DPLL clocks
 * @node: device node containing the DPLL info
 * @ops: ops for the DPLL
 * @ddt: DPLL data template to use
 * @init_flags: flags for controlling init types
 *
 * Initializes a DPLL clock from device tree data.
 */
static void __init of_ti_dpll_setup(struct device_node *node,
                                    const struct clk_ops *ops,
                                    const struct dpll_data *ddt,
                                    u8 init_flags)
{
    struct clk_hw_omap *clk_hw = NULL;
    struct clk_init_data *init = NULL;
    const char **parent_names = NULL;
    struct dpll_data *dd = NULL;
    int i;
    u8 dpll_mode = 0;

    dd = kzalloc(sizeof(*dd), GFP_KERNEL);
    clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
    init = kzalloc(sizeof(*init), GFP_KERNEL);
    if (!dd || !clk_hw || !init)
        goto cleanup;

    memcpy(dd, ddt, sizeof(*dd));

    clk_hw->dpll_data = dd;
    clk_hw->ops = &clkhwops_omap3_dpll;
    clk_hw->hw.init = init;
    clk_hw->flags = MEMMAP_ADDRESSING;

    init->name = node->name;
    init->ops = ops;

    init->num_parents = of_clk_get_parent_count(node);
    if (init->num_parents < 1) {
        pr_err("%s must have parent(s)\n", node->name);
        goto cleanup;
    }

    parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
    if (!parent_names)
        goto cleanup;

    for (i = 0; i < init->num_parents; i++)
        parent_names[i] = of_clk_get_parent_name(node, i);

    init->parent_names = parent_names;

    dd->control_reg = ti_clk_get_reg_addr(node, 0);
    dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
    dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);

    if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg)
        goto cleanup;

    if (init_flags & DPLL_HAS_AUTOIDLE) {
        dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
        if (!dd->autoidle_reg)
            goto cleanup;
    }

    if (of_property_read_bool(node, "ti,low-power-stop"))
        dpll_mode |= 1 << DPLL_LOW_POWER_STOP;

    if (of_property_read_bool(node, "ti,low-power-bypass"))
        dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS;

    if (of_property_read_bool(node, "ti,lock"))
        dpll_mode |= 1 << DPLL_LOCKED;

    if (dpll_mode)
        dd->modes = dpll_mode;

    ti_clk_register_dpll(&clk_hw->hw, node);
    return;

cleanup:
    kfree(dd);
    kfree(parent_names);
    kfree(init);
    kfree(clk_hw);
}
Esempio n. 3
0
static void __init sama5d4_pmc_setup(struct device_node *np)
{
	struct clk_range range = CLK_RANGE(0, 0);
	const char *slck_name, *mainxtal_name;
	struct pmc_data *sama5d4_pmc;
	const char *parent_names[5];
	struct regmap *regmap;
	struct clk *hw;
	int i;
	bool bypass;

	i = of_property_match_string(np, "clock-names", "slow_clk");
	if (i < 0)
		return;

	slck_name = of_clk_get_parent_name(np, i);

	i = of_property_match_string(np, "clock-names", "main_xtal");
	if (i < 0)
		return;
	mainxtal_name = of_clk_get_parent_name(np, i);

	regmap = syscon_node_to_regmap(np);
	if (IS_ERR(regmap))
		return;

	sama5d4_pmc = pmc_data_allocate(PMC_MCK2 + 1,
					nck(sama5d4_systemck),
					nck(sama5d4_periph32ck), 0);
	if (!sama5d4_pmc)
		return;

	hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
					   100000000);
	if (IS_ERR(hw))
		goto err_free;

	bypass = of_property_read_bool(np, "atmel,osc-bypass");

	hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name,
					bypass);
	if (IS_ERR(hw))
		goto err_free;

	parent_names[0] = "main_rc_osc";
	parent_names[1] = "main_osc";
	hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2);
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_pll(regmap, "pllack", "mainck", 0,
				   &sama5d3_pll_layout, &plla_characteristics);
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_plldiv(regmap, "plladivck", "pllack");
	if (IS_ERR(hw))
		goto err_free;

	hw = at91_clk_register_utmi(regmap, NULL, "utmick", "mainck");
	if (IS_ERR(hw))
		goto err_free;

	sama5d4_pmc->chws[PMC_UTMI] = hw;

	parent_names[0] = slck_name;
	parent_names[1] = "mainck";
	parent_names[2] = "plladivck";
	parent_names[3] = "utmick";
	hw = at91_clk_register_master(regmap, "masterck", 4, parent_names,
				      &at91sam9x5_master_layout,
				      &mck_characteristics);
	if (IS_ERR(hw))
		goto err_free;

	sama5d4_pmc->chws[PMC_MCK] = hw;

	hw = at91_clk_register_h32mx(regmap, "h32mxck", "masterck");
	if (IS_ERR(hw))
		goto err_free;

	sama5d4_pmc->chws[PMC_MCK2] = hw;

	parent_names[0] = "plladivck";
	parent_names[1] = "utmick";
	hw = at91sam9x5_clk_register_usb(regmap, "usbck", parent_names, 2);
	if (IS_ERR(hw))
		goto err_free;

	parent_names[0] = "plladivck";
	parent_names[1] = "utmick";
	hw = at91sam9x5_clk_register_smd(regmap, "smdclk", parent_names, 2);
	if (IS_ERR(hw))
		goto err_free;

	parent_names[0] = slck_name;
	parent_names[1] = "mainck";
	parent_names[2] = "plladivck";
	parent_names[3] = "utmick";
	parent_names[4] = "mck";
	for (i = 0; i < 3; i++) {
		char *name;

		name = xasprintf("prog%d", i);

		hw = at91_clk_register_programmable(regmap, name,
						    parent_names, 5, i,
						    &at91sam9x5_programmable_layout);
		if (IS_ERR(hw))
			goto err_free;
	}

	for (i = 0; i < ARRAY_SIZE(sama5d4_systemck); i++) {
		hw = at91_clk_register_system(regmap, sama5d4_systemck[i].n,
					      sama5d4_systemck[i].p,
					      sama5d4_systemck[i].id);
		if (IS_ERR(hw))
			goto err_free;

		sama5d4_pmc->shws[sama5d4_systemck[i].id] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(sama5d4_periphck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap,
							 sama5d4_periphck[i].n,
							 "masterck",
							 sama5d4_periphck[i].id,
							 &range);
		if (IS_ERR(hw))
			goto err_free;

		sama5d4_pmc->phws[sama5d4_periphck[i].id] = hw;
	}

	for (i = 0; i < ARRAY_SIZE(sama5d4_periph32ck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap,
							 sama5d4_periph32ck[i].n,
							 "h32mxck",
							 sama5d4_periph32ck[i].id,
							 &range);
		if (IS_ERR(hw))
			goto err_free;

		sama5d4_pmc->phws[sama5d4_periph32ck[i].id] = hw;
	}

	of_clk_add_provider(np, of_clk_hw_pmc_get, sama5d4_pmc);

	return;

err_free:
	pmc_data_free(sama5d4_pmc);
}
static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct clk_onecell_data *clk_data;
	const char *clk_parent;
	const char *clk_name;
	struct resource *r;
	void __iomem *reg;
	int gate_id;
	int ngates;
	int i;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	reg = devm_ioremap_resource(&pdev->dev, r);
	if (IS_ERR(reg))
		return PTR_ERR(reg);

	clk_parent = of_clk_get_parent_name(np, 0);
	if (!clk_parent)
		return -EINVAL;

	ngates = of_property_count_strings(np, "clock-output-names");
	if (ngates < 0)
		return ngates;

	if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE)
		return -EINVAL;

	clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data),
				GFP_KERNEL);
	if (!clk_data)
		return -ENOMEM;

	clk_data->clks = devm_kzalloc(&pdev->dev,
				      SUN6I_APB0_GATES_MAX_SIZE *
				      sizeof(struct clk *),
				      GFP_KERNEL);
	if (!clk_data->clks)
		return -ENOMEM;

	for (i = 0; i < ngates; i++) {
		of_property_read_string_index(np, "clock-output-names",
					      i, &clk_name);

		gate_id = i;
		of_property_read_u32_index(np, "clock-indices", i, &gate_id);

		WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE);
		if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE)
			continue;

		clk_data->clks[gate_id] = clk_register_gate(&pdev->dev,
							    clk_name,
							    clk_parent, 0,
							    reg, gate_id,
							    0, NULL);
		WARN_ON(IS_ERR(clk_data->clks[gate_id]));
	}

	clk_data->clk_num = ngates;

	return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
}
Esempio n. 5
0
void __init of_dra7_apll_setup(struct device_node *node)
{
	const struct clk_ops *ops;
	struct clk *clk;
	const char *clk_name = node->name;
	int num_parents;
	const char **parent_names = NULL;
	u8 apll_flags = 0;
	struct dpll_data *ad;
	u32 idlest_mask = 0x1;
	u32 autoidle_mask = 0x3;
	int i;

	ops = &apll_ck_ops;
	ad = kzalloc(sizeof(*ad), GFP_KERNEL);
	if (!ad) {
		pr_err("%s: could not allocate dpll_data\n", __func__);
		return;
	}

	of_property_read_string(node, "clock-output-names", &clk_name);

	num_parents = of_clk_get_parent_count(node);
	if (num_parents < 1) {
		pr_err("%s: omap dpll %s must have parent(s)\n",
		       __func__, node->name);
		goto cleanup;
	}

	parent_names = kzalloc(sizeof(char *) * num_parents, GFP_KERNEL);

	for (i = 0; i < num_parents; i++)
		parent_names[i] = of_clk_get_parent_name(node, i);

	ad->clk_ref = of_clk_get(node, 0);
	ad->clk_bypass = of_clk_get(node, 1);

	if (IS_ERR(ad->clk_ref)) {
		pr_err("%s: ti,clk-ref for %s not found\n", __func__,
		       clk_name);
		goto cleanup;
	}

	if (IS_ERR(ad->clk_bypass)) {
		pr_err("%s: ti,clk-bypass for %s not found\n", __func__,
		       clk_name);
		goto cleanup;
	}

	i = of_property_match_string(node, "reg-names", "control");
	if (i >= 0)
		ad->control_reg = of_iomap(node, i);

	i = of_property_match_string(node, "reg-names", "idlest");
	if (i >= 0)
		ad->idlest_reg = of_iomap(node, i);

	ad->idlest_mask = idlest_mask;
	ad->enable_mask = autoidle_mask;

	clk = omap_clk_register_apll(NULL, clk_name, parent_names,
				num_parents, apll_flags, ad,
				NULL, ops);

	if (!IS_ERR(clk))
		of_clk_add_provider(node, of_clk_src_simple_get, clk);
	return;

cleanup:
	kfree(parent_names);
	kfree(ad);
	return;
}
Esempio n. 6
0
static void __init cpg_div6_clock_init(struct device_node *np)
{
	struct clk_init_data init;
	struct div6_clock *clock;
	const char *parent_name;
	const char *name;
	struct clk *clk;
	int ret;

	clock = kzalloc(sizeof(*clock), GFP_KERNEL);
	if (!clock) {
		pr_err("%s: failed to allocate %s DIV6 clock\n",
		       __func__, np->name);
		return;
	}

	/* Remap the clock register and read the divisor. Disabling the
	 * clock overwrites the divisor, so we need to cache its value for the
	 * enable operation.
	 */
	clock->reg = of_iomap(np, 0);
	if (clock->reg == NULL) {
		pr_err("%s: failed to map %s DIV6 clock register\n",
		       __func__, np->name);
		goto error;
	}

	clock->div = (clk_readl(clock->reg) & CPG_DIV6_DIV_MASK) + 1;

	/* Parse the DT properties. */
	ret = of_property_read_string(np, "clock-output-names", &name);
	if (ret < 0) {
		pr_err("%s: failed to get %s DIV6 clock output name\n",
		       __func__, np->name);
		goto error;
	}

	parent_name = of_clk_get_parent_name(np, 0);
	if (parent_name == NULL) {
		pr_err("%s: failed to get %s DIV6 clock parent name\n",
		       __func__, np->name);
		goto error;
	}

	/* Register the clock. */
	init.name = name;
	init.ops = &cpg_div6_clock_ops;
	init.flags = CLK_IS_BASIC;
	init.parent_names = &parent_name;
	init.num_parents = 1;

	clock->hw.init = &init;

	clk = clk_register(NULL, &clock->hw);
	if (IS_ERR(clk)) {
		pr_err("%s: failed to register %s DIV6 clock (%ld)\n",
		       __func__, np->name, PTR_ERR(clk));
		goto error;
	}

	of_clk_add_provider(np, of_clk_src_simple_get, clk);

	return;

error:
	if (clock->reg)
		iounmap(clock->reg);
	kfree(clock);
}
Esempio n. 7
0
/**
 * zynqmp_clk_setup -  Setup the clock framework and register clocks
 * @np:		Device node
 *
 * Return:	Error code on failure
 */
static void __init zynqmp_clk_setup(struct device_node *np)
{
	int i;
	u32 tmp;
	struct clk *clk;
	char *clk_name;
	int idx;

	idx = of_property_match_string(np, "clock-names", "pss_ref_clk");
	if (idx < 0) {
		pr_err("pss_ref_clk not provided\n");
		return;
	}
	input_clks[0] =	of_clk_get_parent_name(np, idx);

	idx = of_property_match_string(np, "clock-names", "video_clk");
	if (idx < 0) {
		pr_err("video_clk not provided\n");
		return;
	}
	input_clks[1] =	of_clk_get_parent_name(np, idx);

	idx = of_property_match_string(np, "clock-names", "pss_alt_ref_clk");
	if (idx < 0) {
		pr_err("pss_alt_ref_clk not provided\n");
		return;
	}
	input_clks[2] =	of_clk_get_parent_name(np, idx);

	idx = of_property_match_string(np, "clock-names", "aux_ref_clk");
	if (idx < 0) {
		pr_err("aux_ref_clk not provided\n");
		return;
	}
	input_clks[3] =	of_clk_get_parent_name(np, idx);

	idx = of_property_match_string(np, "clock-names", "gt_crx_ref_clk");
	if (idx < 0) {
		pr_err("aux_ref_clk not provided\n");
		return;
	}
	input_clks[4] =	of_clk_get_parent_name(np, idx);

	/* get clock output names from DT */
	for (i = 0; i < clk_max; i++) {
		if (of_property_read_string_index(np, "clock-output-names",
				  i, &clk_output_name[i])) {
			pr_err("%s: clock output name not in DT\n", __func__);
			BUG();
		}
	}
	/* APU clocks */
	acpu_parents[0] = clk_output_name[apll];
	acpu_parents[1] = dummy_nm;
	acpu_parents[2] = clk_output_name[dpll];
	acpu_parents[3] = clk_output_name[vpll];

	/* PLL clocks */
	zynqmp_clk_register_pll_clk(apll, clk_output_name[apll],
			CLK_IGNORE_UNUSED,
			(resource_size_t *)CRF_APB_APLL_CTRL,
			(resource_size_t *)CRF_APB_PLL_STATUS, 0);

	zynqmp_clk_register_pll_clk(dpll, clk_output_name[dpll], 0,
			(resource_size_t *)CRF_APB_DPLL_CTRL,
			(resource_size_t *)CRF_APB_PLL_STATUS, 1);

	zynqmp_clk_register_pll_clk(vpll, clk_output_name[vpll],
			CLK_IGNORE_UNUSED,
			(resource_size_t *)CRF_APB_VPLL_CTRL,
			(resource_size_t *)CRF_APB_PLL_STATUS, 2);

	zynqmp_clk_register_pll_clk(iopll, clk_output_name[iopll], 0,
			(resource_size_t *)CRL_APB_IOPLL_CTRL,
			(resource_size_t *)CRL_APB_PLL_STATUS, 0);

	zynqmp_clk_register_pll_clk(rpll, clk_output_name[rpll], 0,
			(resource_size_t *)CRL_APB_RPLL_CTRL,
			(resource_size_t *)CRL_APB_PLL_STATUS, 1);

	/* Domain crossing PLL clock dividers */
	clks[apll_to_lpd] = zynqmp_clk_register_divider(NULL, "apll_to_lpd",
			clk_output_name[apll], 0,
			(resource_size_t *)CRF_APB_APLL_TO_LPD_CTRL, 8,
			6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clks[dpll_to_lpd] = zynqmp_clk_register_divider(NULL, "dpll_to_lpd",
			clk_output_name[dpll], 0,
			(resource_size_t *)CRF_APB_DPLL_TO_LPD_CTRL, 8,
			6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clks[vpll_to_lpd] = zynqmp_clk_register_divider(NULL, "vpll_to_lpd",
			clk_output_name[vpll], 0,
			(resource_size_t *)CRF_APB_VPLL_TO_LPD_CTRL, 8,
			6,  CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clks[iopll_to_fpd] = zynqmp_clk_register_divider(NULL, "iopll_to_fpd",
			clk_output_name[iopll], 0,
			(resource_size_t *)CRL_APB_IOPLL_TO_FPD_CTRL,
			8, 6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clks[rpll_to_fpd] = zynqmp_clk_register_divider(NULL, "rpll_to_fpd",
			clk_output_name[rpll], 0,
			(resource_size_t *)CRL_APB_RPLL_TO_FPD_CTRL, 8,
			6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clk = zynqmp_clk_register_mux(NULL, "acpu_mux", acpu_parents, 4,
			CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRF_APB_ACPU_CTRL, 0, 3, 0);

	clk = zynqmp_clk_register_divider(NULL, "acpu_div0", "acpu_mux", 0,
			(resource_size_t *)CRF_APB_ACPU_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clks[acpu] = zynqmp_clk_register_gate(NULL, clk_output_name[acpu],
			"acpu_div0", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
			(resource_size_t *)CRF_APB_ACPU_CTRL, 24, 0);

	clk_prepare_enable(clks[acpu]);

	clk = clk_register_fixed_factor(NULL, "acpu_half_div", "acpu_div0", 0,
			1, 2);

	clks[acpu_half] = zynqmp_clk_register_gate(NULL,
			clk_output_name[acpu_half], "acpu_half_div",
			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
			(resource_size_t *)CRF_APB_ACPU_CTRL, 25, 0);

	/* Timers */
	/* The first parent clock source will be changed in the future.
	 * Currently, using the acpu clock as the parent based on the
	 * assumption that it comes from APB.
	 */
	wdt_ext_clk_mux_parents[0] = clk_output_name[acpu];
	for (i = 0; i < ARRAY_SIZE(swdt_ext_clk_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				swdt_ext_clk_input_names[i]);
		if (idx >= 0)
			wdt_ext_clk_mux_parents[i + 1] =
				of_clk_get_parent_name(np, idx);
		else
			wdt_ext_clk_mux_parents[i + 1] = dummy_nm;
	}
	clks[wdt] = zynqmp_clk_register_mux(NULL, clk_output_name[wdt],
			wdt_ext_clk_mux_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_WDT_CLK_SEL, 0, 1, 0);

	/* DDR clocks */
	ddr_parents[0] = clk_output_name[dpll];
	ddr_parents[1] = clk_output_name[vpll];

	clk = zynqmp_clk_register_mux(NULL, "ddr_mux", ddr_parents, 2,
			CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRF_APB_DDR_CTRL, 0, 3, 0);

	clks[ddr_ref] = zynqmp_clk_register_divider(NULL,
			clk_output_name[ddr_ref],
			"ddr_mux", 0, (resource_size_t *)CRF_APB_DDR_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clk_prepare_enable(clks[ddr_ref]);

	/* Peripheral clock parents */
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dbg_trace],
					iopll_to_fpd, dpll, apll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dbg_fpd],
					iopll_to_fpd, dpll, apll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dbg_lpd],
					rpll, iopll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dbg_tstmp],
					iopll_to_fpd, dpll, apll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dp_video_ref],
					vpll, dpll, rpll_to_fpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dp_audio_ref],
					vpll, dpll, rpll_to_fpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dp_stc_ref],
					vpll, dpll, rpll_to_fpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gpu_ref],
					iopll_to_fpd, vpll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[sata_ref],
					iopll_to_fpd, apll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pcie_ref],
					iopll_to_fpd, rpll_to_fpd, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gdma_ref],
					apll, vpll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[dpdma_ref],
					apll, vpll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[topsw_main],
					apll, vpll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[topsw_lsbus],
					apll, iopll_to_fpd, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gtgref0_ref],
					iopll_to_fpd, apll, dpll);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[usb3_dual_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[usb0_bus_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[usb1_bus_ref],
					iopll, apll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gem0_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gem1_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gem2_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gem3_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[qspi_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[sdio0_ref],
					iopll, rpll, vpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[sdio1_ref],
					iopll, rpll, vpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[uart0_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[uart1_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[spi0_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[spi1_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[can0_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[can1_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[cpu_r5],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[iou_switch],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[csu_pll],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pcap],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[lpd_switch],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[lpd_lsbus],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[nand_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[adma_ref],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[gem_tsu_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[ams_ref],
					rpll, iopll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[i2c0_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[i2c1_ref],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pl0],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pl1],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pl2],
					iopll, rpll, dpll_to_lpd);
	zynqmp_clk_get_parents(clk_output_name, periph_parents[pl3],
					iopll, rpll, dpll_to_lpd);

	/* PL clocks */
	zynqmp_clk_register_pl_clk(pl0, clk_output_name[pl0],
			(resource_size_t *)CRL_APB_PL0_REF_CTRL,
			periph_parents[pl0]);
	zynqmp_clk_register_pl_clk(pl1, clk_output_name[pl1],
			(resource_size_t *)CRL_APB_PL1_REF_CTRL,
			periph_parents[pl1]);
	zynqmp_clk_register_pl_clk(pl2, clk_output_name[pl2],
			(resource_size_t *)CRL_APB_PL2_REF_CTRL,
			periph_parents[pl2]);
	zynqmp_clk_register_pl_clk(pl3, clk_output_name[pl3],
			(resource_size_t *)CRL_APB_PL3_REF_CTRL,
			periph_parents[pl3]);

	/* Peripheral clock */
	zynqmp_clk_register_periph_clk(dbg_trace, clk_output_name[dbg_trace],
			CRF_APB_DBG_TRACE_CTRL, periph_parents[dbg_trace], 1,
			0, 24);

	zynqmp_clk_get_parents(clk_output_name, periph_parents[dbg_fpd],
					iopll_to_fpd, dpll, apll);
	zynqmp_clk_register_periph_clk(dbg_fpd, clk_output_name[dbg_fpd],
			CRF_APB_DBG_FPD_CTRL, periph_parents[dbg_fpd], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(dbg_lpd, clk_output_name[dbg_lpd],
			CRL_APB_DBG_LPD_CTRL, periph_parents[dbg_lpd], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(dbg_tstmp, clk_output_name[dbg_tstmp],
			CRF_APB_DBG_TSTMP_CTRL, periph_parents[dbg_tstmp], 0,
			0, 0);

	zynqmp_clk_register_periph_clk(dp_video_ref,
			clk_output_name[dp_video_ref],
			CRF_APB_DP_VIDEO_REF_CTRL,
			periph_parents[dp_video_ref], 1, 1, 24);

	zynqmp_clk_register_periph_clk(dp_audio_ref,
			clk_output_name[dp_audio_ref],
			CRF_APB_DP_AUDIO_REF_CTRL,
			periph_parents[dp_audio_ref], 1, 1, 24);

	zynqmp_clk_register_periph_clk(dp_stc_ref,
			clk_output_name[dp_stc_ref], CRF_APB_DP_STC_REF_CTRL,
			periph_parents[dp_stc_ref], 1, 1, 24);

	zynqmp_clk_register_periph_clk(gpu_ref, clk_output_name[gpu_ref],
			CRF_APB_GPU_REF_CTRL, periph_parents[gpu_ref], 1, 0,
			24);
	clks[gpu_pp0_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gpu_pp0_ref], "gpu_ref_div0",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRF_APB_GPU_REF_CTRL, 25, 0);
	clks[gpu_pp1_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gpu_pp1_ref], "gpu_ref_div0",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRF_APB_GPU_REF_CTRL, 26, 0);

	zynqmp_clk_register_periph_clk(sata_ref, clk_output_name[sata_ref],
			CRF_APB_SATA_REF_CTRL, periph_parents[sata_ref], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(pcie_ref, clk_output_name[pcie_ref],
			CRF_APB_PCIE_REF_CTRL, periph_parents[pcie_ref], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(gdma_ref, clk_output_name[gdma_ref],
			CRF_APB_GDMA_REF_CTRL, periph_parents[gdma_ref], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(dpdma_ref, clk_output_name[dpdma_ref],
			CRF_APB_DPDMA_REF_CTRL, periph_parents[dpdma_ref], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(topsw_main, clk_output_name[topsw_main],
			CRF_APB_TOPSW_MAIN_CTRL, periph_parents[topsw_main],
			CLK_IGNORE_UNUSED, 0, 24);

	zynqmp_clk_register_periph_clk(topsw_lsbus,
			clk_output_name[topsw_lsbus], CRF_APB_TOPSW_LSBUS_CTRL,
			periph_parents[topsw_lsbus], CLK_IGNORE_UNUSED, 0, 24);

	zynqmp_clk_register_periph_clk(gtgref0_ref,
			clk_output_name[gtgref0_ref], CRF_APB_GTGREF0_REF_CTRL,
			periph_parents[gtgref0_ref], 1, 0, 24);

	zynqmp_clk_register_periph_clk(usb3_dual_ref,
			clk_output_name[usb3_dual_ref],
			CRL_APB_USB3_DUAL_REF_CTRL,
			periph_parents[usb3_dual_ref], 1, 1, 25);

	zynqmp_clk_register_periph_clk(usb0_bus_ref,
			clk_output_name[usb0_bus_ref],
			CRL_APB_USB0_BUS_REF_CTRL,
			periph_parents[usb0_bus_ref], 1, 1, 25);

	clks[usb0] = zynqmp_clk_register_mux(NULL, clk_output_name[usb0],
			usb0_mio_mux_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_USB0_BUS_REF_CTRL, 2, 1, 0);

	zynqmp_clk_register_periph_clk(usb1_bus_ref,
			clk_output_name[usb1_bus_ref],
			CRL_APB_USB1_BUS_REF_CTRL,
			periph_parents[usb1_bus_ref], 1, 1, 25);
	clks[usb1] = zynqmp_clk_register_mux(NULL, clk_output_name[usb1],
			usb1_mio_mux_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_USB1_BUS_REF_CTRL, 2, 1, 0);

	/* Ethernet clocks */
	for (i = 0; i < ARRAY_SIZE(gem0_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem0_emio_input_names[i]);
		if (idx >= 0)
			gem0_tx_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}
	clk = zynqmp_clk_register_mux(NULL, "gem0_ref_mux",
			periph_parents[gem0_ref], 4, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_GEM0_REF_CTRL, 0, 3, 0);
	clk = zynqmp_clk_register_divider(NULL, "gem0_ref_div0", "gem0_ref_mux",
			0, (resource_size_t *)CRL_APB_GEM0_REF_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_divider(NULL, "gem0_ref_div1",
			"gem0_ref_div0", 0,
			(resource_size_t *)CRL_APB_GEM0_REF_CTRL, 16, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);

	clk = zynqmp_clk_register_mux(NULL, "gem0_tx_mux", gem0_tx_mux_parents,
			2, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_GEM_CLK_CTRL, 1, 1, 0);
	clks[gem0_rx] = zynqmp_clk_register_gate(NULL, clk_output_name[gem0_rx],
			"gem0_tx_mux",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM0_REF_CTRL, 26, 0);
	clks[gem0_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gem0_ref],
			"gem0_ref_div1", CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM0_REF_CTRL, 25, 0);


	for (i = 0; i < ARRAY_SIZE(gem1_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem1_emio_input_names[i]);
		if (idx >= 0)
			gem1_tx_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}

	clk = zynqmp_clk_register_mux(NULL, "gem1_ref_mux",
			periph_parents[gem1_ref],
			4, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_GEM1_REF_CTRL, 0, 3, 0);
	clk = zynqmp_clk_register_divider(NULL, "gem1_ref_div0", "gem1_ref_mux",
			0, (resource_size_t *)CRL_APB_GEM1_REF_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_divider(NULL, "gem1_ref_div1",
			"gem1_ref_div0", 0,
			(resource_size_t *)CRL_APB_GEM1_REF_CTRL, 16, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_mux(NULL, "gem1_tx_mux", gem1_tx_mux_parents,
			2, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_GEM_CLK_CTRL, 6, 1,	0);
	clks[gem1_rx] = zynqmp_clk_register_gate(NULL, clk_output_name[gem1_rx],
			"gem1_tx_mux", CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM1_REF_CTRL, 26, 0);
	clks[gem1_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gem1_ref], "gem1_ref_div1",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM1_REF_CTRL, 25, 0);


	for (i = 0; i < ARRAY_SIZE(gem2_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem2_emio_input_names[i]);
		if (idx >= 0)
			gem2_tx_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}
	clk = zynqmp_clk_register_mux(NULL, "gem2_ref_mux",
			periph_parents[gem2_ref], 4, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_GEM2_REF_CTRL, 0, 3, 0);
	clk = zynqmp_clk_register_divider(NULL, "gem2_ref_div0",
			"gem2_ref_mux", 0,
			(resource_size_t *)CRL_APB_GEM2_REF_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_divider(NULL, "gem2_ref_div1",
			"gem2_ref_div0", 0,
			(resource_size_t *)CRL_APB_GEM2_REF_CTRL, 16, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_mux(NULL, "gem2_tx_mux", gem2_tx_mux_parents,
			2, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_GEM_CLK_CTRL, 11, 1, 0);
	clks[gem2_rx] = zynqmp_clk_register_gate(NULL, clk_output_name[gem2_rx],
			"gem2_tx_mux", CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM2_REF_CTRL, 26, 0);
	clks[gem2_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gem2_ref], "gem2_ref_div1",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM2_REF_CTRL, 25, 0);


	for (i = 0; i < ARRAY_SIZE(gem3_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem3_emio_input_names[i]);
		if (idx >= 0)
			gem3_tx_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}

	clk = zynqmp_clk_register_mux(NULL, "gem3_ref_mux",
			periph_parents[gem3_ref], 4, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_GEM3_REF_CTRL, 0,
			3, 0);
	clk = zynqmp_clk_register_divider(NULL, "gem3_ref_div0",
			"gem3_ref_mux", 0,
			(resource_size_t *)CRL_APB_GEM3_REF_CTRL, 8, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_divider(NULL, "gem3_ref_div1",
			"gem3_ref_div0", CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM3_REF_CTRL, 16, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clk = zynqmp_clk_register_mux(NULL, "gem3_tx_mux", gem3_tx_mux_parents,
			2, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_GEM_CLK_CTRL, 16, 1, 0);
	clks[gem3_rx] = zynqmp_clk_register_gate(NULL, clk_output_name[gem3_rx],
			"gem3_tx_mux", CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM3_REF_CTRL, 26, 0);
	clks[gem3_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[gem3_ref], "gem3_ref_div1",
			CLK_SET_RATE_PARENT,
			(resource_size_t *)CRL_APB_GEM3_REF_CTRL, 25, 0);

	gem_tsu_mux_parents[0] = clk_output_name[gem_tsu_ref];
	gem_tsu_mux_parents[1] = clk_output_name[gem_tsu_ref];
	gem_tsu_mux_parents[2] = "mio_clk_26";
	gem_tsu_mux_parents[3] = "mio_clk_50_or_51";

	zynqmp_clk_register_periph_clk(gem_tsu_ref,
			clk_output_name[gem_tsu_ref], CRL_APB_GEM_TSU_REF_CTRL,
			periph_parents[gem_tsu_ref], 1, 1, 24);

	clks[gem_tsu] = zynqmp_clk_register_mux(NULL, clk_output_name[gem_tsu],
			gem_tsu_mux_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_GEM_CLK_CTRL, 20, 2, 0);

	zynqmp_clk_register_periph_clk(qspi_ref, clk_output_name[qspi_ref],
			CRL_APB_QSPI_REF_CTRL, periph_parents[qspi_ref], 1, 1,
			24);

	zynqmp_clk_register_periph_clk(sdio0_ref, clk_output_name[sdio0_ref],
			CRL_APB_SDIO0_REF_CTRL, periph_parents[sdio0_ref], 1,
			1, 24);

	zynqmp_clk_register_periph_clk(sdio1_ref, clk_output_name[sdio1_ref],
			CRL_APB_SDIO1_REF_CTRL, periph_parents[sdio1_ref], 1,
			1, 24);

	zynqmp_clk_register_periph_clk(uart0_ref, clk_output_name[uart0_ref],
			CRL_APB_UART0_REF_CTRL, periph_parents[uart0_ref], 1,
			1, 24);

	zynqmp_clk_register_periph_clk(uart1_ref, clk_output_name[uart1_ref],
			CRL_APB_UART1_REF_CTRL, periph_parents[uart1_ref], 1,
			1, 24);

	zynqmp_clk_register_periph_clk(spi0_ref, clk_output_name[spi0_ref],
			CRL_APB_SPI0_REF_CTRL, periph_parents[spi0_ref], 1, 1,
			24);

	zynqmp_clk_register_periph_clk(spi1_ref, clk_output_name[spi1_ref],
			CRL_APB_SPI1_REF_CTRL, periph_parents[spi1_ref], 1, 1,
			24);

	tmp = strlen("mio_clk_00x");
	clk_name = kmalloc(tmp, GFP_KERNEL);
	for (i = 0; i < NUM_MIO_PINS; i++) {
		int idx;

		snprintf(clk_name, tmp, "mio_clk_%2.2d", i);
		idx = of_property_match_string(np, "clock-names", clk_name);
		if (idx >= 0)
			can_mio_mux_parents[i] = of_clk_get_parent_name(np,
						idx);
		else
			can_mio_mux_parents[i] = dummy_nm;
	}
	kfree(clk_name);
	zynqmp_clk_register_periph_clk(can0_ref, clk_output_name[can0_ref],
			CRL_APB_CAN0_REF_CTRL, periph_parents[can0_ref], 1, 1,
			24);
	clk = zynqmp_clk_register_mux(NULL, "can0_mio_mux",
			can_mio_mux_parents, NUM_MIO_PINS,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_CAN_MIO_CTRL, 0, 7, 0);
	clks[can0] = zynqmp_clk_register_mux(NULL, clk_output_name[can0],
			can0_mio_mux2_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_CAN_MIO_CTRL, 7, 1, 0);

	zynqmp_clk_register_periph_clk(can1_ref, clk_output_name[can1_ref],
			CRL_APB_CAN1_REF_CTRL, periph_parents[can1_ref], 1, 1,
			24);
	clk = zynqmp_clk_register_mux(NULL, "can1_mio_mux",
			can_mio_mux_parents, NUM_MIO_PINS,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_CAN_MIO_CTRL, 15, 7, 0);
	clks[can1] = zynqmp_clk_register_mux(NULL, clk_output_name[can1],
			can1_mio_mux2_parents, 2,
			CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)IOU_SLCR_CAN_MIO_CTRL, 22, 1, 0);

	zynqmp_clk_register_periph_clk(cpu_r5, clk_output_name[cpu_r5],
			CRL_APB_CPU_R5_CTRL, periph_parents[cpu_r5],
			CLK_IGNORE_UNUSED, 0, 24);
	clk = zynqmp_clk_register_gate(NULL, "cpu_r5_core_gate", "cpu_r5_div0",
			CLK_IGNORE_UNUSED,
			(resource_size_t *)CRL_APB_CPU_R5_CTRL, 25, 0);

	zynqmp_clk_register_periph_clk(iou_switch, clk_output_name[iou_switch],
			CRL_APB_IOU_SWITCH_CTRL, periph_parents[iou_switch],
			CLK_IGNORE_UNUSED, 0, 24);

	zynqmp_clk_register_periph_clk(csu_pll, clk_output_name[csu_pll],
			CRL_APB_CSU_PLL_CTRL, periph_parents[csu_pll], 1, 0,
			24);

	zynqmp_clk_register_periph_clk(pcap, clk_output_name[pcap],
			CRL_APB_PCAP_CTRL, periph_parents[pcap], 1, 0, 24);

	zynqmp_clk_register_periph_clk(lpd_switch, clk_output_name[lpd_switch],
			CRL_APB_LPD_SWITCH_CTRL, periph_parents[lpd_switch],
			CLK_IGNORE_UNUSED, 0, 24);

	zynqmp_clk_register_periph_clk(lpd_lsbus, clk_output_name[lpd_lsbus],
			CRL_APB_LPD_LSBUS_CTRL, periph_parents[lpd_lsbus],
			CLK_IGNORE_UNUSED, 0, 24);

	zynqmp_clk_register_periph_clk(nand_ref, clk_output_name[nand_ref],
			CRL_APB_NAND_REF_CTRL, periph_parents[nand_ref], 1, 1,
			24);

	zynqmp_clk_register_periph_clk(adma_ref, clk_output_name[adma_ref],
			CRL_APB_ADMA_REF_CTRL, periph_parents[adma_ref], 1, 0,
			24);

	dll_ref_parents[0] = clk_output_name[iopll];
	dll_ref_parents[1] = clk_output_name[rpll];
	clks[dll_ref] = zynqmp_clk_register_mux(NULL, clk_output_name[dll_ref],
				dll_ref_parents, 2,
				CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
				(resource_size_t *)CRL_APB_DLL_REF_CTRL,
				0, 3, 0);

	zynqmp_clk_register_periph_clk(ams_ref, clk_output_name[ams_ref],
			CRL_APB_AMS_REF_CTRL, periph_parents[ams_ref], 1, 1,
			24);

	zynqmp_clk_register_periph_clk(i2c0_ref, clk_output_name[i2c0_ref],
			CRL_APB_I2C0_REF_CTRL, periph_parents[i2c0_ref], 1,
			1, 24);

	zynqmp_clk_register_periph_clk(i2c1_ref, clk_output_name[i2c1_ref],
			CRL_APB_I2C1_REF_CTRL, periph_parents[i2c1_ref], 1,
			1, 24);

	timestamp_ref_parents[0] = clk_output_name[rpll];
	timestamp_ref_parents[1] = dummy_nm;
	timestamp_ref_parents[2] = clk_output_name[iopll];
	timestamp_ref_parents[3] = clk_output_name[dpll_to_lpd];
	timestamp_ref_parents[4] = input_clks[0];
	timestamp_ref_parents[5] = input_clks[0];
	timestamp_ref_parents[6] = input_clks[0];
	timestamp_ref_parents[7] = input_clks[0];
	clk = zynqmp_clk_register_mux(NULL, "timestamp_ref_mux",
			timestamp_ref_parents, 8, CLK_SET_RATE_NO_REPARENT,
			(resource_size_t *)CRL_APB_TIMESTAMP_REF_CTRL, 0, 3, 0);
	clk = zynqmp_clk_register_divider(NULL, "timestamp_ref_div0",
			"timestamp_ref_mux", 0,
			(resource_size_t *)CRL_APB_TIMESTAMP_REF_CTRL,
			8, 6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO);
	clks[timestamp_ref] = zynqmp_clk_register_gate(NULL,
			clk_output_name[timestamp_ref], "timestamp_ref_div0",
			CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
			(resource_size_t *)CRL_APB_TIMESTAMP_REF_CTRL, 24, 0);

	for (i = 0; i < ARRAY_SIZE(clks); i++) {
		if (IS_ERR(clks[i])) {
			pr_err("Zynq Ultrascale+ MPSoC clk %d: register failed with %ld\n",
			       i, PTR_ERR(clks[i]));
			BUG();
		}
	}

	clk_data.clks = clks;
	clk_data.clk_num = ARRAY_SIZE(clks);
	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
Esempio n. 8
0
static void __init zynq_clk_setup(struct device_node *np)
{
	int i;
	u32 tmp;
	int ret;
	struct clk *clk;
	char *clk_name;
	const char *clk_output_name[clk_max];
	const char *cpu_parents[4];
	const char *periph_parents[4];
	const char *swdt_ext_clk_mux_parents[2];
	const char *can_mio_mux_parents[NUM_MIO_PINS];

	pr_info("Zynq clock init\n");

	/* get clock output names from DT */
	for (i = 0; i < clk_max; i++) {
		if (of_property_read_string_index(np, "clock-output-names",
				  i, &clk_output_name[i])) {
			pr_err("%s: clock output name not in DT\n", __func__);
			BUG();
		}
	}
	cpu_parents[0] = clk_output_name[armpll];
	cpu_parents[1] = clk_output_name[armpll];
	cpu_parents[2] = clk_output_name[ddrpll];
	cpu_parents[3] = clk_output_name[iopll];
	periph_parents[0] = clk_output_name[iopll];
	periph_parents[1] = clk_output_name[iopll];
	periph_parents[2] = clk_output_name[armpll];
	periph_parents[3] = clk_output_name[ddrpll];

	/* ps_clk */
	ret = of_property_read_u32(np, "ps-clk-frequency", &tmp);
	if (ret) {
		pr_warn("ps_clk frequency not specified, using 33 MHz.\n");
		tmp = 33333333;
	}
	ps_clk = clk_register_fixed_rate(NULL, "ps_clk", NULL, CLK_IS_ROOT,
			tmp);

	/* PLLs */
	clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL,
			SLCR_PLL_STATUS, 0, &armpll_lock);
	clks[armpll] = clk_register_mux(NULL, clk_output_name[armpll],
			armpll_parents, 2, 0, SLCR_ARMPLL_CTRL, 4, 1, 0,
			&armpll_lock);

	clk = clk_register_zynq_pll("ddrpll_int", "ps_clk", SLCR_DDRPLL_CTRL,
			SLCR_PLL_STATUS, 1, &ddrpll_lock);
	clks[ddrpll] = clk_register_mux(NULL, clk_output_name[ddrpll],
			ddrpll_parents, 2, 0, SLCR_DDRPLL_CTRL, 4, 1, 0,
			&ddrpll_lock);

	clk = clk_register_zynq_pll("iopll_int", "ps_clk", SLCR_IOPLL_CTRL,
			SLCR_PLL_STATUS, 2, &iopll_lock);
	clks[iopll] = clk_register_mux(NULL, clk_output_name[iopll],
			iopll_parents, 2, 0, SLCR_IOPLL_CTRL, 4, 1, 0,
			&iopll_lock);

	/* CPU clocks */
	tmp = readl(SLCR_621_TRUE) & 1;
	clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, 0,
			SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock);
	clk = clk_register_divider(NULL, "cpu_div", "cpu_mux", 0,
			SLCR_ARM_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &armclk_lock);

	clks[cpu_6or4x] = clk_register_gate(NULL, clk_output_name[cpu_6or4x],
			"cpu_div", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
			SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock);

	clk = clk_register_fixed_factor(NULL, "cpu_3or2x_div", "cpu_div", 0,
			1, 2);
	clks[cpu_3or2x] = clk_register_gate(NULL, clk_output_name[cpu_3or2x],
			"cpu_3or2x_div", CLK_IGNORE_UNUSED,
			SLCR_ARM_CLK_CTRL, 25, 0, &armclk_lock);

	clk = clk_register_fixed_factor(NULL, "cpu_2x_div", "cpu_div", 0, 1,
			2 + tmp);
	clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x],
			"cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL,
			26, 0, &armclk_lock);

	clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1,
			4 + 2 * tmp);
	clks[cpu_1x] = clk_register_gate(NULL, clk_output_name[cpu_1x],
			"cpu_1x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 27,
			0, &armclk_lock);

	/* Timers */
	swdt_ext_clk_mux_parents[0] = clk_output_name[cpu_1x];
	for (i = 0; i < ARRAY_SIZE(swdt_ext_clk_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				swdt_ext_clk_input_names[i]);
		if (idx >= 0)
			swdt_ext_clk_mux_parents[i + 1] =
				of_clk_get_parent_name(np, idx);
		else
			swdt_ext_clk_mux_parents[i + 1] = dummy_nm;
	}
	clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt],
			swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT,
			SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock);

	/* DDR clocks */
	clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0,
			SLCR_DDR_CLK_CTRL, 26, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock);
	clks[ddr2x] = clk_register_gate(NULL, clk_output_name[ddr2x],
			"ddr2x_div", 0, SLCR_DDR_CLK_CTRL, 1, 0, &ddrclk_lock);
	clk_prepare_enable(clks[ddr2x]);
	clk = clk_register_divider(NULL, "ddr3x_div", "ddrpll", 0,
			SLCR_DDR_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock);
	clks[ddr3x] = clk_register_gate(NULL, clk_output_name[ddr3x],
			"ddr3x_div", 0, SLCR_DDR_CLK_CTRL, 0, 0, &ddrclk_lock);
	clk_prepare_enable(clks[ddr3x]);

	clk = clk_register_divider(NULL, "dci_div0", "ddrpll", 0,
			SLCR_DCI_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &dciclk_lock);
	clk = clk_register_divider(NULL, "dci_div1", "dci_div0",
			CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 20, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
			&dciclk_lock);
	clks[dci] = clk_register_gate(NULL, clk_output_name[dci], "dci_div1",
			CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 0, 0,
			&dciclk_lock);
	clk_prepare_enable(clks[dci]);

	/* Peripheral clocks */
	for (i = fclk0; i <= fclk3; i++)
		zynq_clk_register_fclk(i, clk_output_name[i],
				SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0),
				periph_parents);

	zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL,
			SLCR_LQSPI_CLK_CTRL, periph_parents, 0);

	zynq_clk_register_periph_clk(smc, 0, clk_output_name[smc], NULL,
			SLCR_SMC_CLK_CTRL, periph_parents, 0);

	zynq_clk_register_periph_clk(pcap, 0, clk_output_name[pcap], NULL,
			SLCR_PCAP_CLK_CTRL, periph_parents, 0);

	zynq_clk_register_periph_clk(sdio0, sdio1, clk_output_name[sdio0],
			clk_output_name[sdio1], SLCR_SDIO_CLK_CTRL,
			periph_parents, 1);

	zynq_clk_register_periph_clk(uart0, uart1, clk_output_name[uart0],
			clk_output_name[uart1], SLCR_UART_CLK_CTRL,
			periph_parents, 1);

	zynq_clk_register_periph_clk(spi0, spi1, clk_output_name[spi0],
			clk_output_name[spi1], SLCR_SPI_CLK_CTRL,
			periph_parents, 1);

	for (i = 0; i < ARRAY_SIZE(gem0_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem0_emio_input_names[i]);
		if (idx >= 0)
			gem0_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}
	clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4, 0,
			SLCR_GEM0_CLK_CTRL, 4, 2, 0, &gem0clk_lock);
	clk = clk_register_divider(NULL, "gem0_div0", "gem0_mux", 0,
			SLCR_GEM0_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock);
	clk = clk_register_divider(NULL, "gem0_div1", "gem0_div0",
			CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
			&gem0clk_lock);
	clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2,
			CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0,
			&gem0clk_lock);
	clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0],
			"gem0_emio_mux", CLK_SET_RATE_PARENT,
			SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock);

	for (i = 0; i < ARRAY_SIZE(gem1_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				gem1_emio_input_names[i]);
		if (idx >= 0)
			gem1_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}
	clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4, 0,
			SLCR_GEM1_CLK_CTRL, 4, 2, 0, &gem1clk_lock);
	clk = clk_register_divider(NULL, "gem1_div0", "gem1_mux", 0,
			SLCR_GEM1_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock);
	clk = clk_register_divider(NULL, "gem1_div1", "gem1_div0",
			CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
			&gem1clk_lock);
	clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2,
			CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0,
			&gem1clk_lock);
	clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1],
			"gem1_emio_mux", CLK_SET_RATE_PARENT,
			SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock);

	tmp = strlen("mio_clk_00x");
	clk_name = kmalloc(tmp, GFP_KERNEL);
	for (i = 0; i < NUM_MIO_PINS; i++) {
		int idx;

		snprintf(clk_name, tmp, "mio_clk_%2.2d", i);
		idx = of_property_match_string(np, "clock-names", clk_name);
		if (idx >= 0)
			can_mio_mux_parents[i] = of_clk_get_parent_name(np,
						idx);
		else
			can_mio_mux_parents[i] = dummy_nm;
	}
	kfree(clk_name);
	clk = clk_register_mux(NULL, "can_mux", periph_parents, 4, 0,
			SLCR_CAN_CLK_CTRL, 4, 2, 0, &canclk_lock);
	clk = clk_register_divider(NULL, "can_div0", "can_mux", 0,
			SLCR_CAN_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &canclk_lock);
	clk = clk_register_divider(NULL, "can_div1", "can_div0",
			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 20, 6,
			CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
			&canclk_lock);
	clk = clk_register_gate(NULL, "can0_gate", "can_div1",
			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 0, 0,
			&canclk_lock);
	clk = clk_register_gate(NULL, "can1_gate", "can_div1",
			CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 1, 0,
			&canclk_lock);
	clk = clk_register_mux(NULL, "can0_mio_mux",
			can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
			SLCR_CAN_MIOCLK_CTRL, 0, 6, 0, &canmioclk_lock);
	clk = clk_register_mux(NULL, "can1_mio_mux",
			can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
			SLCR_CAN_MIOCLK_CTRL, 16, 6, 0, &canmioclk_lock);
	clks[can0] = clk_register_mux(NULL, clk_output_name[can0],
			can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
			SLCR_CAN_MIOCLK_CTRL, 6, 1, 0, &canmioclk_lock);
	clks[can1] = clk_register_mux(NULL, clk_output_name[can1],
			can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
			SLCR_CAN_MIOCLK_CTRL, 22, 1, 0, &canmioclk_lock);

	for (i = 0; i < ARRAY_SIZE(dbgtrc_emio_input_names); i++) {
		int idx = of_property_match_string(np, "clock-names",
				dbgtrc_emio_input_names[i]);
		if (idx >= 0)
			dbg_emio_mux_parents[i + 1] = of_clk_get_parent_name(np,
					idx);
	}
	clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4, 0,
			SLCR_DBG_CLK_CTRL, 4, 2, 0, &dbgclk_lock);
	clk = clk_register_divider(NULL, "dbg_div", "dbg_mux", 0,
			SLCR_DBG_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
			CLK_DIVIDER_ALLOW_ZERO, &dbgclk_lock);
	clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2, 0,
			SLCR_DBG_CLK_CTRL, 6, 1, 0, &dbgclk_lock);
	clks[dbg_trc] = clk_register_gate(NULL, clk_output_name[dbg_trc],
			"dbg_emio_mux", CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL,
			0, 0, &dbgclk_lock);
	clks[dbg_apb] = clk_register_gate(NULL, clk_output_name[dbg_apb],
			clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0,
			&dbgclk_lock);

	/* One gated clock for all APER clocks. */
	clks[dma] = clk_register_gate(NULL, clk_output_name[dma],
			clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0,
			&aperclk_lock);
	clks[usb0_aper] = clk_register_gate(NULL, clk_output_name[usb0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 2, 0,
			&aperclk_lock);
	clks[usb1_aper] = clk_register_gate(NULL, clk_output_name[usb1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 3, 0,
			&aperclk_lock);
	clks[gem0_aper] = clk_register_gate(NULL, clk_output_name[gem0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 6, 0,
			&aperclk_lock);
	clks[gem1_aper] = clk_register_gate(NULL, clk_output_name[gem1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 7, 0,
			&aperclk_lock);
	clks[sdio0_aper] = clk_register_gate(NULL, clk_output_name[sdio0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 10, 0,
			&aperclk_lock);
	clks[sdio1_aper] = clk_register_gate(NULL, clk_output_name[sdio1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 11, 0,
			&aperclk_lock);
	clks[spi0_aper] = clk_register_gate(NULL, clk_output_name[spi0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 14, 0,
			&aperclk_lock);
	clks[spi1_aper] = clk_register_gate(NULL, clk_output_name[spi1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 15, 0,
			&aperclk_lock);
	clks[can0_aper] = clk_register_gate(NULL, clk_output_name[can0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 16, 0,
			&aperclk_lock);
	clks[can1_aper] = clk_register_gate(NULL, clk_output_name[can1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 17, 0,
			&aperclk_lock);
	clks[i2c0_aper] = clk_register_gate(NULL, clk_output_name[i2c0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 18, 0,
			&aperclk_lock);
	clks[i2c1_aper] = clk_register_gate(NULL, clk_output_name[i2c1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 19, 0,
			&aperclk_lock);
	clks[uart0_aper] = clk_register_gate(NULL, clk_output_name[uart0_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 20, 0,
			&aperclk_lock);
	clks[uart1_aper] = clk_register_gate(NULL, clk_output_name[uart1_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 21, 0,
			&aperclk_lock);
	clks[gpio_aper] = clk_register_gate(NULL, clk_output_name[gpio_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 22, 0,
			&aperclk_lock);
	clks[lqspi_aper] = clk_register_gate(NULL, clk_output_name[lqspi_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 23, 0,
			&aperclk_lock);
	clks[smc_aper] = clk_register_gate(NULL, clk_output_name[smc_aper],
			clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 24, 0,
			&aperclk_lock);

	for (i = 0; i < ARRAY_SIZE(clks); i++) {
		if (IS_ERR(clks[i])) {
			pr_err("Zynq clk %d: register failed with %ld\n",
			       i, PTR_ERR(clks[i]));
			BUG();
		}
	}

	clk_data.clks = clks;
	clk_data.clk_num = ARRAY_SIZE(clks);
	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
Esempio n. 9
0
/**
 * of_ti_dpll_setup - Setup function for OMAP DPLL clocks
 * @node: device node containing the DPLL info
 * @ops: ops for the DPLL
 * @ddt: DPLL data template to use
 *
 * Initializes a DPLL clock from device tree data.
 */
static void __init of_ti_dpll_setup(struct device_node *node,
				    const struct clk_ops *ops,
				    const struct dpll_data *ddt)
{
	struct clk_hw_omap *clk_hw = NULL;
	struct clk_init_data *init = NULL;
	const char **parent_names = NULL;
	struct dpll_data *dd = NULL;
	int i;
	u8 dpll_mode = 0;

	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
	clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
	init = kzalloc(sizeof(*init), GFP_KERNEL);
	if (!dd || !clk_hw || !init)
		goto cleanup;

	memcpy(dd, ddt, sizeof(*dd));

	clk_hw->dpll_data = dd;
	clk_hw->ops = &clkhwops_omap3_dpll;
	clk_hw->hw.init = init;
	clk_hw->flags = MEMMAP_ADDRESSING;

	init->name = node->name;
	init->ops = ops;

	init->num_parents = of_clk_get_parent_count(node);
	if (init->num_parents < 1) {
		pr_err("%s must have parent(s)\n", node->name);
		goto cleanup;
	}

	parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
	if (!parent_names)
		goto cleanup;

	for (i = 0; i < init->num_parents; i++)
		parent_names[i] = of_clk_get_parent_name(node, i);

	init->parent_names = parent_names;

	dd->control_reg = ti_clk_get_reg_addr(node, 0);

	/*
	 * Special case for OMAP2 DPLL, register order is different due to
	 * missing idlest_reg, also clkhwops is different. Detected from
	 * missing idlest_mask.
	 */
	if (!dd->idlest_mask) {
		dd->mult_div1_reg = ti_clk_get_reg_addr(node, 1);
#ifdef CONFIG_ARCH_OMAP2
		clk_hw->ops = &clkhwops_omap2xxx_dpll;
		omap2xxx_clkt_dpllcore_init(&clk_hw->hw);
#endif
	} else {
		dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
		if (IS_ERR(dd->idlest_reg))
			goto cleanup;

		dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
	}

	if (IS_ERR(dd->control_reg) || IS_ERR(dd->mult_div1_reg))
		goto cleanup;

	if (dd->autoidle_mask) {
		dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
		if (IS_ERR(dd->autoidle_reg))
			goto cleanup;
	}

	if (of_property_read_bool(node, "ti,low-power-stop"))
		dpll_mode |= 1 << DPLL_LOW_POWER_STOP;

	if (of_property_read_bool(node, "ti,low-power-bypass"))
		dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS;

	if (of_property_read_bool(node, "ti,lock"))
		dpll_mode |= 1 << DPLL_LOCKED;

	if (dpll_mode)
		dd->modes = dpll_mode;

	_register_dpll(&clk_hw->hw, node);
	return;

cleanup:
	kfree(dd);
	kfree(parent_names);
	kfree(init);
	kfree(clk_hw);
}
Esempio n. 10
0
static void __init zynq_periph_clk_setup(struct device_node *np)
{
	struct zynq_periph_clk *periph;
	const char *parent_names[3];
	struct clk_init_data init;
	int clk_num = 0, err;
	const char *name;
	struct clk *clk;
	u32 reg;
	int i;

	err = of_property_read_u32(np, "reg", &reg);
	if (WARN_ON(err))
		return;

	periph = kzalloc(sizeof(*periph), GFP_KERNEL);
	if (WARN_ON(!periph))
		return;

	periph->clk_ctrl = slcr_base + reg;
	spin_lock_init(&periph->clkact_lock);

	init.name = np->name;
	init.ops = &zynq_periph_clk_ops;
	for (i = 0; i < ARRAY_SIZE(parent_names); i++)
		parent_names[i] = of_clk_get_parent_name(np, i);
	init.parent_names = parent_names;
	init.num_parents = ARRAY_SIZE(parent_names);

	periph->hw.init = &init;

	clk = clk_register(NULL, &periph->hw);
	if (WARN_ON(IS_ERR(clk)))
		return;

	err = of_clk_add_provider(np, of_clk_src_simple_get, clk);
	if (WARN_ON(err))
		return;

	err = of_property_read_string_index(np, "clock-output-names", 0,
					    &name);
	if (WARN_ON(err))
		return;

	periph->gates[0] = clk_register_gate(NULL, name, np->name, 0,
					     periph->clk_ctrl, 0, 0,
					     &periph->clkact_lock);
	if (WARN_ON(IS_ERR(periph->gates[0])))
		return;
	clk_num++;

	/* some periph clks have 2 downstream gates */
	err = of_property_read_string_index(np, "clock-output-names", 1,
					    &name);
	if (err != -ENODATA) {
		periph->gates[1] = clk_register_gate(NULL, name, np->name, 0,
						     periph->clk_ctrl, 1, 0,
						     &periph->clkact_lock);
		if (WARN_ON(IS_ERR(periph->gates[1])))
			return;
		clk_num++;
	}

	periph->onecell_data.clks = periph->gates;
	periph->onecell_data.clk_num = clk_num;

	err = of_clk_add_provider(np, of_clk_src_onecell_get,
				  &periph->onecell_data);
	if (WARN_ON(err))
		return;
}