10fbeae70SCristian Marussi // SPDX-License-Identifier: GPL-2.0
20fbeae70SCristian Marussi //
30fbeae70SCristian Marussi // System Control and Management Interface (SCMI) based regulator driver
40fbeae70SCristian Marussi //
559046d15SCristian Marussi // Copyright (C) 2020-2021 ARM Ltd.
60fbeae70SCristian Marussi //
70fbeae70SCristian Marussi // Implements a regulator driver on top of the SCMI Voltage Protocol.
80fbeae70SCristian Marussi //
90fbeae70SCristian Marussi // The ARM SCMI Protocol aims in general to hide as much as possible all the
100fbeae70SCristian Marussi // underlying operational details while providing an abstracted interface for
110fbeae70SCristian Marussi // its users to operate upon: as a consequence the resulting operational
120fbeae70SCristian Marussi // capabilities and configurability of this regulator device are much more
130fbeae70SCristian Marussi // limited than the ones usually available on a standard physical regulator.
140fbeae70SCristian Marussi //
150fbeae70SCristian Marussi // The supported SCMI regulator ops are restricted to the bare minimum:
160fbeae70SCristian Marussi //
170fbeae70SCristian Marussi //  - 'status_ops': enable/disable/is_enabled
180fbeae70SCristian Marussi //  - 'voltage_ops': get_voltage_sel/set_voltage_sel
190fbeae70SCristian Marussi //		     list_voltage/map_voltage
200fbeae70SCristian Marussi //
210fbeae70SCristian Marussi // Each SCMI regulator instance is associated, through the means of a proper DT
220fbeae70SCristian Marussi // entry description, to a specific SCMI Voltage Domain.
230fbeae70SCristian Marussi 
240fbeae70SCristian Marussi #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
250fbeae70SCristian Marussi 
260fbeae70SCristian Marussi #include <linux/linear_range.h>
270fbeae70SCristian Marussi #include <linux/module.h>
280fbeae70SCristian Marussi #include <linux/of.h>
290fbeae70SCristian Marussi #include <linux/regulator/driver.h>
300fbeae70SCristian Marussi #include <linux/regulator/machine.h>
310fbeae70SCristian Marussi #include <linux/regulator/of_regulator.h>
320fbeae70SCristian Marussi #include <linux/scmi_protocol.h>
330fbeae70SCristian Marussi #include <linux/slab.h>
340fbeae70SCristian Marussi #include <linux/types.h>
350fbeae70SCristian Marussi 
3659046d15SCristian Marussi static const struct scmi_voltage_proto_ops *voltage_ops;
3759046d15SCristian Marussi 
380fbeae70SCristian Marussi struct scmi_regulator {
390fbeae70SCristian Marussi 	u32 id;
400fbeae70SCristian Marussi 	struct scmi_device *sdev;
4159046d15SCristian Marussi 	struct scmi_protocol_handle *ph;
420fbeae70SCristian Marussi 	struct regulator_dev *rdev;
430fbeae70SCristian Marussi 	struct device_node *of_node;
440fbeae70SCristian Marussi 	struct regulator_desc desc;
450fbeae70SCristian Marussi 	struct regulator_config conf;
460fbeae70SCristian Marussi };
470fbeae70SCristian Marussi 
480fbeae70SCristian Marussi struct scmi_regulator_info {
490fbeae70SCristian Marussi 	int num_doms;
500fbeae70SCristian Marussi 	struct scmi_regulator **sregv;
510fbeae70SCristian Marussi };
520fbeae70SCristian Marussi 
scmi_reg_enable(struct regulator_dev * rdev)530fbeae70SCristian Marussi static int scmi_reg_enable(struct regulator_dev *rdev)
540fbeae70SCristian Marussi {
550fbeae70SCristian Marussi 	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
560fbeae70SCristian Marussi 
5759046d15SCristian Marussi 	return voltage_ops->config_set(sreg->ph, sreg->id,
580fbeae70SCristian Marussi 				       SCMI_VOLTAGE_ARCH_STATE_ON);
590fbeae70SCristian Marussi }
600fbeae70SCristian Marussi 
scmi_reg_disable(struct regulator_dev * rdev)610fbeae70SCristian Marussi static int scmi_reg_disable(struct regulator_dev *rdev)
620fbeae70SCristian Marussi {
630fbeae70SCristian Marussi 	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
640fbeae70SCristian Marussi 
6559046d15SCristian Marussi 	return voltage_ops->config_set(sreg->ph, sreg->id,
660fbeae70SCristian Marussi 				       SCMI_VOLTAGE_ARCH_STATE_OFF);
670fbeae70SCristian Marussi }
680fbeae70SCristian Marussi 
scmi_reg_is_enabled(struct regulator_dev * rdev)690fbeae70SCristian Marussi static int scmi_reg_is_enabled(struct regulator_dev *rdev)
700fbeae70SCristian Marussi {
710fbeae70SCristian Marussi 	int ret;
720fbeae70SCristian Marussi 	u32 config;
730fbeae70SCristian Marussi 	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
740fbeae70SCristian Marussi 
7559046d15SCristian Marussi 	ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);
760fbeae70SCristian Marussi 	if (ret) {
770fbeae70SCristian Marussi 		dev_err(&sreg->sdev->dev,
780fbeae70SCristian Marussi 			"Error %d reading regulator %s status.\n",
790fbeae70SCristian Marussi 			ret, sreg->desc.name);
800fbeae70SCristian Marussi 		return ret;
810fbeae70SCristian Marussi 	}
820fbeae70SCristian Marussi 
830fbeae70SCristian Marussi 	return config & SCMI_VOLTAGE_ARCH_STATE_ON;
840fbeae70SCristian Marussi }
850fbeae70SCristian Marussi 
scmi_reg_get_voltage_sel(struct regulator_dev * rdev)860fbeae70SCristian Marussi static int scmi_reg_get_voltage_sel(struct regulator_dev *rdev)
870fbeae70SCristian Marussi {
880fbeae70SCristian Marussi 	int ret;
890fbeae70SCristian Marussi 	s32 volt_uV;
900fbeae70SCristian Marussi 	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
910fbeae70SCristian Marussi 
9259046d15SCristian Marussi 	ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);
930fbeae70SCristian Marussi 	if (ret)
940fbeae70SCristian Marussi 		return ret;
950fbeae70SCristian Marussi 
960fbeae70SCristian Marussi 	return sreg->desc.ops->map_voltage(rdev, volt_uV, volt_uV);
970fbeae70SCristian Marussi }
980fbeae70SCristian Marussi 
scmi_reg_set_voltage_sel(struct regulator_dev * rdev,unsigned int selector)990fbeae70SCristian Marussi static int scmi_reg_set_voltage_sel(struct regulator_dev *rdev,
1000fbeae70SCristian Marussi 				    unsigned int selector)
1010fbeae70SCristian Marussi {
1020fbeae70SCristian Marussi 	s32 volt_uV;
1030fbeae70SCristian Marussi 	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);
1040fbeae70SCristian Marussi 
1050fbeae70SCristian Marussi 	volt_uV = sreg->desc.ops->list_voltage(rdev, selector);
1060fbeae70SCristian Marussi 	if (volt_uV <= 0)
1070fbeae70SCristian Marussi 		return -EINVAL;
1080fbeae70SCristian Marussi 
10959046d15SCristian Marussi 	return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);
1100fbeae70SCristian Marussi }
1110fbeae70SCristian Marussi 
1120fbeae70SCristian Marussi static const struct regulator_ops scmi_reg_fixed_ops = {
1130fbeae70SCristian Marussi 	.enable = scmi_reg_enable,
1140fbeae70SCristian Marussi 	.disable = scmi_reg_disable,
1150fbeae70SCristian Marussi 	.is_enabled = scmi_reg_is_enabled,
1160fbeae70SCristian Marussi };
1170fbeae70SCristian Marussi 
1180fbeae70SCristian Marussi static const struct regulator_ops scmi_reg_linear_ops = {
1190fbeae70SCristian Marussi 	.enable = scmi_reg_enable,
1200fbeae70SCristian Marussi 	.disable = scmi_reg_disable,
1210fbeae70SCristian Marussi 	.is_enabled = scmi_reg_is_enabled,
1220fbeae70SCristian Marussi 	.get_voltage_sel = scmi_reg_get_voltage_sel,
1230fbeae70SCristian Marussi 	.set_voltage_sel = scmi_reg_set_voltage_sel,
1240fbeae70SCristian Marussi 	.list_voltage = regulator_list_voltage_linear,
1250fbeae70SCristian Marussi 	.map_voltage = regulator_map_voltage_linear,
1260fbeae70SCristian Marussi };
1270fbeae70SCristian Marussi 
1280fbeae70SCristian Marussi static const struct regulator_ops scmi_reg_discrete_ops = {
1290fbeae70SCristian Marussi 	.enable = scmi_reg_enable,
1300fbeae70SCristian Marussi 	.disable = scmi_reg_disable,
1310fbeae70SCristian Marussi 	.is_enabled = scmi_reg_is_enabled,
1320fbeae70SCristian Marussi 	.get_voltage_sel = scmi_reg_get_voltage_sel,
1330fbeae70SCristian Marussi 	.set_voltage_sel = scmi_reg_set_voltage_sel,
1340fbeae70SCristian Marussi 	.list_voltage = regulator_list_voltage_table,
1350fbeae70SCristian Marussi 	.map_voltage = regulator_map_voltage_iterate,
1360fbeae70SCristian Marussi };
1370fbeae70SCristian Marussi 
1380fbeae70SCristian Marussi static int
scmi_config_linear_regulator_mappings(struct scmi_regulator * sreg,const struct scmi_voltage_info * vinfo)1390fbeae70SCristian Marussi scmi_config_linear_regulator_mappings(struct scmi_regulator *sreg,
1400fbeae70SCristian Marussi 				      const struct scmi_voltage_info *vinfo)
1410fbeae70SCristian Marussi {
1420fbeae70SCristian Marussi 	s32 delta_uV;
1430fbeae70SCristian Marussi 
1440fbeae70SCristian Marussi 	/*
1450fbeae70SCristian Marussi 	 * Note that SCMI voltage domains describable by linear ranges
1460fbeae70SCristian Marussi 	 * (segments) {low, high, step} are guaranteed to come in one single
1470fbeae70SCristian Marussi 	 * triplet by the SCMI Voltage Domain protocol support itself.
1480fbeae70SCristian Marussi 	 */
1490fbeae70SCristian Marussi 
1500fbeae70SCristian Marussi 	delta_uV = (vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH] -
1510fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW]);
1520fbeae70SCristian Marussi 
1530fbeae70SCristian Marussi 	/* Rule out buggy negative-intervals answers from fw */
1540fbeae70SCristian Marussi 	if (delta_uV < 0) {
1550fbeae70SCristian Marussi 		dev_err(&sreg->sdev->dev,
1560fbeae70SCristian Marussi 			"Invalid volt-range %d-%duV for domain %d\n",
1570fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW],
1580fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_HIGH],
1590fbeae70SCristian Marussi 			sreg->id);
1600fbeae70SCristian Marussi 		return -EINVAL;
1610fbeae70SCristian Marussi 	}
1620fbeae70SCristian Marussi 
1630fbeae70SCristian Marussi 	if (!delta_uV) {
1640fbeae70SCristian Marussi 		/* Just one fixed voltage exposed by SCMI */
1650fbeae70SCristian Marussi 		sreg->desc.fixed_uV =
1660fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
1670fbeae70SCristian Marussi 		sreg->desc.n_voltages = 1;
1680fbeae70SCristian Marussi 		sreg->desc.ops = &scmi_reg_fixed_ops;
1690fbeae70SCristian Marussi 	} else {
1700fbeae70SCristian Marussi 		/* One simple linear mapping. */
1710fbeae70SCristian Marussi 		sreg->desc.min_uV =
1720fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_LOW];
1730fbeae70SCristian Marussi 		sreg->desc.uV_step =
1740fbeae70SCristian Marussi 			vinfo->levels_uv[SCMI_VOLTAGE_SEGMENT_STEP];
1750fbeae70SCristian Marussi 		sreg->desc.linear_min_sel = 0;
17636cb555fSAxel Lin 		sreg->desc.n_voltages = (delta_uV / sreg->desc.uV_step) + 1;
1770fbeae70SCristian Marussi 		sreg->desc.ops = &scmi_reg_linear_ops;
1780fbeae70SCristian Marussi 	}
1790fbeae70SCristian Marussi 
1800fbeae70SCristian Marussi 	return 0;
1810fbeae70SCristian Marussi }
1820fbeae70SCristian Marussi 
1830fbeae70SCristian Marussi static int
scmi_config_discrete_regulator_mappings(struct scmi_regulator * sreg,const struct scmi_voltage_info * vinfo)1840fbeae70SCristian Marussi scmi_config_discrete_regulator_mappings(struct scmi_regulator *sreg,
1850fbeae70SCristian Marussi 					const struct scmi_voltage_info *vinfo)
1860fbeae70SCristian Marussi {
1870fbeae70SCristian Marussi 	/* Discrete non linear levels are mapped to volt_table */
1880fbeae70SCristian Marussi 	sreg->desc.n_voltages = vinfo->num_levels;
1890fbeae70SCristian Marussi 
1900fbeae70SCristian Marussi 	if (sreg->desc.n_voltages > 1) {
1910fbeae70SCristian Marussi 		sreg->desc.volt_table = (const unsigned int *)vinfo->levels_uv;
1920fbeae70SCristian Marussi 		sreg->desc.ops = &scmi_reg_discrete_ops;
1930fbeae70SCristian Marussi 	} else {
1940fbeae70SCristian Marussi 		sreg->desc.fixed_uV = vinfo->levels_uv[0];
1950fbeae70SCristian Marussi 		sreg->desc.ops = &scmi_reg_fixed_ops;
1960fbeae70SCristian Marussi 	}
1970fbeae70SCristian Marussi 
1980fbeae70SCristian Marussi 	return 0;
1990fbeae70SCristian Marussi }
2000fbeae70SCristian Marussi 
scmi_regulator_common_init(struct scmi_regulator * sreg)2010fbeae70SCristian Marussi static int scmi_regulator_common_init(struct scmi_regulator *sreg)
2020fbeae70SCristian Marussi {
2030fbeae70SCristian Marussi 	int ret;
2040fbeae70SCristian Marussi 	struct device *dev = &sreg->sdev->dev;
2050fbeae70SCristian Marussi 	const struct scmi_voltage_info *vinfo;
2060fbeae70SCristian Marussi 
20759046d15SCristian Marussi 	vinfo = voltage_ops->info_get(sreg->ph, sreg->id);
2080fbeae70SCristian Marussi 	if (!vinfo) {
2090fbeae70SCristian Marussi 		dev_warn(dev, "Failure to get voltage domain %d\n",
2100fbeae70SCristian Marussi 			 sreg->id);
2110fbeae70SCristian Marussi 		return -ENODEV;
2120fbeae70SCristian Marussi 	}
2130fbeae70SCristian Marussi 
2140fbeae70SCristian Marussi 	/*
2150fbeae70SCristian Marussi 	 * Regulator framework does not fully support negative voltages
2160fbeae70SCristian Marussi 	 * so we discard any voltage domain reported as supporting negative
2170fbeae70SCristian Marussi 	 * voltages: as a consequence each levels_uv entry is guaranteed to
2180fbeae70SCristian Marussi 	 * be non-negative from here on.
2190fbeae70SCristian Marussi 	 */
2200fbeae70SCristian Marussi 	if (vinfo->negative_volts_allowed) {
2210fbeae70SCristian Marussi 		dev_warn(dev, "Negative voltages NOT supported...skip %s\n",
2220fbeae70SCristian Marussi 			 sreg->of_node->full_name);
2230fbeae70SCristian Marussi 		return -EOPNOTSUPP;
2240fbeae70SCristian Marussi 	}
2250fbeae70SCristian Marussi 
2260fbeae70SCristian Marussi 	sreg->desc.name = devm_kasprintf(dev, GFP_KERNEL, "%s", vinfo->name);
2270fbeae70SCristian Marussi 	if (!sreg->desc.name)
2280fbeae70SCristian Marussi 		return -ENOMEM;
2290fbeae70SCristian Marussi 
2300fbeae70SCristian Marussi 	sreg->desc.id = sreg->id;
2310fbeae70SCristian Marussi 	sreg->desc.type = REGULATOR_VOLTAGE;
2320fbeae70SCristian Marussi 	sreg->desc.owner = THIS_MODULE;
2330fbeae70SCristian Marussi 	sreg->desc.of_match_full_name = true;
2340fbeae70SCristian Marussi 	sreg->desc.of_match = sreg->of_node->full_name;
2350fbeae70SCristian Marussi 	sreg->desc.regulators_node = "regulators";
2360fbeae70SCristian Marussi 	if (vinfo->segmented)
2370fbeae70SCristian Marussi 		ret = scmi_config_linear_regulator_mappings(sreg, vinfo);
2380fbeae70SCristian Marussi 	else
2390fbeae70SCristian Marussi 		ret = scmi_config_discrete_regulator_mappings(sreg, vinfo);
2400fbeae70SCristian Marussi 	if (ret)
2410fbeae70SCristian Marussi 		return ret;
2420fbeae70SCristian Marussi 
2430fbeae70SCristian Marussi 	/*
2440fbeae70SCristian Marussi 	 * Using the scmi device here to have DT searched from Voltage
2450fbeae70SCristian Marussi 	 * protocol node down.
2460fbeae70SCristian Marussi 	 */
2470fbeae70SCristian Marussi 	sreg->conf.dev = dev;
2480fbeae70SCristian Marussi 
2490fbeae70SCristian Marussi 	/* Store for later retrieval via rdev_get_drvdata() */
2500fbeae70SCristian Marussi 	sreg->conf.driver_data = sreg;
2510fbeae70SCristian Marussi 
2520fbeae70SCristian Marussi 	return 0;
2530fbeae70SCristian Marussi }
2540fbeae70SCristian Marussi 
process_scmi_regulator_of_node(struct scmi_device * sdev,struct scmi_protocol_handle * ph,struct device_node * np,struct scmi_regulator_info * rinfo)2550fbeae70SCristian Marussi static int process_scmi_regulator_of_node(struct scmi_device *sdev,
25659046d15SCristian Marussi 					  struct scmi_protocol_handle *ph,
2570fbeae70SCristian Marussi 					  struct device_node *np,
2580fbeae70SCristian Marussi 					  struct scmi_regulator_info *rinfo)
2590fbeae70SCristian Marussi {
2600fbeae70SCristian Marussi 	u32 dom, ret;
2610fbeae70SCristian Marussi 
2620fbeae70SCristian Marussi 	ret = of_property_read_u32(np, "reg", &dom);
2630fbeae70SCristian Marussi 	if (ret)
2640fbeae70SCristian Marussi 		return ret;
2650fbeae70SCristian Marussi 
2660fbeae70SCristian Marussi 	if (dom >= rinfo->num_doms)
2670fbeae70SCristian Marussi 		return -ENODEV;
2680fbeae70SCristian Marussi 
2690fbeae70SCristian Marussi 	if (rinfo->sregv[dom]) {
2700fbeae70SCristian Marussi 		dev_err(&sdev->dev,
2710fbeae70SCristian Marussi 			"SCMI Voltage Domain %d already in use. Skipping: %s\n",
2720fbeae70SCristian Marussi 			dom, np->full_name);
2730fbeae70SCristian Marussi 		return -EINVAL;
2740fbeae70SCristian Marussi 	}
2750fbeae70SCristian Marussi 
2760fbeae70SCristian Marussi 	rinfo->sregv[dom] = devm_kzalloc(&sdev->dev,
2770fbeae70SCristian Marussi 					 sizeof(struct scmi_regulator),
2780fbeae70SCristian Marussi 					 GFP_KERNEL);
2790fbeae70SCristian Marussi 	if (!rinfo->sregv[dom])
2800fbeae70SCristian Marussi 		return -ENOMEM;
2810fbeae70SCristian Marussi 
2820fbeae70SCristian Marussi 	rinfo->sregv[dom]->id = dom;
2830fbeae70SCristian Marussi 	rinfo->sregv[dom]->sdev = sdev;
28459046d15SCristian Marussi 	rinfo->sregv[dom]->ph = ph;
2850fbeae70SCristian Marussi 
2860fbeae70SCristian Marussi 	/* get hold of good nodes */
2870fbeae70SCristian Marussi 	of_node_get(np);
2880fbeae70SCristian Marussi 	rinfo->sregv[dom]->of_node = np;
2890fbeae70SCristian Marussi 
2900fbeae70SCristian Marussi 	dev_dbg(&sdev->dev,
2910fbeae70SCristian Marussi 		"Found SCMI Regulator entry -- OF node [%d] -> %s\n",
2920fbeae70SCristian Marussi 		dom, np->full_name);
2930fbeae70SCristian Marussi 
2940fbeae70SCristian Marussi 	return 0;
2950fbeae70SCristian Marussi }
2960fbeae70SCristian Marussi 
scmi_regulator_probe(struct scmi_device * sdev)2970fbeae70SCristian Marussi static int scmi_regulator_probe(struct scmi_device *sdev)
2980fbeae70SCristian Marussi {
2990fbeae70SCristian Marussi 	int d, ret, num_doms;
3000fbeae70SCristian Marussi 	struct device_node *np, *child;
3010fbeae70SCristian Marussi 	const struct scmi_handle *handle = sdev->handle;
3020fbeae70SCristian Marussi 	struct scmi_regulator_info *rinfo;
30359046d15SCristian Marussi 	struct scmi_protocol_handle *ph;
3040fbeae70SCristian Marussi 
30559046d15SCristian Marussi 	if (!handle)
3060fbeae70SCristian Marussi 		return -ENODEV;
3070fbeae70SCristian Marussi 
30859046d15SCristian Marussi 	voltage_ops = handle->devm_protocol_get(sdev,
30959046d15SCristian Marussi 						SCMI_PROTOCOL_VOLTAGE, &ph);
31059046d15SCristian Marussi 	if (IS_ERR(voltage_ops))
31159046d15SCristian Marussi 		return PTR_ERR(voltage_ops);
31259046d15SCristian Marussi 
31359046d15SCristian Marussi 	num_doms = voltage_ops->num_domains_get(ph);
314*668f777dSCristian Marussi 	if (!num_doms)
315*668f777dSCristian Marussi 		return 0;
316*668f777dSCristian Marussi 
317*668f777dSCristian Marussi 	if (num_doms < 0) {
318*668f777dSCristian Marussi 		dev_err(&sdev->dev, "failed to get voltage domains - err:%d\n",
3190fbeae70SCristian Marussi 			num_doms);
3200fbeae70SCristian Marussi 
3210fbeae70SCristian Marussi 		return num_doms;
3220fbeae70SCristian Marussi 	}
3230fbeae70SCristian Marussi 
3240fbeae70SCristian Marussi 	rinfo = devm_kzalloc(&sdev->dev, sizeof(*rinfo), GFP_KERNEL);
3250fbeae70SCristian Marussi 	if (!rinfo)
3260fbeae70SCristian Marussi 		return -ENOMEM;
3270fbeae70SCristian Marussi 
3280fbeae70SCristian Marussi 	/* Allocate pointers array for all possible domains */
3290fbeae70SCristian Marussi 	rinfo->sregv = devm_kcalloc(&sdev->dev, num_doms,
3300fbeae70SCristian Marussi 				    sizeof(void *), GFP_KERNEL);
3310fbeae70SCristian Marussi 	if (!rinfo->sregv)
3320fbeae70SCristian Marussi 		return -ENOMEM;
3330fbeae70SCristian Marussi 
3340fbeae70SCristian Marussi 	rinfo->num_doms = num_doms;
3350fbeae70SCristian Marussi 
3360fbeae70SCristian Marussi 	/*
3370fbeae70SCristian Marussi 	 * Start collecting into rinfo->sregv possibly good SCMI Regulators as
3380fbeae70SCristian Marussi 	 * described by a well-formed DT entry and associated with an existing
3390fbeae70SCristian Marussi 	 * plausible SCMI Voltage Domain number, all belonging to this SCMI
3400fbeae70SCristian Marussi 	 * platform instance node (handle->dev->of_node).
3410fbeae70SCristian Marussi 	 */
342a9e37a82SLiang He 	of_node_get(handle->dev->of_node);
3430fbeae70SCristian Marussi 	np = of_find_node_by_name(handle->dev->of_node, "regulators");
3440fbeae70SCristian Marussi 	for_each_child_of_node(np, child) {
34559046d15SCristian Marussi 		ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);
3460fbeae70SCristian Marussi 		/* abort on any mem issue */
34745ee8b79SYang Li 		if (ret == -ENOMEM) {
34845ee8b79SYang Li 			of_node_put(child);
3490fbeae70SCristian Marussi 			return ret;
3500fbeae70SCristian Marussi 		}
35145ee8b79SYang Li 	}
35268d6c847SMiaoqian Lin 	of_node_put(np);
3530fbeae70SCristian Marussi 	/*
3540fbeae70SCristian Marussi 	 * Register a regulator for each valid regulator-DT-entry that we
3550fbeae70SCristian Marussi 	 * can successfully reach via SCMI and has a valid associated voltage
3560fbeae70SCristian Marussi 	 * domain.
3570fbeae70SCristian Marussi 	 */
3580fbeae70SCristian Marussi 	for (d = 0; d < num_doms; d++) {
3590fbeae70SCristian Marussi 		struct scmi_regulator *sreg = rinfo->sregv[d];
3600fbeae70SCristian Marussi 
3610fbeae70SCristian Marussi 		/* Skip empty slots */
3620fbeae70SCristian Marussi 		if (!sreg)
3630fbeae70SCristian Marussi 			continue;
3640fbeae70SCristian Marussi 
3650fbeae70SCristian Marussi 		ret = scmi_regulator_common_init(sreg);
3660fbeae70SCristian Marussi 		/* Skip invalid voltage domains */
3670fbeae70SCristian Marussi 		if (ret)
3680fbeae70SCristian Marussi 			continue;
3690fbeae70SCristian Marussi 
3700fbeae70SCristian Marussi 		sreg->rdev = devm_regulator_register(&sdev->dev, &sreg->desc,
3710fbeae70SCristian Marussi 						     &sreg->conf);
3720fbeae70SCristian Marussi 		if (IS_ERR(sreg->rdev)) {
3730fbeae70SCristian Marussi 			sreg->rdev = NULL;
3740fbeae70SCristian Marussi 			continue;
3750fbeae70SCristian Marussi 		}
3760fbeae70SCristian Marussi 
3770fbeae70SCristian Marussi 		dev_info(&sdev->dev,
3780fbeae70SCristian Marussi 			 "Regulator %s registered for domain [%d]\n",
3790fbeae70SCristian Marussi 			 sreg->desc.name, sreg->id);
3800fbeae70SCristian Marussi 	}
3810fbeae70SCristian Marussi 
3820fbeae70SCristian Marussi 	dev_set_drvdata(&sdev->dev, rinfo);
3830fbeae70SCristian Marussi 
3840fbeae70SCristian Marussi 	return 0;
3850fbeae70SCristian Marussi }
3860fbeae70SCristian Marussi 
scmi_regulator_remove(struct scmi_device * sdev)3870fbeae70SCristian Marussi static void scmi_regulator_remove(struct scmi_device *sdev)
3880fbeae70SCristian Marussi {
3890fbeae70SCristian Marussi 	int d;
3900fbeae70SCristian Marussi 	struct scmi_regulator_info *rinfo;
3910fbeae70SCristian Marussi 
3920fbeae70SCristian Marussi 	rinfo = dev_get_drvdata(&sdev->dev);
3930fbeae70SCristian Marussi 	if (!rinfo)
3940fbeae70SCristian Marussi 		return;
3950fbeae70SCristian Marussi 
3960fbeae70SCristian Marussi 	for (d = 0; d < rinfo->num_doms; d++) {
3970fbeae70SCristian Marussi 		if (!rinfo->sregv[d])
3980fbeae70SCristian Marussi 			continue;
3990fbeae70SCristian Marussi 		of_node_put(rinfo->sregv[d]->of_node);
4000fbeae70SCristian Marussi 	}
4010fbeae70SCristian Marussi }
4020fbeae70SCristian Marussi 
4030fbeae70SCristian Marussi static const struct scmi_device_id scmi_regulator_id_table[] = {
4040fbeae70SCristian Marussi 	{ SCMI_PROTOCOL_VOLTAGE,  "regulator" },
4050fbeae70SCristian Marussi 	{ },
4060fbeae70SCristian Marussi };
4070fbeae70SCristian Marussi MODULE_DEVICE_TABLE(scmi, scmi_regulator_id_table);
4080fbeae70SCristian Marussi 
4090fbeae70SCristian Marussi static struct scmi_driver scmi_drv = {
4100fbeae70SCristian Marussi 	.name		= "scmi-regulator",
4110fbeae70SCristian Marussi 	.probe		= scmi_regulator_probe,
4120fbeae70SCristian Marussi 	.remove		= scmi_regulator_remove,
4130fbeae70SCristian Marussi 	.id_table	= scmi_regulator_id_table,
4140fbeae70SCristian Marussi };
4150fbeae70SCristian Marussi 
4160fbeae70SCristian Marussi module_scmi_driver(scmi_drv);
4170fbeae70SCristian Marussi 
4180fbeae70SCristian Marussi MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");
4190fbeae70SCristian Marussi MODULE_DESCRIPTION("ARM SCMI regulator driver");
4200fbeae70SCristian Marussi MODULE_LICENSE("GPL v2");
421