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 long rate; 61 62 rate = owl_divider_helper_round_rate(&comp->common, &comp->rate.div_hw, 63 req->rate, &req->best_parent_rate); 64 if (rate < 0) 65 return rate; 66 67 req->rate = rate; 68 return 0; 69 } 70 71 static unsigned long owl_comp_div_recalc_rate(struct clk_hw *hw, 72 unsigned long parent_rate) 73 { 74 struct owl_composite *comp = hw_to_owl_comp(hw); 75 76 return owl_divider_helper_recalc_rate(&comp->common, &comp->rate.div_hw, 77 parent_rate); 78 } 79 80 static int owl_comp_div_set_rate(struct clk_hw *hw, unsigned long rate, 81 unsigned long parent_rate) 82 { 83 struct owl_composite *comp = hw_to_owl_comp(hw); 84 85 return owl_divider_helper_set_rate(&comp->common, &comp->rate.div_hw, 86 rate, parent_rate); 87 } 88 89 static int owl_comp_fact_determine_rate(struct clk_hw *hw, 90 struct clk_rate_request *req) 91 { 92 struct owl_composite *comp = hw_to_owl_comp(hw); 93 long rate; 94 95 rate = owl_factor_helper_round_rate(&comp->common, 96 &comp->rate.factor_hw, 97 req->rate, &req->best_parent_rate); 98 if (rate < 0) 99 return rate; 100 101 req->rate = rate; 102 return 0; 103 } 104 105 static unsigned long owl_comp_fact_recalc_rate(struct clk_hw *hw, 106 unsigned long parent_rate) 107 { 108 struct owl_composite *comp = hw_to_owl_comp(hw); 109 110 return owl_factor_helper_recalc_rate(&comp->common, 111 &comp->rate.factor_hw, 112 parent_rate); 113 } 114 115 static int owl_comp_fact_set_rate(struct clk_hw *hw, unsigned long rate, 116 unsigned long parent_rate) 117 { 118 struct owl_composite *comp = hw_to_owl_comp(hw); 119 120 return owl_factor_helper_set_rate(&comp->common, 121 &comp->rate.factor_hw, 122 rate, parent_rate); 123 } 124 125 static long owl_comp_fix_fact_round_rate(struct clk_hw *hw, unsigned long rate, 126 unsigned long *parent_rate) 127 { 128 struct owl_composite *comp = hw_to_owl_comp(hw); 129 struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw; 130 131 return comp->fix_fact_ops->round_rate(&fix_fact_hw->hw, rate, parent_rate); 132 } 133 134 static unsigned long owl_comp_fix_fact_recalc_rate(struct clk_hw *hw, 135 unsigned long parent_rate) 136 { 137 struct owl_composite *comp = hw_to_owl_comp(hw); 138 struct clk_fixed_factor *fix_fact_hw = &comp->rate.fix_fact_hw; 139 140 return comp->fix_fact_ops->recalc_rate(&fix_fact_hw->hw, parent_rate); 141 142 } 143 144 static int owl_comp_fix_fact_set_rate(struct clk_hw *hw, unsigned long rate, 145 unsigned long parent_rate) 146 { 147 /* 148 * We must report success but we can do so unconditionally because 149 * owl_comp_fix_fact_round_rate returns values that ensure this call is 150 * a nop. 151 */ 152 153 return 0; 154 } 155 156 const struct clk_ops owl_comp_div_ops = { 157 /* mux_ops */ 158 .get_parent = owl_comp_get_parent, 159 .set_parent = owl_comp_set_parent, 160 161 /* gate_ops */ 162 .disable = owl_comp_disable, 163 .enable = owl_comp_enable, 164 .is_enabled = owl_comp_is_enabled, 165 166 /* div_ops */ 167 .determine_rate = owl_comp_div_determine_rate, 168 .recalc_rate = owl_comp_div_recalc_rate, 169 .set_rate = owl_comp_div_set_rate, 170 }; 171 172 173 const struct clk_ops owl_comp_fact_ops = { 174 /* mux_ops */ 175 .get_parent = owl_comp_get_parent, 176 .set_parent = owl_comp_set_parent, 177 178 /* gate_ops */ 179 .disable = owl_comp_disable, 180 .enable = owl_comp_enable, 181 .is_enabled = owl_comp_is_enabled, 182 183 /* fact_ops */ 184 .determine_rate = owl_comp_fact_determine_rate, 185 .recalc_rate = owl_comp_fact_recalc_rate, 186 .set_rate = owl_comp_fact_set_rate, 187 }; 188 189 const struct clk_ops owl_comp_fix_fact_ops = { 190 /* gate_ops */ 191 .disable = owl_comp_disable, 192 .enable = owl_comp_enable, 193 .is_enabled = owl_comp_is_enabled, 194 195 /* fix_fact_ops */ 196 .round_rate = owl_comp_fix_fact_round_rate, 197 .recalc_rate = owl_comp_fix_fact_recalc_rate, 198 .set_rate = owl_comp_fix_fact_set_rate, 199 }; 200 201 202 const struct clk_ops owl_comp_pass_ops = { 203 /* mux_ops */ 204 .determine_rate = clk_hw_determine_rate_no_reparent, 205 .get_parent = owl_comp_get_parent, 206 .set_parent = owl_comp_set_parent, 207 208 /* gate_ops */ 209 .disable = owl_comp_disable, 210 .enable = owl_comp_enable, 211 .is_enabled = owl_comp_is_enabled, 212 }; 213