121b72156SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0
221b72156SMatti Vaittinen // Copyright (C) 2020 ROHM Semiconductors
321b72156SMatti Vaittinen 
421b72156SMatti Vaittinen #include <linux/errno.h>
521b72156SMatti Vaittinen #include <linux/mfd/rohm-generic.h>
621b72156SMatti Vaittinen #include <linux/module.h>
721b72156SMatti Vaittinen #include <linux/of.h>
821b72156SMatti Vaittinen #include <linux/regmap.h>
921b72156SMatti Vaittinen #include <linux/regulator/driver.h>
1021b72156SMatti Vaittinen 
set_dvs_level(const struct regulator_desc * desc,struct device_node * np,struct regmap * regmap,char * prop,unsigned int reg,unsigned int mask,unsigned int omask,unsigned int oreg)1121b72156SMatti Vaittinen static int set_dvs_level(const struct regulator_desc *desc,
1221b72156SMatti Vaittinen 			 struct device_node *np, struct regmap *regmap,
1321b72156SMatti Vaittinen 			 char *prop, unsigned int reg, unsigned int mask,
1421b72156SMatti Vaittinen 			 unsigned int omask, unsigned int oreg)
1521b72156SMatti Vaittinen {
1621b72156SMatti Vaittinen 	int ret, i;
1721b72156SMatti Vaittinen 	uint32_t uv;
1821b72156SMatti Vaittinen 
1921b72156SMatti Vaittinen 	ret = of_property_read_u32(np, prop, &uv);
2021b72156SMatti Vaittinen 	if (ret) {
2121b72156SMatti Vaittinen 		if (ret != -EINVAL)
2221b72156SMatti Vaittinen 			return ret;
2321b72156SMatti Vaittinen 		return 0;
2421b72156SMatti Vaittinen 	}
259cf37cecSMatti Vaittinen 	/* If voltage is set to 0 => disable */
2621b72156SMatti Vaittinen 	if (uv == 0) {
2721b72156SMatti Vaittinen 		if (omask)
2821b72156SMatti Vaittinen 			return regmap_update_bits(regmap, oreg, omask, 0);
2921b72156SMatti Vaittinen 	}
309cf37cecSMatti Vaittinen 	/* Some setups don't allow setting own voltage but do allow enabling */
319cf37cecSMatti Vaittinen 	if (!mask) {
329cf37cecSMatti Vaittinen 		if (omask)
339cf37cecSMatti Vaittinen 			return regmap_update_bits(regmap, oreg, omask, omask);
349cf37cecSMatti Vaittinen 
359cf37cecSMatti Vaittinen 		return -EINVAL;
369cf37cecSMatti Vaittinen 	}
3721b72156SMatti Vaittinen 	for (i = 0; i < desc->n_voltages; i++) {
389cf37cecSMatti Vaittinen 		/* NOTE to next hacker - Does not support pickable ranges */
39*269cb04bSChen-Yu Tsai 		if (desc->linear_range_selectors_bitfield)
409cf37cecSMatti Vaittinen 			return -EINVAL;
419cf37cecSMatti Vaittinen 		if (desc->n_linear_ranges)
4221b72156SMatti Vaittinen 			ret = regulator_desc_list_voltage_linear_range(desc, i);
439cf37cecSMatti Vaittinen 		else
449cf37cecSMatti Vaittinen 			ret = regulator_desc_list_voltage_linear(desc, i);
4521b72156SMatti Vaittinen 		if (ret < 0)
4621b72156SMatti Vaittinen 			continue;
4721b72156SMatti Vaittinen 		if (ret == uv) {
4821b72156SMatti Vaittinen 			i <<= ffs(desc->vsel_mask) - 1;
4921b72156SMatti Vaittinen 			ret = regmap_update_bits(regmap, reg, mask, i);
5021b72156SMatti Vaittinen 			if (omask && !ret)
5121b72156SMatti Vaittinen 				ret = regmap_update_bits(regmap, oreg, omask,
5221b72156SMatti Vaittinen 							 omask);
5321b72156SMatti Vaittinen 			break;
5421b72156SMatti Vaittinen 		}
5521b72156SMatti Vaittinen 	}
5621b72156SMatti Vaittinen 	return ret;
5721b72156SMatti Vaittinen }
5821b72156SMatti Vaittinen 
rohm_regulator_set_dvs_levels(const struct rohm_dvs_config * dvs,struct device_node * np,const struct regulator_desc * desc,struct regmap * regmap)5921b72156SMatti Vaittinen int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
6021b72156SMatti Vaittinen 			  struct device_node *np,
6121b72156SMatti Vaittinen 			  const struct regulator_desc *desc,
6221b72156SMatti Vaittinen 			  struct regmap *regmap)
6321b72156SMatti Vaittinen {
6421b72156SMatti Vaittinen 	int i, ret = 0;
6521b72156SMatti Vaittinen 	char *prop;
6621b72156SMatti Vaittinen 	unsigned int reg, mask, omask, oreg = desc->enable_reg;
6721b72156SMatti Vaittinen 
68c2945541SMatti Vaittinen 	for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) {
69c2945541SMatti Vaittinen 		int bit;
70c2945541SMatti Vaittinen 
71c2945541SMatti Vaittinen 		bit = BIT(i);
72c2945541SMatti Vaittinen 		if (dvs->level_map & bit) {
73c2945541SMatti Vaittinen 			switch (bit) {
7421b72156SMatti Vaittinen 			case ROHM_DVS_LEVEL_RUN:
7521b72156SMatti Vaittinen 				prop = "rohm,dvs-run-voltage";
7621b72156SMatti Vaittinen 				reg = dvs->run_reg;
7721b72156SMatti Vaittinen 				mask = dvs->run_mask;
7821b72156SMatti Vaittinen 				omask = dvs->run_on_mask;
7921b72156SMatti Vaittinen 				break;
8021b72156SMatti Vaittinen 			case ROHM_DVS_LEVEL_IDLE:
8121b72156SMatti Vaittinen 				prop = "rohm,dvs-idle-voltage";
8221b72156SMatti Vaittinen 				reg = dvs->idle_reg;
8321b72156SMatti Vaittinen 				mask = dvs->idle_mask;
8421b72156SMatti Vaittinen 				omask = dvs->idle_on_mask;
8521b72156SMatti Vaittinen 				break;
8621b72156SMatti Vaittinen 			case ROHM_DVS_LEVEL_SUSPEND:
8721b72156SMatti Vaittinen 				prop = "rohm,dvs-suspend-voltage";
8821b72156SMatti Vaittinen 				reg = dvs->suspend_reg;
8921b72156SMatti Vaittinen 				mask = dvs->suspend_mask;
9021b72156SMatti Vaittinen 				omask = dvs->suspend_on_mask;
9121b72156SMatti Vaittinen 				break;
9221b72156SMatti Vaittinen 			case ROHM_DVS_LEVEL_LPSR:
9321b72156SMatti Vaittinen 				prop = "rohm,dvs-lpsr-voltage";
9421b72156SMatti Vaittinen 				reg = dvs->lpsr_reg;
9521b72156SMatti Vaittinen 				mask = dvs->lpsr_mask;
9621b72156SMatti Vaittinen 				omask = dvs->lpsr_on_mask;
9721b72156SMatti Vaittinen 				break;
9880a71170SMatti Vaittinen 			case ROHM_DVS_LEVEL_SNVS:
9980a71170SMatti Vaittinen 				prop = "rohm,dvs-snvs-voltage";
10080a71170SMatti Vaittinen 				reg = dvs->snvs_reg;
10180a71170SMatti Vaittinen 				mask = dvs->snvs_mask;
10280a71170SMatti Vaittinen 				omask = dvs->snvs_on_mask;
10380a71170SMatti Vaittinen 				break;
10421b72156SMatti Vaittinen 			default:
10521b72156SMatti Vaittinen 				return -EINVAL;
10621b72156SMatti Vaittinen 			}
10721b72156SMatti Vaittinen 			ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
10821b72156SMatti Vaittinen 					    omask, oreg);
10921b72156SMatti Vaittinen 		}
11021b72156SMatti Vaittinen 	}
11121b72156SMatti Vaittinen 	return ret;
11221b72156SMatti Vaittinen }
11321b72156SMatti Vaittinen EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
11421b72156SMatti Vaittinen 
1158b6e8855SMatti Vaittinen /*
1168b6e8855SMatti Vaittinen  * Few ROHM PMIC ICs have constrains on voltage changing:
1178b6e8855SMatti Vaittinen  * BD71837 - only buck 1-4 voltages can be changed when they are enabled.
1188b6e8855SMatti Vaittinen  * Other bucks and all LDOs must be disabled when voltage is changed.
1198b6e8855SMatti Vaittinen  * BD96801 - LDO voltage levels can be changed when LDOs are disabled.
1208b6e8855SMatti Vaittinen  */
rohm_regulator_set_voltage_sel_restricted(struct regulator_dev * rdev,unsigned int sel)1218b6e8855SMatti Vaittinen int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
1228b6e8855SMatti Vaittinen 					      unsigned int sel)
1238b6e8855SMatti Vaittinen {
1248b6e8855SMatti Vaittinen 	if (rdev->desc->ops->is_enabled(rdev))
1258b6e8855SMatti Vaittinen 		return -EBUSY;
1268b6e8855SMatti Vaittinen 
1278b6e8855SMatti Vaittinen 	return regulator_set_voltage_sel_regmap(rdev, sel);
1288b6e8855SMatti Vaittinen }
1298b6e8855SMatti Vaittinen EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted);
1308b6e8855SMatti Vaittinen 
13121b72156SMatti Vaittinen MODULE_LICENSE("GPL v2");
13221b72156SMatti Vaittinen MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
13321b72156SMatti Vaittinen MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
134