xref: /OK3568_Linux_fs/kernel/drivers/regulator/rohm-regulator.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright (C) 2020 ROHM Semiconductors
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/errno.h>
5*4882a593Smuzhiyun #include <linux/mfd/rohm-generic.h>
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <linux/of.h>
8*4882a593Smuzhiyun #include <linux/regmap.h>
9*4882a593Smuzhiyun #include <linux/regulator/driver.h>
10*4882a593Smuzhiyun 
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)11*4882a593Smuzhiyun static int set_dvs_level(const struct regulator_desc *desc,
12*4882a593Smuzhiyun 			 struct device_node *np, struct regmap *regmap,
13*4882a593Smuzhiyun 			 char *prop, unsigned int reg, unsigned int mask,
14*4882a593Smuzhiyun 			 unsigned int omask, unsigned int oreg)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	int ret, i;
17*4882a593Smuzhiyun 	uint32_t uv;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	ret = of_property_read_u32(np, prop, &uv);
20*4882a593Smuzhiyun 	if (ret) {
21*4882a593Smuzhiyun 		if (ret != -EINVAL)
22*4882a593Smuzhiyun 			return ret;
23*4882a593Smuzhiyun 		return 0;
24*4882a593Smuzhiyun 	}
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun 	if (uv == 0) {
27*4882a593Smuzhiyun 		if (omask)
28*4882a593Smuzhiyun 			return regmap_update_bits(regmap, oreg, omask, 0);
29*4882a593Smuzhiyun 	}
30*4882a593Smuzhiyun 	for (i = 0; i < desc->n_voltages; i++) {
31*4882a593Smuzhiyun 		ret = regulator_desc_list_voltage_linear_range(desc, i);
32*4882a593Smuzhiyun 		if (ret < 0)
33*4882a593Smuzhiyun 			continue;
34*4882a593Smuzhiyun 		if (ret == uv) {
35*4882a593Smuzhiyun 			i <<= ffs(desc->vsel_mask) - 1;
36*4882a593Smuzhiyun 			ret = regmap_update_bits(regmap, reg, mask, i);
37*4882a593Smuzhiyun 			if (omask && !ret)
38*4882a593Smuzhiyun 				ret = regmap_update_bits(regmap, oreg, omask,
39*4882a593Smuzhiyun 							 omask);
40*4882a593Smuzhiyun 			break;
41*4882a593Smuzhiyun 		}
42*4882a593Smuzhiyun 	}
43*4882a593Smuzhiyun 	return ret;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
rohm_regulator_set_dvs_levels(const struct rohm_dvs_config * dvs,struct device_node * np,const struct regulator_desc * desc,struct regmap * regmap)46*4882a593Smuzhiyun int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
47*4882a593Smuzhiyun 			  struct device_node *np,
48*4882a593Smuzhiyun 			  const struct regulator_desc *desc,
49*4882a593Smuzhiyun 			  struct regmap *regmap)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	int i, ret = 0;
52*4882a593Smuzhiyun 	char *prop;
53*4882a593Smuzhiyun 	unsigned int reg, mask, omask, oreg = desc->enable_reg;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) {
56*4882a593Smuzhiyun 		int bit;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 		bit = BIT(i);
59*4882a593Smuzhiyun 		if (dvs->level_map & bit) {
60*4882a593Smuzhiyun 			switch (bit) {
61*4882a593Smuzhiyun 			case ROHM_DVS_LEVEL_RUN:
62*4882a593Smuzhiyun 				prop = "rohm,dvs-run-voltage";
63*4882a593Smuzhiyun 				reg = dvs->run_reg;
64*4882a593Smuzhiyun 				mask = dvs->run_mask;
65*4882a593Smuzhiyun 				omask = dvs->run_on_mask;
66*4882a593Smuzhiyun 				break;
67*4882a593Smuzhiyun 			case ROHM_DVS_LEVEL_IDLE:
68*4882a593Smuzhiyun 				prop = "rohm,dvs-idle-voltage";
69*4882a593Smuzhiyun 				reg = dvs->idle_reg;
70*4882a593Smuzhiyun 				mask = dvs->idle_mask;
71*4882a593Smuzhiyun 				omask = dvs->idle_on_mask;
72*4882a593Smuzhiyun 				break;
73*4882a593Smuzhiyun 			case ROHM_DVS_LEVEL_SUSPEND:
74*4882a593Smuzhiyun 				prop = "rohm,dvs-suspend-voltage";
75*4882a593Smuzhiyun 				reg = dvs->suspend_reg;
76*4882a593Smuzhiyun 				mask = dvs->suspend_mask;
77*4882a593Smuzhiyun 				omask = dvs->suspend_on_mask;
78*4882a593Smuzhiyun 				break;
79*4882a593Smuzhiyun 			case ROHM_DVS_LEVEL_LPSR:
80*4882a593Smuzhiyun 				prop = "rohm,dvs-lpsr-voltage";
81*4882a593Smuzhiyun 				reg = dvs->lpsr_reg;
82*4882a593Smuzhiyun 				mask = dvs->lpsr_mask;
83*4882a593Smuzhiyun 				omask = dvs->lpsr_on_mask;
84*4882a593Smuzhiyun 				break;
85*4882a593Smuzhiyun 			default:
86*4882a593Smuzhiyun 				return -EINVAL;
87*4882a593Smuzhiyun 			}
88*4882a593Smuzhiyun 			ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
89*4882a593Smuzhiyun 					    omask, oreg);
90*4882a593Smuzhiyun 		}
91*4882a593Smuzhiyun 	}
92*4882a593Smuzhiyun 	return ret;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
97*4882a593Smuzhiyun MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
98*4882a593Smuzhiyun MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
99