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