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