]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/regulator/scmi-regulator.c
Merge tag 'sunxi-dt-for-5.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-jammy-kernel.git] / drivers / regulator / scmi-regulator.c
CommitLineData
0fbeae70
CM
1// SPDX-License-Identifier: GPL-2.0
2//
3// System Control and Management Interface (SCMI) based regulator driver
4//
59046d15 5// Copyright (C) 2020-2021 ARM Ltd.
0fbeae70
CM
6//
7// Implements a regulator driver on top of the SCMI Voltage Protocol.
8//
9// The ARM SCMI Protocol aims in general to hide as much as possible all the
10// underlying operational details while providing an abstracted interface for
11// its users to operate upon: as a consequence the resulting operational
12// capabilities and configurability of this regulator device are much more
13// limited than the ones usually available on a standard physical regulator.
14//
15// The supported SCMI regulator ops are restricted to the bare minimum:
16//
17// - 'status_ops': enable/disable/is_enabled
18// - 'voltage_ops': get_voltage_sel/set_voltage_sel
19// list_voltage/map_voltage
20//
21// Each SCMI regulator instance is associated, through the means of a proper DT
22// entry description, to a specific SCMI Voltage Domain.
23
24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25
26#include <linux/linear_range.h>
27#include <linux/module.h>
28#include <linux/of.h>
29#include <linux/regulator/driver.h>
30#include <linux/regulator/machine.h>
31#include <linux/regulator/of_regulator.h>
32#include <linux/scmi_protocol.h>
33#include <linux/slab.h>
34#include <linux/types.h>
35
59046d15
CM
36static const struct scmi_voltage_proto_ops *voltage_ops;
37
0fbeae70
CM
38struct scmi_regulator {
39 u32 id;
40 struct scmi_device *sdev;
59046d15 41 struct scmi_protocol_handle *ph;
0fbeae70
CM
42 struct regulator_dev *rdev;
43 struct device_node *of_node;
44 struct regulator_desc desc;
45 struct regulator_config conf;
46};
47
48struct scmi_regulator_info {
49 int num_doms;
50 struct scmi_regulator **sregv;
51};
52
53static int scmi_reg_enable(struct regulator_dev *rdev)
54{
55 struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
0fbeae70 56
59046d15
CM
57 return voltage_ops->config_set(sreg->ph, sreg->id,
58 SCMI_VOLTAGE_ARCH_STATE_ON);
0fbeae70
CM
59}
60
61static int scmi_reg_disable(struct regulator_dev *rdev)
62{
63 struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
0fbeae70 64
59046d15
CM
65 return voltage_ops->config_set(sreg->ph, sreg->id,
66 SCMI_VOLTAGE_ARCH_STATE_OFF);
0fbeae70
CM
67}
68
69static int scmi_reg_is_enabled(struct regulator_dev *rdev)
70{
71 int ret;
72 u32 config;
73 struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
0fbeae70 74
59046d15 75 ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
0fbeae70
CM
76 if (ret) {
77 dev_err(&sreg->sdev->dev,
78 "Error %d reading regulator %s status.\n",
79 ret, sreg->desc.name);
80 return ret;
81 }
82
83 return config & SCMI_VOLTAGE_ARCH_STATE_ON;
84}
85
86static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
87{
88 int ret;
89 s32 volt_uV;
90 struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
0fbeae70 91
59046d15 92 ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
0fbeae70
CM
93 if (ret)
94 return ret;
95
96 return sreg->desc.ops->map_voltage(rdev, volt_uV, volt_uV);
97}
98
99static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
100 unsigned int selector)
101{
102 s32 volt_uV;
103 struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
0fbeae70
CM
104
105 volt_uV = sreg->desc.ops->list_voltage(rdev, selector);
106 if (volt_uV <= 0)
107 return -EINVAL;
108
59046d15 109 return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
0fbeae70
CM
110}
111
112static const struct regulator_ops scmi_reg_fixed_ops = {
113 .enable = scmi_reg_enable,
114 .disable = scmi_reg_disable,
115 .is_enabled = scmi_reg_is_enabled,
116};
117
118static const struct regulator_ops scmi_reg_linear_ops = {
119 .enable = scmi_reg_enable,
120 .disable = scmi_reg_disable,
121 .is_enabled = scmi_reg_is_enabled,
122 .get_voltage_sel = scmi_reg_get_voltage_sel,
123 .set_voltage_sel = scmi_reg_set_voltage_sel,
124 .list_voltage = regulator_list_voltage_linear,
125 .map_voltage = regulator_map_voltage_linear,
126};
127
128static const struct regulator_ops scmi_reg_discrete_ops = {
129 .enable = scmi_reg_enable,
130 .disable = scmi_reg_disable,
131 .is_enabled = scmi_reg_is_enabled,
132 .get_voltage_sel = scmi_reg_get_voltage_sel,
133 .set_voltage_sel = scmi_reg_set_voltage_sel,
134 .list_voltage = regulator_list_voltage_table,
135 .map_voltage = regulator_map_voltage_iterate,
136};
137
138static int
139scmi_config_linear_regulator_mappings(struct scmi_regulator *sreg,
140 const struct scmi_voltage_info *vinfo)
141{
142 s32 delta_uV;
143
144 /*
145 * Note that SCMI voltage domains describable by linear ranges
146 * (segments) {low, high, step} are guaranteed to come in one single
147 * triplet by the SCMI Voltage Domain protocol support itself.
148 */
149
150 delta_uV = (vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH] -
151 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW]);
152
153 /* Rule out buggy negative-intervals answers from fw */
154 if (delta_uV < 0) {
155 dev_err(&sreg->sdev->dev,
156 "Invalid volt-range %d-%duV for domain %d\n",
157 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW],
158 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH],
159 sreg->id);
160 return -EINVAL;
161 }
162
163 if (!delta_uV) {
164 /* Just one fixed voltage exposed by SCMI */
165 sreg->desc.fixed_uV =
166 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
167 sreg->desc.n_voltages = 1;
168 sreg->desc.ops = &scmi_reg_fixed_ops;
169 } else {
170 /* One simple linear mapping. */
171 sreg->desc.min_uV =
172 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
173 sreg->desc.uV_step =
174 vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_STEP];
175 sreg->desc.linear_min_sel = 0;
36cb555f 176 sreg->desc.n_voltages = (delta_uV / sreg->desc.uV_step) + 1;
0fbeae70
CM
177 sreg->desc.ops = &scmi_reg_linear_ops;
178 }
179
180 return 0;
181}
182
183static int
184scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
185 const struct scmi_voltage_info *vinfo)
186{
187 /* Discrete non linear levels are mapped to volt_table */
188 sreg->desc.n_voltages = vinfo->num_levels;
189
190 if (sreg->desc.n_voltages > 1) {
191 sreg->desc.volt_table = (const unsigned int *)vinfo->levels_uv;
192 sreg->desc.ops = &scmi_reg_discrete_ops;
193 } else {
194 sreg->desc.fixed_uV = vinfo->levels_uv[0];
195 sreg->desc.ops = &scmi_reg_fixed_ops;
196 }
197
198 return 0;
199}
200
201static int scmi_regulator_common_init(struct scmi_regulator *sreg)
202{
203 int ret;
0fbeae70
CM
204 struct device *dev = &sreg->sdev->dev;
205 const struct scmi_voltage_info *vinfo;
206
59046d15 207 vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
0fbeae70
CM
208 if (!vinfo) {
209 dev_warn(dev, "Failure to get voltage domain %d\n",
210 sreg->id);
211 return -ENODEV;
212 }
213
214 /*
215 * Regulator framework does not fully support negative voltages
216 * so we discard any voltage domain reported as supporting negative
217 * voltages: as a consequence each levels_uv entry is guaranteed to
218 * be non-negative from here on.
219 */
220 if (vinfo->negative_volts_allowed) {
221 dev_warn(dev, "Negative voltages NOT supported...skip %s\n",
222 sreg->of_node->full_name);
223 return -EOPNOTSUPP;
224 }
225
226 sreg->desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s", vinfo->name);
227 if (!sreg->desc.name)
228 return -ENOMEM;
229
230 sreg->desc.id = sreg->id;
231 sreg->desc.type = REGULATOR_VOLTAGE;
232 sreg->desc.owner = THIS_MODULE;
233 sreg->desc.of_match_full_name = true;
234 sreg->desc.of_match = sreg->of_node->full_name;
235 sreg->desc.regulators_node = "regulators";
236 if (vinfo->segmented)
237 ret = scmi_config_linear_regulator_mappings(sreg, vinfo);
238 else
239 ret = scmi_config_discrete_regulator_mappings(sreg, vinfo);
240 if (ret)
241 return ret;
242
243 /*
244 * Using the scmi device here to have DT searched from Voltage
245 * protocol node down.
246 */
247 sreg->conf.dev = dev;
248
249 /* Store for later retrieval via rdev_get_drvdata() */
250 sreg->conf.driver_data = sreg;
251
252 return 0;
253}
254
255static int process_scmi_regulator_of_node(struct scmi_device *sdev,
59046d15 256 struct scmi_protocol_handle *ph,
0fbeae70
CM
257 struct device_node *np,
258 struct scmi_regulator_info *rinfo)
259{
260 u32 dom, ret;
261
262 ret = of_property_read_u32(np, "reg", &dom);
263 if (ret)
264 return ret;
265
266 if (dom >= rinfo->num_doms)
267 return -ENODEV;
268
269 if (rinfo->sregv[dom]) {
270 dev_err(&sdev->dev,
271 "SCMI Voltage Domain %d already in use. Skipping: %s\n",
272 dom, np->full_name);
273 return -EINVAL;
274 }
275
276 rinfo->sregv[dom] = devm_kzalloc(&sdev->dev,
277 sizeof(struct scmi_regulator),
278 GFP_KERNEL);
279 if (!rinfo->sregv[dom])
280 return -ENOMEM;
281
282 rinfo->sregv[dom]->id = dom;
283 rinfo->sregv[dom]->sdev = sdev;
59046d15 284 rinfo->sregv[dom]->ph = ph;
0fbeae70
CM
285
286 /* get hold of good nodes */
287 of_node_get(np);
288 rinfo->sregv[dom]->of_node = np;
289
290 dev_dbg(&sdev->dev,
291 "Found SCMI Regulator entry -- OF node [%d] -> %s\n",
292 dom, np->full_name);
293
294 return 0;
295}
296
297static int scmi_regulator_probe(struct scmi_device *sdev)
298{
299 int d, ret, num_doms;
300 struct device_node *np, *child;
301 const struct scmi_handle *handle = sdev->handle;
302 struct scmi_regulator_info *rinfo;
59046d15 303 struct scmi_protocol_handle *ph;
0fbeae70 304
59046d15 305 if (!handle)
0fbeae70
CM
306 return -ENODEV;
307
59046d15
CM
308 voltage_ops = handle->devm_protocol_get(sdev,
309 SCMI_PROTOCOL_VOLTAGE, &ph);
310 if (IS_ERR(voltage_ops))
311 return PTR_ERR(voltage_ops);
312
313 num_doms = voltage_ops->num_domains_get(ph);
0fbeae70
CM
314 if (num_doms <= 0) {
315 if (!num_doms) {
316 dev_err(&sdev->dev,
317 "number of voltage domains invalid\n");
318 num_doms = -EINVAL;
319 } else {
320 dev_err(&sdev->dev,
321 "failed to get voltage domains - err:%d\n",
322 num_doms);
323 }
324
325 return num_doms;
326 }
327
328 rinfo = devm_kzalloc(&sdev->dev, sizeof(*rinfo), GFP_KERNEL);
329 if (!rinfo)
330 return -ENOMEM;
331
332 /* Allocate pointers array for all possible domains */
333 rinfo->sregv = devm_kcalloc(&sdev->dev, num_doms,
334 sizeof(void *), GFP_KERNEL);
335 if (!rinfo->sregv)
336 return -ENOMEM;
337
338 rinfo->num_doms = num_doms;
339
340 /*
341 * Start collecting into rinfo->sregv possibly good SCMI Regulators as
342 * described by a well-formed DT entry and associated with an existing
343 * plausible SCMI Voltage Domain number, all belonging to this SCMI
344 * platform instance node (handle->dev->of_node).
345 */
346 np = of_find_node_by_name(handle->dev->of_node, "regulators");
347 for_each_child_of_node(np, child) {
59046d15 348 ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
0fbeae70 349 /* abort on any mem issue */
45ee8b79
YL
350 if (ret == -ENOMEM) {
351 of_node_put(child);
0fbeae70 352 return ret;
45ee8b79 353 }
0fbeae70
CM
354 }
355
356 /*
357 * Register a regulator for each valid regulator-DT-entry that we
358 * can successfully reach via SCMI and has a valid associated voltage
359 * domain.
360 */
361 for (d = 0; d < num_doms; d++) {
362 struct scmi_regulator *sreg = rinfo->sregv[d];
363
364 /* Skip empty slots */
365 if (!sreg)
366 continue;
367
368 ret = scmi_regulator_common_init(sreg);
369 /* Skip invalid voltage domains */
370 if (ret)
371 continue;
372
373 sreg->rdev = devm_regulator_register(&sdev->dev, &sreg->desc,
374 &sreg->conf);
375 if (IS_ERR(sreg->rdev)) {
376 sreg->rdev = NULL;
377 continue;
378 }
379
380 dev_info(&sdev->dev,
381 "Regulator %s registered for domain [%d]\n",
382 sreg->desc.name, sreg->id);
383 }
384
385 dev_set_drvdata(&sdev->dev, rinfo);
386
387 return 0;
388}
389
390static void scmi_regulator_remove(struct scmi_device *sdev)
391{
392 int d;
393 struct scmi_regulator_info *rinfo;
394
395 rinfo = dev_get_drvdata(&sdev->dev);
396 if (!rinfo)
397 return;
398
399 for (d = 0; d < rinfo->num_doms; d++) {
400 if (!rinfo->sregv[d])
401 continue;
402 of_node_put(rinfo->sregv[d]->of_node);
403 }
404}
405
406static const struct scmi_device_id scmi_regulator_id_table[] = {
407 { SCMI_PROTOCOL_VOLTAGE, "regulator" },
408 { },
409};
410MODULE_DEVICE_TABLE(scmi, scmi_regulator_id_table);
411
412static struct scmi_driver scmi_drv = {
413 .name = "scmi-regulator",
414 .probe = scmi_regulator_probe,
415 .remove = scmi_regulator_remove,
416 .id_table = scmi_regulator_id_table,
417};
418
419module_scmi_driver(scmi_drv);
420
421MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
422MODULE_DESCRIPTION("ARM SCMI regulator driver");
423MODULE_LICENSE("GPL v2");