xref: /openbmc/linux/drivers/clk/sunxi/clk-sun4i-pll3.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2fa4d0ca1SMaxime Ripard /*
3fa4d0ca1SMaxime Ripard  * Copyright 2015 Maxime Ripard
4fa4d0ca1SMaxime Ripard  *
5fa4d0ca1SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
6fa4d0ca1SMaxime Ripard  */
7fa4d0ca1SMaxime Ripard 
8fa4d0ca1SMaxime Ripard #include <linux/clk-provider.h>
962e59c4eSStephen Boyd #include <linux/io.h>
10fa4d0ca1SMaxime Ripard #include <linux/of.h>
11fa4d0ca1SMaxime Ripard #include <linux/of_address.h>
12fa4d0ca1SMaxime Ripard #include <linux/slab.h>
13fa4d0ca1SMaxime Ripard #include <linux/spinlock.h>
14fa4d0ca1SMaxime Ripard 
15fa4d0ca1SMaxime Ripard #define SUN4I_A10_PLL3_GATE_BIT	31
16fa4d0ca1SMaxime Ripard #define SUN4I_A10_PLL3_DIV_WIDTH	7
17fa4d0ca1SMaxime Ripard #define SUN4I_A10_PLL3_DIV_SHIFT	0
18fa4d0ca1SMaxime Ripard 
19fa4d0ca1SMaxime Ripard static DEFINE_SPINLOCK(sun4i_a10_pll3_lock);
20fa4d0ca1SMaxime Ripard 
sun4i_a10_pll3_setup(struct device_node * node)21fa4d0ca1SMaxime Ripard static void __init sun4i_a10_pll3_setup(struct device_node *node)
22fa4d0ca1SMaxime Ripard {
23fa4d0ca1SMaxime Ripard 	const char *clk_name = node->name, *parent;
24fa4d0ca1SMaxime Ripard 	struct clk_multiplier *mult;
25fa4d0ca1SMaxime Ripard 	struct clk_gate *gate;
26fa4d0ca1SMaxime Ripard 	struct resource res;
27fa4d0ca1SMaxime Ripard 	void __iomem *reg;
28fa4d0ca1SMaxime Ripard 	struct clk *clk;
29fa4d0ca1SMaxime Ripard 	int ret;
30fa4d0ca1SMaxime Ripard 
31fa4d0ca1SMaxime Ripard 	of_property_read_string(node, "clock-output-names", &clk_name);
32fa4d0ca1SMaxime Ripard 	parent = of_clk_get_parent_name(node, 0);
33fa4d0ca1SMaxime Ripard 
34fa4d0ca1SMaxime Ripard 	reg = of_io_request_and_map(node, 0, of_node_full_name(node));
35fa4d0ca1SMaxime Ripard 	if (IS_ERR(reg)) {
36fa4d0ca1SMaxime Ripard 		pr_err("%s: Could not map the clock registers\n", clk_name);
37fa4d0ca1SMaxime Ripard 		return;
38fa4d0ca1SMaxime Ripard 	}
39fa4d0ca1SMaxime Ripard 
40fa4d0ca1SMaxime Ripard 	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
41fa4d0ca1SMaxime Ripard 	if (!gate)
42fa4d0ca1SMaxime Ripard 		goto err_unmap;
43fa4d0ca1SMaxime Ripard 
44fa4d0ca1SMaxime Ripard 	gate->reg = reg;
45fa4d0ca1SMaxime Ripard 	gate->bit_idx = SUN4I_A10_PLL3_GATE_BIT;
46fa4d0ca1SMaxime Ripard 	gate->lock = &sun4i_a10_pll3_lock;
47fa4d0ca1SMaxime Ripard 
48fa4d0ca1SMaxime Ripard 	mult = kzalloc(sizeof(*mult), GFP_KERNEL);
49fa4d0ca1SMaxime Ripard 	if (!mult)
50fa4d0ca1SMaxime Ripard 		goto err_free_gate;
51fa4d0ca1SMaxime Ripard 
52fa4d0ca1SMaxime Ripard 	mult->reg = reg;
53fa4d0ca1SMaxime Ripard 	mult->shift = SUN4I_A10_PLL3_DIV_SHIFT;
54fa4d0ca1SMaxime Ripard 	mult->width = SUN4I_A10_PLL3_DIV_WIDTH;
55fa4d0ca1SMaxime Ripard 	mult->lock = &sun4i_a10_pll3_lock;
56fa4d0ca1SMaxime Ripard 
57fa4d0ca1SMaxime Ripard 	clk = clk_register_composite(NULL, clk_name,
58fa4d0ca1SMaxime Ripard 				     &parent, 1,
59fa4d0ca1SMaxime Ripard 				     NULL, NULL,
60fa4d0ca1SMaxime Ripard 				     &mult->hw, &clk_multiplier_ops,
61fa4d0ca1SMaxime Ripard 				     &gate->hw, &clk_gate_ops,
62fa4d0ca1SMaxime Ripard 				     0);
63fa4d0ca1SMaxime Ripard 	if (IS_ERR(clk)) {
64fa4d0ca1SMaxime Ripard 		pr_err("%s: Couldn't register the clock\n", clk_name);
65fa4d0ca1SMaxime Ripard 		goto err_free_mult;
66fa4d0ca1SMaxime Ripard 	}
67fa4d0ca1SMaxime Ripard 
68fa4d0ca1SMaxime Ripard 	ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
69fa4d0ca1SMaxime Ripard 	if (ret) {
70fa4d0ca1SMaxime Ripard 		pr_err("%s: Couldn't register DT provider\n",
71fa4d0ca1SMaxime Ripard 		       clk_name);
72fa4d0ca1SMaxime Ripard 		goto err_clk_unregister;
73fa4d0ca1SMaxime Ripard 	}
74fa4d0ca1SMaxime Ripard 
75fa4d0ca1SMaxime Ripard 	return;
76fa4d0ca1SMaxime Ripard 
77fa4d0ca1SMaxime Ripard err_clk_unregister:
78fa4d0ca1SMaxime Ripard 	clk_unregister_composite(clk);
79fa4d0ca1SMaxime Ripard err_free_mult:
80fa4d0ca1SMaxime Ripard 	kfree(mult);
81fa4d0ca1SMaxime Ripard err_free_gate:
82fa4d0ca1SMaxime Ripard 	kfree(gate);
83fa4d0ca1SMaxime Ripard err_unmap:
84fa4d0ca1SMaxime Ripard 	iounmap(reg);
85fa4d0ca1SMaxime Ripard 	of_address_to_resource(node, 0, &res);
86fa4d0ca1SMaxime Ripard 	release_mem_region(res.start, resource_size(&res));
87fa4d0ca1SMaxime Ripard }
88fa4d0ca1SMaxime Ripard 
89fa4d0ca1SMaxime Ripard CLK_OF_DECLARE(sun4i_a10_pll3, "allwinner,sun4i-a10-pll3-clk",
90fa4d0ca1SMaxime Ripard 	       sun4i_a10_pll3_setup);
91