Commit | Line | Data |
---|---|---|
21b72156 MV |
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 | } | |
9cf37cec | 25 | /* If voltage is set to 0 => disable */ |
21b72156 MV |
26 | if (uv == 0) { |
27 | if (omask) | |
28 | return regmap_update_bits(regmap, oreg, omask, 0); | |
29 | } | |
9cf37cec MV |
30 | /* Some setups don't allow setting own voltage but do allow enabling */ |
31 | if (!mask) { | |
32 | if (omask) | |
33 | return regmap_update_bits(regmap, oreg, omask, omask); | |
34 | ||
35 | return -EINVAL; | |
36 | } | |
21b72156 | 37 | for (i = 0; i < desc->n_voltages; i++) { |
9cf37cec MV |
38 | /* NOTE to next hacker - Does not support pickable ranges */ |
39 | if (desc->linear_range_selectors) | |
40 | return -EINVAL; | |
41 | if (desc->n_linear_ranges) | |
42 | ret = regulator_desc_list_voltage_linear_range(desc, i); | |
43 | else | |
44 | ret = regulator_desc_list_voltage_linear(desc, i); | |
21b72156 MV |
45 | if (ret < 0) |
46 | continue; | |
47 | if (ret == uv) { | |
48 | i <<= ffs(desc->vsel_mask) - 1; | |
49 | ret = regmap_update_bits(regmap, reg, mask, i); | |
50 | if (omask && !ret) | |
51 | ret = regmap_update_bits(regmap, oreg, omask, | |
52 | omask); | |
53 | break; | |
54 | } | |
55 | } | |
56 | return ret; | |
57 | } | |
58 | ||
59 | int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, | |
60 | struct device_node *np, | |
61 | const struct regulator_desc *desc, | |
62 | struct regmap *regmap) | |
63 | { | |
64 | int i, ret = 0; | |
65 | char *prop; | |
66 | unsigned int reg, mask, omask, oreg = desc->enable_reg; | |
67 | ||
c2945541 MV |
68 | for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) { |
69 | int bit; | |
70 | ||
71 | bit = BIT(i); | |
72 | if (dvs->level_map & bit) { | |
73 | switch (bit) { | |
21b72156 MV |
74 | case ROHM_DVS_LEVEL_RUN: |
75 | prop = "rohm,dvs-run-voltage"; | |
76 | reg = dvs->run_reg; | |
77 | mask = dvs->run_mask; | |
78 | omask = dvs->run_on_mask; | |
79 | break; | |
80 | case ROHM_DVS_LEVEL_IDLE: | |
81 | prop = "rohm,dvs-idle-voltage"; | |
82 | reg = dvs->idle_reg; | |
83 | mask = dvs->idle_mask; | |
84 | omask = dvs->idle_on_mask; | |
85 | break; | |
86 | case ROHM_DVS_LEVEL_SUSPEND: | |
87 | prop = "rohm,dvs-suspend-voltage"; | |
88 | reg = dvs->suspend_reg; | |
89 | mask = dvs->suspend_mask; | |
90 | omask = dvs->suspend_on_mask; | |
91 | break; | |
92 | case ROHM_DVS_LEVEL_LPSR: | |
93 | prop = "rohm,dvs-lpsr-voltage"; | |
94 | reg = dvs->lpsr_reg; | |
95 | mask = dvs->lpsr_mask; | |
96 | omask = dvs->lpsr_on_mask; | |
97 | break; | |
80a71170 MV |
98 | case ROHM_DVS_LEVEL_SNVS: |
99 | prop = "rohm,dvs-snvs-voltage"; | |
100 | reg = dvs->snvs_reg; | |
101 | mask = dvs->snvs_mask; | |
102 | omask = dvs->snvs_on_mask; | |
103 | break; | |
21b72156 MV |
104 | default: |
105 | return -EINVAL; | |
106 | } | |
107 | ret = set_dvs_level(desc, np, regmap, prop, reg, mask, | |
108 | omask, oreg); | |
109 | } | |
110 | } | |
111 | return ret; | |
112 | } | |
113 | EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); | |
114 | ||
8b6e8855 MV |
115 | /* |
116 | * Few ROHM PMIC ICs have constrains on voltage changing: | |
117 | * BD71837 - only buck 1-4 voltages can be changed when they are enabled. | |
118 | * Other bucks and all LDOs must be disabled when voltage is changed. | |
119 | * BD96801 - LDO voltage levels can be changed when LDOs are disabled. | |
120 | */ | |
121 | int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, | |
122 | unsigned int sel) | |
123 | { | |
124 | if (rdev->desc->ops->is_enabled(rdev)) | |
125 | return -EBUSY; | |
126 | ||
127 | return regulator_set_voltage_sel_regmap(rdev, sel); | |
128 | } | |
129 | EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); | |
130 | ||
21b72156 MV |
131 | MODULE_LICENSE("GPL v2"); |
132 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); | |
133 | MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); |