GNU Linux-libre 5.10.219-gnu1
[releases.git] / drivers / regulator / rohm-regulator.c
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");