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 16static 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 23static 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 30static 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 38static 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 48static 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 56static 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 71static 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 80static 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 89static 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 105static 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 115static 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 125static 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 134static 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 144static 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 156const 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 173const 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 189const 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 202const 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