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