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