Commit | Line | Data |
---|---|---|
3fde0e16 JS |
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 | /** | |
6e1cc688 | 15 | * struct zynqmp_clk_gate - gating clock |
3fde0e16 JS |
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; | |
3fde0e16 | 40 | |
3637e84c | 41 | ret = zynqmp_pm_clock_enable(clk_id); |
3fde0e16 JS |
42 | |
43 | if (ret) | |
4917394e MT |
44 | pr_debug("%s() clock enable failed for %s (id %d), ret = %d\n", |
45 | __func__, clk_name, clk_id, ret); | |
3fde0e16 JS |
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; | |
3fde0e16 | 60 | |
f5ccd54b | 61 | ret = zynqmp_pm_clock_disable(clk_id); |
3fde0e16 JS |
62 | |
63 | if (ret) | |
4917394e MT |
64 | pr_debug("%s() clock disable failed for %s (id %d), ret = %d\n", |
65 | __func__, clk_name, clk_id, ret); | |
3fde0e16 JS |
66 | } |
67 | ||
68 | /** | |
6e1cc688 | 69 | * zynqmp_clk_gate_is_enabled() - Check clock state |
3fde0e16 JS |
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; | |
3fde0e16 | 80 | |
5e76731d | 81 | ret = zynqmp_pm_clock_getstate(clk_id, &state); |
3fde0e16 | 82 | if (ret) { |
4917394e MT |
83 | pr_debug("%s() clock get state failed for %s, ret = %d\n", |
84 | __func__, clk_name, ret); | |
3fde0e16 JS |
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(sizeof(*gate), GFP_KERNEL); | |
119 | if (!gate) | |
120 | return ERR_PTR(-ENOMEM); | |
121 | ||
122 | init.name = name; | |
123 | init.ops = &zynqmp_clk_gate_ops; | |
610a5d83 RV |
124 | |
125 | init.flags = zynqmp_clk_map_common_ccf_flags(nodes->flag); | |
126 | ||
3fde0e16 JS |
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(gate); | |
139 | hw = ERR_PTR(ret); | |
140 | } | |
141 | ||
142 | return hw; | |
143 | } |