brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 9df726f Raw
419 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// System Control and Management Interface (SCMI) based regulator driver4//5// Copyright (C) 2020-2021 ARM Ltd.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 the10// underlying operational details while providing an abstracted interface for11// its users to operate upon: as a consequence the resulting operational12// capabilities and configurability of this regulator device are much more13// 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_enabled18//  - 'voltage_ops': get_voltage_sel/set_voltage_sel19//		     list_voltage/map_voltage20//21// Each SCMI regulator instance is associated, through the means of a proper DT22// entry description, to a specific SCMI Voltage Domain.23 24#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt25 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 36static const struct scmi_voltage_proto_ops *voltage_ops;37 38struct scmi_regulator {39	u32 id;40	struct scmi_device *sdev;41	struct scmi_protocol_handle *ph;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);56 57	return voltage_ops->config_set(sreg->ph, sreg->id,58				       SCMI_VOLTAGE_ARCH_STATE_ON);59}60 61static int scmi_reg_disable(struct regulator_dev *rdev)62{63	struct scmi_regulator *sreg = rdev_get_drvdata(rdev);64 65	return voltage_ops->config_set(sreg->ph, sreg->id,66				       SCMI_VOLTAGE_ARCH_STATE_OFF);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);74 75	ret = voltage_ops->config_get(sreg->ph, sreg->id, &config);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);91 92	ret = voltage_ops->level_get(sreg->ph, sreg->id, &volt_uV);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);104 105	volt_uV = sreg->desc.ops->list_voltage(rdev, selector);106	if (volt_uV <= 0)107		return -EINVAL;108 109	return voltage_ops->level_set(sreg->ph, sreg->id, 0x0, volt_uV);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 int139scmi_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 ranges146	 * (segments) {low, high, step} are guaranteed to come in one single147	 * 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;176		sreg->desc.n_voltages = (delta_uV / sreg->desc.uV_step) + 1;177		sreg->desc.ops = &scmi_reg_linear_ops;178	}179 180	return 0;181}182 183static int184scmi_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;204	struct device *dev = &sreg->sdev->dev;205	const struct scmi_voltage_info *vinfo;206 207	vinfo = voltage_ops->info_get(sreg->ph, sreg->id);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 voltages216	 * so we discard any voltage domain reported as supporting negative217	 * voltages: as a consequence each levels_uv entry is guaranteed to218	 * 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	else239		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 Voltage245	 * 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,256					  struct scmi_protocol_handle *ph,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;284	rinfo->sregv[dom]->ph = ph;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;301	const struct scmi_handle *handle = sdev->handle;302	struct scmi_regulator_info *rinfo;303	struct scmi_protocol_handle *ph;304 305	if (!handle)306		return -ENODEV;307 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);314	if (!num_doms)315		return 0;316 317	if (num_doms < 0) {318		dev_err(&sdev->dev, "failed to get voltage domains - err:%d\n",319			num_doms);320 321		return num_doms;322	}323 324	rinfo = devm_kzalloc(&sdev->dev, sizeof(*rinfo), GFP_KERNEL);325	if (!rinfo)326		return -ENOMEM;327 328	/* Allocate pointers array for all possible domains */329	rinfo->sregv = devm_kcalloc(&sdev->dev, num_doms,330				    sizeof(void *), GFP_KERNEL);331	if (!rinfo->sregv)332		return -ENOMEM;333 334	rinfo->num_doms = num_doms;335 336	/*337	 * Start collecting into rinfo->sregv possibly good SCMI Regulators as338	 * described by a well-formed DT entry and associated with an existing339	 * plausible SCMI Voltage Domain number, all belonging to this SCMI340	 * platform instance node (handle->dev->of_node).341	 */342	of_node_get(handle->dev->of_node);343	np = of_find_node_by_name(handle->dev->of_node, "regulators");344	for_each_child_of_node_scoped(np, child) {345		ret = process_scmi_regulator_of_node(sdev, ph, child, rinfo);346		/* abort on any mem issue */347		if (ret == -ENOMEM)348			return ret;349	}350	of_node_put(np);351	/*352	 * Register a regulator for each valid regulator-DT-entry that we353	 * can successfully reach via SCMI and has a valid associated voltage354	 * domain.355	 */356	for (d = 0; d < num_doms; d++) {357		struct scmi_regulator *sreg = rinfo->sregv[d];358 359		/* Skip empty slots */360		if (!sreg)361			continue;362 363		ret = scmi_regulator_common_init(sreg);364		/* Skip invalid voltage domains */365		if (ret)366			continue;367 368		sreg->rdev = devm_regulator_register(&sdev->dev, &sreg->desc,369						     &sreg->conf);370		if (IS_ERR(sreg->rdev)) {371			sreg->rdev = NULL;372			continue;373		}374 375		dev_info(&sdev->dev,376			 "Regulator %s registered for domain [%d]\n",377			 sreg->desc.name, sreg->id);378	}379 380	dev_set_drvdata(&sdev->dev, rinfo);381 382	return 0;383}384 385static void scmi_regulator_remove(struct scmi_device *sdev)386{387	int d;388	struct scmi_regulator_info *rinfo;389 390	rinfo = dev_get_drvdata(&sdev->dev);391	if (!rinfo)392		return;393 394	for (d = 0; d < rinfo->num_doms; d++) {395		if (!rinfo->sregv[d])396			continue;397		of_node_put(rinfo->sregv[d]->of_node);398	}399}400 401static const struct scmi_device_id scmi_regulator_id_table[] = {402	{ SCMI_PROTOCOL_VOLTAGE,  "regulator" },403	{ },404};405MODULE_DEVICE_TABLE(scmi, scmi_regulator_id_table);406 407static struct scmi_driver scmi_drv = {408	.name		= "scmi-regulator",409	.probe		= scmi_regulator_probe,410	.remove		= scmi_regulator_remove,411	.id_table	= scmi_regulator_id_table,412};413 414module_scmi_driver(scmi_drv);415 416MODULE_AUTHOR("Cristian Marussi <cristian.marussi@arm.com>");417MODULE_DESCRIPTION("ARM SCMI regulator driver");418MODULE_LICENSE("GPL v2");419