1 // SPDX-License-Identifier: GPL-2.0
3 // System Control and Management Interface (SCMI) based regulator driver
5 // Copyright (C) 2020 ARM Ltd.
7 // Implements a regulator driver on top of the SCMI Voltage Protocol.
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.
15 // The supported SCMI regulator ops are restricted to the bare minimum:
17 // - 'status_ops': enable/disable/is_enabled
18 // - 'voltage_ops': get_voltage_sel/set_voltage_sel
19 // list_voltage/map_voltage
21 // Each SCMI regulator instance is associated, through the means of a proper DT
22 // entry description, to a specific SCMI Voltage Domain.
24 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26 #include <linux/linear_range.h>
27 #include <linux/module.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>
36 struct scmi_regulator
{
38 struct scmi_device
*sdev
;
39 struct regulator_dev
*rdev
;
40 struct device_node
*of_node
;
41 struct regulator_desc desc
;
42 struct regulator_config conf
;
45 struct scmi_regulator_info
{
47 struct scmi_regulator
**sregv
;
50 static int scmi_reg_enable(struct regulator_dev
*rdev
)
52 struct scmi_regulator
*sreg
= rdev_get_drvdata(rdev
);
53 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
55 return handle
->voltage_ops
->config_set(handle
, sreg
->id
,
56 SCMI_VOLTAGE_ARCH_STATE_ON
);
59 static int scmi_reg_disable(struct regulator_dev
*rdev
)
61 struct scmi_regulator
*sreg
= rdev_get_drvdata(rdev
);
62 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
64 return handle
->voltage_ops
->config_set(handle
, sreg
->id
,
65 SCMI_VOLTAGE_ARCH_STATE_OFF
);
68 static int scmi_reg_is_enabled(struct regulator_dev
*rdev
)
72 struct scmi_regulator
*sreg
= rdev_get_drvdata(rdev
);
73 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
75 ret
= handle
->voltage_ops
->config_get(handle
, sreg
->id
,
78 dev_err(&sreg
->sdev
->dev
,
79 "Error %d reading regulator %s status.\n",
80 ret
, sreg
->desc
.name
);
84 return config
& SCMI_VOLTAGE_ARCH_STATE_ON
;
87 static int scmi_reg_get_voltage_sel(struct regulator_dev
*rdev
)
91 struct scmi_regulator
*sreg
= rdev_get_drvdata(rdev
);
92 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
94 ret
= handle
->voltage_ops
->level_get(handle
, sreg
->id
, &volt_uV
);
98 return sreg
->desc
.ops
->map_voltage(rdev
, volt_uV
, volt_uV
);
101 static int scmi_reg_set_voltage_sel(struct regulator_dev
*rdev
,
102 unsigned int selector
)
105 struct scmi_regulator
*sreg
= rdev_get_drvdata(rdev
);
106 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
108 volt_uV
= sreg
->desc
.ops
->list_voltage(rdev
, selector
);
112 return handle
->voltage_ops
->level_set(handle
, sreg
->id
, 0x0, volt_uV
);
115 static const struct regulator_ops scmi_reg_fixed_ops
= {
116 .enable
= scmi_reg_enable
,
117 .disable
= scmi_reg_disable
,
118 .is_enabled
= scmi_reg_is_enabled
,
121 static const struct regulator_ops scmi_reg_linear_ops
= {
122 .enable
= scmi_reg_enable
,
123 .disable
= scmi_reg_disable
,
124 .is_enabled
= scmi_reg_is_enabled
,
125 .get_voltage_sel
= scmi_reg_get_voltage_sel
,
126 .set_voltage_sel
= scmi_reg_set_voltage_sel
,
127 .list_voltage
= regulator_list_voltage_linear
,
128 .map_voltage
= regulator_map_voltage_linear
,
131 static const struct regulator_ops scmi_reg_discrete_ops
= {
132 .enable
= scmi_reg_enable
,
133 .disable
= scmi_reg_disable
,
134 .is_enabled
= scmi_reg_is_enabled
,
135 .get_voltage_sel
= scmi_reg_get_voltage_sel
,
136 .set_voltage_sel
= scmi_reg_set_voltage_sel
,
137 .list_voltage
= regulator_list_voltage_table
,
138 .map_voltage
= regulator_map_voltage_iterate
,
142 scmi_config_linear_regulator_mappings(struct scmi_regulator
*sreg
,
143 const struct scmi_voltage_info
*vinfo
)
148 * Note that SCMI voltage domains describable by linear ranges
149 * (segments) {low, high, step} are guaranteed to come in one single
150 * triplet by the SCMI Voltage Domain protocol support itself.
153 delta_uV
= (vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_HIGH
] -
154 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_LOW
]);
156 /* Rule out buggy negative-intervals answers from fw */
158 dev_err(&sreg
->sdev
->dev
,
159 "Invalid volt-range %d-%duV for domain %d\n",
160 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_LOW
],
161 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_HIGH
],
167 /* Just one fixed voltage exposed by SCMI */
168 sreg
->desc
.fixed_uV
=
169 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_LOW
];
170 sreg
->desc
.n_voltages
= 1;
171 sreg
->desc
.ops
= &scmi_reg_fixed_ops
;
173 /* One simple linear mapping. */
175 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_LOW
];
177 vinfo
->levels_uv
[SCMI_VOLTAGE_SEGMENT_STEP
];
178 sreg
->desc
.linear_min_sel
= 0;
179 sreg
->desc
.n_voltages
= delta_uV
/ sreg
->desc
.uV_step
;
180 sreg
->desc
.ops
= &scmi_reg_linear_ops
;
187 scmi_config_discrete_regulator_mappings(struct scmi_regulator
*sreg
,
188 const struct scmi_voltage_info
*vinfo
)
190 /* Discrete non linear levels are mapped to volt_table */
191 sreg
->desc
.n_voltages
= vinfo
->num_levels
;
193 if (sreg
->desc
.n_voltages
> 1) {
194 sreg
->desc
.volt_table
= (const unsigned int *)vinfo
->levels_uv
;
195 sreg
->desc
.ops
= &scmi_reg_discrete_ops
;
197 sreg
->desc
.fixed_uV
= vinfo
->levels_uv
[0];
198 sreg
->desc
.ops
= &scmi_reg_fixed_ops
;
204 static int scmi_regulator_common_init(struct scmi_regulator
*sreg
)
207 const struct scmi_handle
*handle
= sreg
->sdev
->handle
;
208 struct device
*dev
= &sreg
->sdev
->dev
;
209 const struct scmi_voltage_info
*vinfo
;
211 vinfo
= handle
->voltage_ops
->info_get(handle
, sreg
->id
);
213 dev_warn(dev
, "Failure to get voltage domain %d\n",
219 * Regulator framework does not fully support negative voltages
220 * so we discard any voltage domain reported as supporting negative
221 * voltages: as a consequence each levels_uv entry is guaranteed to
222 * be non-negative from here on.
224 if (vinfo
->negative_volts_allowed
) {
225 dev_warn(dev
, "Negative voltages NOT supported...skip %s\n",
226 sreg
->of_node
->full_name
);
230 sreg
->desc
.name
= devm_kasprintf(dev
, GFP_KERNEL
, "%s", vinfo
->name
);
231 if (!sreg
->desc
.name
)
234 sreg
->desc
.id
= sreg
->id
;
235 sreg
->desc
.type
= REGULATOR_VOLTAGE
;
236 sreg
->desc
.owner
= THIS_MODULE
;
237 sreg
->desc
.of_match_full_name
= true;
238 sreg
->desc
.of_match
= sreg
->of_node
->full_name
;
239 sreg
->desc
.regulators_node
= "regulators";
240 if (vinfo
->segmented
)
241 ret
= scmi_config_linear_regulator_mappings(sreg
, vinfo
);
243 ret
= scmi_config_discrete_regulator_mappings(sreg
, vinfo
);
248 * Using the scmi device here to have DT searched from Voltage
249 * protocol node down.
251 sreg
->conf
.dev
= dev
;
253 /* Store for later retrieval via rdev_get_drvdata() */
254 sreg
->conf
.driver_data
= sreg
;
259 static int process_scmi_regulator_of_node(struct scmi_device
*sdev
,
260 struct device_node
*np
,
261 struct scmi_regulator_info
*rinfo
)
265 ret
= of_property_read_u32(np
, "reg", &dom
);
269 if (dom
>= rinfo
->num_doms
)
272 if (rinfo
->sregv
[dom
]) {
274 "SCMI Voltage Domain %d already in use. Skipping: %s\n",
279 rinfo
->sregv
[dom
] = devm_kzalloc(&sdev
->dev
,
280 sizeof(struct scmi_regulator
),
282 if (!rinfo
->sregv
[dom
])
285 rinfo
->sregv
[dom
]->id
= dom
;
286 rinfo
->sregv
[dom
]->sdev
= sdev
;
288 /* get hold of good nodes */
290 rinfo
->sregv
[dom
]->of_node
= np
;
293 "Found SCMI Regulator entry -- OF node [%d] -> %s\n",
299 static int scmi_regulator_probe(struct scmi_device
*sdev
)
301 int d
, ret
, num_doms
;
302 struct device_node
*np
, *child
;
303 const struct scmi_handle
*handle
= sdev
->handle
;
304 struct scmi_regulator_info
*rinfo
;
306 if (!handle
|| !handle
->voltage_ops
)
309 num_doms
= handle
->voltage_ops
->num_domains_get(handle
);
313 "number of voltage domains invalid\n");
317 "failed to get voltage domains - err:%d\n",
324 rinfo
= devm_kzalloc(&sdev
->dev
, sizeof(*rinfo
), GFP_KERNEL
);
328 /* Allocate pointers array for all possible domains */
329 rinfo
->sregv
= devm_kcalloc(&sdev
->dev
, num_doms
,
330 sizeof(void *), GFP_KERNEL
);
334 rinfo
->num_doms
= num_doms
;
337 * Start collecting into rinfo->sregv possibly good SCMI Regulators as
338 * described by a well-formed DT entry and associated with an existing
339 * plausible SCMI Voltage Domain number, all belonging to this SCMI
340 * platform instance node (handle->dev->of_node).
342 np
= of_find_node_by_name(handle
->dev
->of_node
, "regulators");
343 for_each_child_of_node(np
, child
) {
344 ret
= process_scmi_regulator_of_node(sdev
, child
, rinfo
);
345 /* abort on any mem issue */
351 * Register a regulator for each valid regulator-DT-entry that we
352 * can successfully reach via SCMI and has a valid associated voltage
355 for (d
= 0; d
< num_doms
; d
++) {
356 struct scmi_regulator
*sreg
= rinfo
->sregv
[d
];
358 /* Skip empty slots */
362 ret
= scmi_regulator_common_init(sreg
);
363 /* Skip invalid voltage domains */
367 sreg
->rdev
= devm_regulator_register(&sdev
->dev
, &sreg
->desc
,
369 if (IS_ERR(sreg
->rdev
)) {
375 "Regulator %s registered for domain [%d]\n",
376 sreg
->desc
.name
, sreg
->id
);
379 dev_set_drvdata(&sdev
->dev
, rinfo
);
384 static void scmi_regulator_remove(struct scmi_device
*sdev
)
387 struct scmi_regulator_info
*rinfo
;
389 rinfo
= dev_get_drvdata(&sdev
->dev
);
393 for (d
= 0; d
< rinfo
->num_doms
; d
++) {
394 if (!rinfo
->sregv
[d
])
396 of_node_put(rinfo
->sregv
[d
]->of_node
);
400 static const struct scmi_device_id scmi_regulator_id_table
[] = {
401 { SCMI_PROTOCOL_VOLTAGE
, "regulator" },
404 MODULE_DEVICE_TABLE(scmi
, scmi_regulator_id_table
);
406 static struct scmi_driver scmi_drv
= {
407 .name
= "scmi-regulator",
408 .probe
= scmi_regulator_probe
,
409 .remove
= scmi_regulator_remove
,
410 .id_table
= scmi_regulator_id_table
,
413 module_scmi_driver(scmi_drv
);
415 MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
416 MODULE_DESCRIPTION("ARM SCMI regulator driver");
417 MODULE_LICENSE("GPL v2");