Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: scmi: Add support for clock {set,get}_parent

SCMI v3.2 adds set/get parent clock commands, so update the SCMI clock
driver to support them.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
Link: https://lore.kernel.org/r/20231004-scmi-clock-v3-v5-2-1b8a1435673e@nxp.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

authored by

Peng Fan and committed by
Sudeep Holla
65a8a3dd 77bbfe60

+60 -1
+60 -1
drivers/clk/clk-scmi.c
··· 24 24 struct clk_hw hw; 25 25 const struct scmi_clock_info *info; 26 26 const struct scmi_protocol_handle *ph; 27 + struct clk_parent_data *parent_data; 27 28 }; 28 29 29 30 #define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw) ··· 77 76 struct scmi_clk *clk = to_scmi_clk(hw); 78 77 79 78 return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate); 79 + } 80 + 81 + static int scmi_clk_set_parent(struct clk_hw *hw, u8 parent_index) 82 + { 83 + struct scmi_clk *clk = to_scmi_clk(hw); 84 + 85 + return scmi_proto_clk_ops->parent_set(clk->ph, clk->id, parent_index); 86 + } 87 + 88 + static u8 scmi_clk_get_parent(struct clk_hw *hw) 89 + { 90 + struct scmi_clk *clk = to_scmi_clk(hw); 91 + u32 parent_id, p_idx; 92 + int ret; 93 + 94 + ret = scmi_proto_clk_ops->parent_get(clk->ph, clk->id, &parent_id); 95 + if (ret) 96 + return 0; 97 + 98 + for (p_idx = 0; p_idx < clk->info->num_parents; p_idx++) { 99 + if (clk->parent_data[p_idx].index == parent_id) 100 + break; 101 + } 102 + 103 + if (p_idx == clk->info->num_parents) 104 + return 0; 105 + 106 + return p_idx; 107 + } 108 + 109 + static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) 110 + { 111 + /* 112 + * Suppose all the requested rates are supported, and let firmware 113 + * to handle the left work. 114 + */ 115 + return 0; 80 116 } 81 117 82 118 static int scmi_clk_enable(struct clk_hw *hw) ··· 177 139 .set_rate = scmi_clk_set_rate, 178 140 .prepare = scmi_clk_enable, 179 141 .unprepare = scmi_clk_disable, 142 + .set_parent = scmi_clk_set_parent, 143 + .get_parent = scmi_clk_get_parent, 144 + .determine_rate = scmi_clk_determine_rate, 180 145 }; 181 146 182 147 static const struct clk_ops scmi_atomic_clk_ops = { ··· 189 148 .enable = scmi_clk_atomic_enable, 190 149 .disable = scmi_clk_atomic_disable, 191 150 .is_enabled = scmi_clk_atomic_is_enabled, 151 + .set_parent = scmi_clk_set_parent, 152 + .get_parent = scmi_clk_get_parent, 153 + .determine_rate = scmi_clk_determine_rate, 192 154 }; 193 155 194 156 static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk, ··· 202 158 203 159 struct clk_init_data init = { 204 160 .flags = CLK_GET_RATE_NOCACHE, 205 - .num_parents = 0, 161 + .num_parents = sclk->info->num_parents, 206 162 .ops = scmi_ops, 207 163 .name = sclk->info->name, 164 + .parent_data = sclk->parent_data, 208 165 }; 209 166 210 167 sclk->hw.init = &init; ··· 296 251 else 297 252 scmi_ops = &scmi_clk_ops; 298 253 254 + /* Initialize clock parent data. */ 255 + if (sclk->info->num_parents > 0) { 256 + sclk->parent_data = devm_kcalloc(dev, sclk->info->num_parents, 257 + sizeof(*sclk->parent_data), GFP_KERNEL); 258 + if (!sclk->parent_data) 259 + return -ENOMEM; 260 + 261 + for (int i = 0; i < sclk->info->num_parents; i++) { 262 + sclk->parent_data[i].index = sclk->info->parents[i]; 263 + sclk->parent_data[i].hw = hws[sclk->info->parents[i]]; 264 + } 265 + } 266 + 299 267 err = scmi_clk_ops_init(dev, sclk, scmi_ops); 300 268 if (err) { 301 269 dev_err(dev, "failed to register clock %d\n", idx); 270 + devm_kfree(dev, sclk->parent_data); 302 271 devm_kfree(dev, sclk); 303 272 hws[idx] = NULL; 304 273 } else {