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