1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Zynq UltraScale+ MPSoC clock controller |
4 | * |
5 | * Copyright (C) 2016-2018 Xilinx |
6 | * |
7 | * Gated clock implementation |
8 | */ |
9 | |
10 | #include <linux/clk-provider.h> |
11 | #include <linux/slab.h> |
12 | #include "clk-zynqmp.h" |
13 | |
14 | /** |
15 | * struct zynqmp_clk_gate - gating clock |
16 | * @hw: handle between common and hardware-specific interfaces |
17 | * @flags: hardware-specific flags |
18 | * @clk_id: Id of clock |
19 | */ |
20 | struct zynqmp_clk_gate { |
21 | struct clk_hw hw; |
22 | u8 flags; |
23 | u32 clk_id; |
24 | }; |
25 | |
26 | #define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw) |
27 | |
28 | /** |
29 | * zynqmp_clk_gate_enable() - Enable clock |
30 | * @hw: handle between common and hardware-specific interfaces |
31 | * |
32 | * Return: 0 on success else error code |
33 | */ |
34 | static int zynqmp_clk_gate_enable(struct clk_hw *hw) |
35 | { |
36 | struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); |
37 | const char *clk_name = clk_hw_get_name(hw); |
38 | u32 clk_id = gate->clk_id; |
39 | int ret; |
40 | |
41 | ret = zynqmp_pm_clock_enable(clock_id: clk_id); |
42 | |
43 | if (ret) |
44 | pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n" , |
45 | __func__, clk_name, clk_id, ret); |
46 | |
47 | return ret; |
48 | } |
49 | |
50 | /* |
51 | * zynqmp_clk_gate_disable() - Disable clock |
52 | * @hw: handle between common and hardware-specific interfaces |
53 | */ |
54 | static void zynqmp_clk_gate_disable(struct clk_hw *hw) |
55 | { |
56 | struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); |
57 | const char *clk_name = clk_hw_get_name(hw); |
58 | u32 clk_id = gate->clk_id; |
59 | int ret; |
60 | |
61 | ret = zynqmp_pm_clock_disable(clock_id: clk_id); |
62 | |
63 | if (ret) |
64 | pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n" , |
65 | __func__, clk_name, clk_id, ret); |
66 | } |
67 | |
68 | /** |
69 | * zynqmp_clk_gate_is_enabled() - Check clock state |
70 | * @hw: handle between common and hardware-specific interfaces |
71 | * |
72 | * Return: 1 if enabled, 0 if disabled else error code |
73 | */ |
74 | static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw) |
75 | { |
76 | struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); |
77 | const char *clk_name = clk_hw_get_name(hw); |
78 | u32 clk_id = gate->clk_id; |
79 | int state, ret; |
80 | |
81 | ret = zynqmp_pm_clock_getstate(clock_id: clk_id, state: &state); |
82 | if (ret) { |
83 | pr_debug("%s() clock get state failed for %s, ret = %d\n" , |
84 | __func__, clk_name, ret); |
85 | return -EIO; |
86 | } |
87 | |
88 | return state ? 1 : 0; |
89 | } |
90 | |
91 | static const struct clk_ops zynqmp_clk_gate_ops = { |
92 | .enable = zynqmp_clk_gate_enable, |
93 | .disable = zynqmp_clk_gate_disable, |
94 | .is_enabled = zynqmp_clk_gate_is_enabled, |
95 | }; |
96 | |
97 | /** |
98 | * zynqmp_clk_register_gate() - Register a gate clock with the clock framework |
99 | * @name: Name of this clock |
100 | * @clk_id: Id of this clock |
101 | * @parents: Name of this clock's parents |
102 | * @num_parents: Number of parents |
103 | * @nodes: Clock topology node |
104 | * |
105 | * Return: clock hardware of the registered clock gate |
106 | */ |
107 | struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id, |
108 | const char * const *parents, |
109 | u8 num_parents, |
110 | const struct clock_topology *nodes) |
111 | { |
112 | struct zynqmp_clk_gate *gate; |
113 | struct clk_hw *hw; |
114 | int ret; |
115 | struct clk_init_data init; |
116 | |
117 | /* allocate the gate */ |
118 | gate = kzalloc(size: sizeof(*gate), GFP_KERNEL); |
119 | if (!gate) |
120 | return ERR_PTR(error: -ENOMEM); |
121 | |
122 | init.name = name; |
123 | init.ops = &zynqmp_clk_gate_ops; |
124 | |
125 | init.flags = zynqmp_clk_map_common_ccf_flags(zynqmp_flag: nodes->flag); |
126 | |
127 | init.parent_names = parents; |
128 | init.num_parents = 1; |
129 | |
130 | /* struct clk_gate assignments */ |
131 | gate->flags = nodes->type_flag; |
132 | gate->hw.init = &init; |
133 | gate->clk_id = clk_id; |
134 | |
135 | hw = &gate->hw; |
136 | ret = clk_hw_register(NULL, hw); |
137 | if (ret) { |
138 | kfree(objp: gate); |
139 | hw = ERR_PTR(error: ret); |
140 | } |
141 | |
142 | return hw; |
143 | } |
144 | |