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