xref: /linux/drivers/clk/actions/owl-composite.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
1 // SPDX-License-Identifier: GPL-2.0+
2 //
3 // OWL composite clock driver
4 //
5 // Copyright (c) 2014 Actions Semi Inc.
6 // Author: David Liu <liuwei@actions-semi.com>
7 //
8 // Copyright (c) 2018 Linaro Ltd.
9 // Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
10 
11 #include <linux/clk-provider.h>
12 #include <linux/regmap.h>
13 
14 #include "owl-composite.h"
15 
16 static u8 owl_comp_get_parent(struct clk_hw *hw)
17 {
18 	struct owl_composite *comp = hw_to_owl_comp(hw);
19 
20 	return owl_mux_helper_get_parent(&comp->common, &comp->mux_hw);
21 }
22 
23 static int owl_comp_set_parent(struct clk_hw *hw, u8 index)
24 {
25 	struct owl_composite *comp = hw_to_owl_comp(hw);
26 
27 	return owl_mux_helper_set_parent(&comp->common, &comp->mux_hw, index);
28 }
29 
30 static void owl_comp_disable(struct clk_hw *hw)
31 {
32 	struct owl_composite *comp = hw_to_owl_comp(hw);
33 	struct owl_clk_common *common = &comp->common;
34 
35 	owl_gate_set(common, &comp->gate_hw, false);
36 }
37 
38 static int owl_comp_enable(struct clk_hw *hw)
39 {
40 	struct owl_composite *comp = hw_to_owl_comp(hw);
41 	struct owl_clk_common *common = &comp->common;
42 
43 	owl_gate_set(common, &comp->gate_hw, true);
44 
45 	return 0;
46 }
47 
48 static int owl_comp_is_enabled(struct clk_hw *hw)
49 {
50 	struct owl_composite *comp = hw_to_owl_comp(hw);
51 	struct owl_clk_common *common = &comp->common;
52 
53 	return owl_gate_clk_is_enabled(common, &comp->gate_hw);
54 }
55 
56 static int owl_comp_div_determine_rate(struct clk_hw *hw,
57 				       struct clk_rate_request *req)
58 {
59 	struct owl_composite *comp = hw_to_owl_comp(hw);
60 	struct owl_divider_hw *div = &comp->rate.div_hw;
61 
62 	return divider_determine_rate(&comp->common.hw, req, div->table,
63 				      div->width, div->div_flags);
64 }
65 
66 static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw,
67 					  unsigned long parent_rate)
68 {
69 	struct owl_composite *comp = hw_to_owl_comp(hw);
70 
71 	return owl_divider_helper_recalc_rate(&comp->common, &comp->rate.div_hw,
72 					parent_rate);
73 }
74 
75 static int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate,
76 				unsigned long parent_rate)
77 {
78 	struct owl_composite *comp = hw_to_owl_comp(hw);
79 
80 	return owl_divider_helper_set_rate(&comp->common, &comp->rate.div_hw,
81 					rate, parent_rate);
82 }
83 
84 static int owl_comp_fact_determine_rate(struct clk_hw *hw,
85 					struct clk_rate_request *req)
86 {
87 	struct owl_composite *comp = hw_to_owl_comp(hw);
88 	long rate;
89 
90 	rate = owl_factor_helper_round_rate(&comp->common,
91 					    &comp->rate.factor_hw,
92 					    req->rate, &req->best_parent_rate);
93 	if (rate < 0)
94 		return rate;
95 
96 	req->rate = rate;
97 	return 0;
98 }
99 
100 static unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw,
101 			unsigned long parent_rate)
102 {
103 	struct owl_composite *comp = hw_to_owl_comp(hw);
104 
105 	return owl_factor_helper_recalc_rate(&comp->common,
106 					&comp->rate.factor_hw,
107 					parent_rate);
108 }
109 
110 static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate,
111 			unsigned long parent_rate)
112 {
113 	struct owl_composite *comp = hw_to_owl_comp(hw);
114 
115 	return owl_factor_helper_set_rate(&comp->common,
116 					&comp->rate.factor_hw,
117 					rate, parent_rate);
118 }
119 
120 static int owl_comp_fix_fact_determine_rate(struct clk_hw *hw,
121 					    struct clk_rate_request *req)
122 {
123 	struct owl_composite *comp = hw_to_owl_comp(hw);
124 	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
125 
126 	return comp->fix_fact_ops->determine_rate(&fix_fact_hw->hw, req);
127 }
128 
129 static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw,
130 			unsigned long parent_rate)
131 {
132 	struct owl_composite *comp = hw_to_owl_comp(hw);
133 	struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw;
134 
135 	return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate);
136 
137 }
138 
139 static int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate,
140 			unsigned long parent_rate)
141 {
142 	/*
143 	 * We must report success but we can do so unconditionally because
144 	 * owl_comp_fix_fact_round_rate returns values that ensure this call is
145 	 * a nop.
146 	 */
147 
148 	return 0;
149 }
150 
151 const struct clk_ops owl_comp_div_ops = {
152 	/* mux_ops */
153 	.get_parent	= owl_comp_get_parent,
154 	.set_parent	= owl_comp_set_parent,
155 
156 	/* gate_ops */
157 	.disable	= owl_comp_disable,
158 	.enable		= owl_comp_enable,
159 	.is_enabled	= owl_comp_is_enabled,
160 
161 	/* div_ops */
162 	.determine_rate	= owl_comp_div_determine_rate,
163 	.recalc_rate	= owl_comp_div_recalc_rate,
164 	.set_rate	= owl_comp_div_set_rate,
165 };
166 
167 
168 const struct clk_ops owl_comp_fact_ops = {
169 	/* mux_ops */
170 	.get_parent	= owl_comp_get_parent,
171 	.set_parent	= owl_comp_set_parent,
172 
173 	/* gate_ops */
174 	.disable	= owl_comp_disable,
175 	.enable		= owl_comp_enable,
176 	.is_enabled	= owl_comp_is_enabled,
177 
178 	/* fact_ops */
179 	.determine_rate	= owl_comp_fact_determine_rate,
180 	.recalc_rate	= owl_comp_fact_recalc_rate,
181 	.set_rate	= owl_comp_fact_set_rate,
182 };
183 
184 const struct clk_ops owl_comp_fix_fact_ops = {
185 	/* gate_ops */
186 	.disable	= owl_comp_disable,
187 	.enable		= owl_comp_enable,
188 	.is_enabled	= owl_comp_is_enabled,
189 
190 	/* fix_fact_ops */
191 	.determine_rate = owl_comp_fix_fact_determine_rate,
192 	.recalc_rate	= owl_comp_fix_fact_recalc_rate,
193 	.set_rate	= owl_comp_fix_fact_set_rate,
194 };
195 
196 
197 const struct clk_ops owl_comp_pass_ops = {
198 	/* mux_ops */
199 	.determine_rate	= clk_hw_determine_rate_no_reparent,
200 	.get_parent	= owl_comp_get_parent,
201 	.set_parent	= owl_comp_set_parent,
202 
203 	/* gate_ops */
204 	.disable	= owl_comp_disable,
205 	.enable		= owl_comp_enable,
206 	.is_enabled	= owl_comp_is_enabled,
207 };
208