1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2013 Emilio López |
4 | * |
5 | * Emilio López <emilio@elopez.com.ar> |
6 | */ |
7 | |
8 | #include <linux/clk-provider.h> |
9 | #include <linux/io.h> |
10 | #include <linux/of.h> |
11 | #include <linux/of_address.h> |
12 | #include <linux/slab.h> |
13 | |
14 | static DEFINE_SPINLOCK(mod1_lock); |
15 | |
16 | #define SUN4I_MOD1_ENABLE 31 |
17 | #define SUN4I_MOD1_MUX 16 |
18 | #define SUN4I_MOD1_MUX_WIDTH 2 |
19 | #define SUN4I_MOD1_MAX_PARENTS 4 |
20 | |
21 | static void __init sun4i_mod1_clk_setup(struct device_node *node) |
22 | { |
23 | struct clk *clk; |
24 | struct clk_mux *mux; |
25 | struct clk_gate *gate; |
26 | const char *parents[4]; |
27 | const char *clk_name = node->name; |
28 | void __iomem *reg; |
29 | int i; |
30 | |
31 | reg = of_io_request_and_map(device: node, index: 0, name: of_node_full_name(np: node)); |
32 | if (IS_ERR(ptr: reg)) |
33 | return; |
34 | |
35 | mux = kzalloc(size: sizeof(*mux), GFP_KERNEL); |
36 | if (!mux) |
37 | goto err_unmap; |
38 | |
39 | gate = kzalloc(size: sizeof(*gate), GFP_KERNEL); |
40 | if (!gate) |
41 | goto err_free_mux; |
42 | |
43 | of_property_read_string(np: node, propname: "clock-output-names" , out_string: &clk_name); |
44 | i = of_clk_parent_fill(np: node, parents, SUN4I_MOD1_MAX_PARENTS); |
45 | |
46 | gate->reg = reg; |
47 | gate->bit_idx = SUN4I_MOD1_ENABLE; |
48 | gate->lock = &mod1_lock; |
49 | mux->reg = reg; |
50 | mux->shift = SUN4I_MOD1_MUX; |
51 | mux->mask = BIT(SUN4I_MOD1_MUX_WIDTH) - 1; |
52 | mux->lock = &mod1_lock; |
53 | |
54 | clk = clk_register_composite(NULL, name: clk_name, parent_names: parents, num_parents: i, |
55 | mux_hw: &mux->hw, mux_ops: &clk_mux_ops, |
56 | NULL, NULL, |
57 | gate_hw: &gate->hw, gate_ops: &clk_gate_ops, CLK_SET_RATE_PARENT); |
58 | if (IS_ERR(ptr: clk)) |
59 | goto err_free_gate; |
60 | |
61 | of_clk_add_provider(np: node, clk_src_get: of_clk_src_simple_get, data: clk); |
62 | |
63 | return; |
64 | |
65 | err_free_gate: |
66 | kfree(objp: gate); |
67 | err_free_mux: |
68 | kfree(objp: mux); |
69 | err_unmap: |
70 | iounmap(addr: reg); |
71 | } |
72 | CLK_OF_DECLARE(sun4i_mod1, "allwinner,sun4i-a10-mod1-clk" , |
73 | sun4i_mod1_clk_setup); |
74 | |