blob: 3e342f48086bd48b12c10714f0a1a455ba8cab75 [file] [log] [blame]
Christophe Kerello069f0b62018-04-26 17:13:09 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
4 * Author: Christophe Kerello <christophe.kerello@st.com>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <errno.h>
Simon Glassc05ed002020-05-10 11:40:11 -060010#include <linux/delay.h>
Christophe Kerello069f0b62018-04-26 17:13:09 +020011#include <power/pmic.h>
12#include <power/regulator.h>
Patrick Delaunayd46c22b2019-02-04 11:26:16 +010013#include <power/stpmic1.h>
Christophe Kerello069f0b62018-04-26 17:13:09 +020014
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010015struct stpmic1_range {
Christophe Kerello069f0b62018-04-26 17:13:09 +020016 int min_uv;
17 int min_sel;
18 int max_sel;
19 int step;
20};
21
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010022struct stpmic1_output {
23 const struct stpmic1_range *ranges;
Christophe Kerello069f0b62018-04-26 17:13:09 +020024 int nbranges;
25};
26
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010027#define STPMIC1_MODE(_id, _val, _name) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020028 .id = _id, \
29 .register_value = _val, \
30 .name = _name, \
31}
32
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010033#define STPMIC1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020034 .min_uv = _min_uv, \
35 .min_sel = _min_sel, \
36 .max_sel = _max_sel, \
37 .step = _step, \
38}
39
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010040#define STPMIC1_OUTPUT(_ranges, _nbranges) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020041 .ranges = _ranges, \
42 .nbranges = _nbranges, \
43}
44
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010045static int stpmic1_output_find_uv(int sel,
46 const struct stpmic1_output *output)
Christophe Kerello069f0b62018-04-26 17:13:09 +020047{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010048 const struct stpmic1_range *range;
Christophe Kerello069f0b62018-04-26 17:13:09 +020049 int i;
50
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010051 for (i = 0, range = output->ranges;
52 i < output->nbranges; i++, range++) {
Christophe Kerello069f0b62018-04-26 17:13:09 +020053 if (sel >= range->min_sel && sel <= range->max_sel)
54 return range->min_uv +
55 (sel - range->min_sel) * range->step;
56 }
57
58 return -EINVAL;
59}
60
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010061static int stpmic1_output_find_sel(int uv,
62 const struct stpmic1_output *output)
Christophe Kerello069f0b62018-04-26 17:13:09 +020063{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010064 const struct stpmic1_range *range;
Christophe Kerello069f0b62018-04-26 17:13:09 +020065 int i;
66
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010067 for (i = 0, range = output->ranges;
68 i < output->nbranges; i++, range++) {
Christophe Kerello069f0b62018-04-26 17:13:09 +020069 if (uv == range->min_uv && !range->step)
70 return range->min_sel;
71
72 if (uv >= range->min_uv &&
73 uv <= range->min_uv +
74 (range->max_sel - range->min_sel) * range->step)
75 return range->min_sel +
76 (uv - range->min_uv) / range->step;
77 }
78
79 return -EINVAL;
80}
81
82/*
83 * BUCK regulators
84 */
85
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010086static const struct stpmic1_range buck1_ranges[] = {
87 STPMIC1_RANGE(725000, 0, 4, 0),
88 STPMIC1_RANGE(725000, 5, 36, 25000),
89 STPMIC1_RANGE(1500000, 37, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +020090};
91
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010092static const struct stpmic1_range buck2_ranges[] = {
93 STPMIC1_RANGE(1000000, 0, 17, 0),
94 STPMIC1_RANGE(1050000, 18, 19, 0),
95 STPMIC1_RANGE(1100000, 20, 21, 0),
96 STPMIC1_RANGE(1150000, 22, 23, 0),
97 STPMIC1_RANGE(1200000, 24, 25, 0),
98 STPMIC1_RANGE(1250000, 26, 27, 0),
99 STPMIC1_RANGE(1300000, 28, 29, 0),
100 STPMIC1_RANGE(1350000, 30, 31, 0),
101 STPMIC1_RANGE(1400000, 32, 33, 0),
102 STPMIC1_RANGE(1450000, 34, 35, 0),
103 STPMIC1_RANGE(1500000, 36, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200104};
105
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100106static const struct stpmic1_range buck3_ranges[] = {
107 STPMIC1_RANGE(1000000, 0, 19, 0),
108 STPMIC1_RANGE(1100000, 20, 23, 0),
109 STPMIC1_RANGE(1200000, 24, 27, 0),
110 STPMIC1_RANGE(1300000, 28, 31, 0),
111 STPMIC1_RANGE(1400000, 32, 35, 0),
112 STPMIC1_RANGE(1500000, 36, 55, 100000),
113 STPMIC1_RANGE(3400000, 56, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200114};
115
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100116static const struct stpmic1_range buck4_ranges[] = {
117 STPMIC1_RANGE(600000, 0, 27, 25000),
118 STPMIC1_RANGE(1300000, 28, 29, 0),
119 STPMIC1_RANGE(1350000, 30, 31, 0),
120 STPMIC1_RANGE(1400000, 32, 33, 0),
121 STPMIC1_RANGE(1450000, 34, 35, 0),
122 STPMIC1_RANGE(1500000, 36, 60, 100000),
123 STPMIC1_RANGE(3900000, 61, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200124};
125
126/* BUCK: 1,2,3,4 - voltage ranges */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100127static const struct stpmic1_output buck_voltage_range[] = {
128 STPMIC1_OUTPUT(buck1_ranges, ARRAY_SIZE(buck1_ranges)),
129 STPMIC1_OUTPUT(buck2_ranges, ARRAY_SIZE(buck2_ranges)),
130 STPMIC1_OUTPUT(buck3_ranges, ARRAY_SIZE(buck3_ranges)),
131 STPMIC1_OUTPUT(buck4_ranges, ARRAY_SIZE(buck4_ranges)),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200132};
133
134/* BUCK modes */
135static const struct dm_regulator_mode buck_modes[] = {
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100136 STPMIC1_MODE(STPMIC1_PREG_MODE_HP, STPMIC1_PREG_MODE_HP, "HP"),
137 STPMIC1_MODE(STPMIC1_PREG_MODE_LP, STPMIC1_PREG_MODE_LP, "LP"),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200138};
139
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100140static int stpmic1_buck_get_uv(struct udevice *dev, int buck)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200141{
142 int sel;
143
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100144 sel = pmic_reg_read(dev, STPMIC1_BUCKX_MAIN_CR(buck));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200145 if (sel < 0)
146 return sel;
147
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100148 sel &= STPMIC1_BUCK_VOUT_MASK;
149 sel >>= STPMIC1_BUCK_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200150
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100151 return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200152}
153
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100154static int stpmic1_buck_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200155{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100156 return stpmic1_buck_get_uv(dev->parent, dev->driver_data - 1);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200157}
158
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100159static int stpmic1_buck_set_value(struct udevice *dev, int uv)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200160{
161 int sel, buck = dev->driver_data - 1;
162
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100163 sel = stpmic1_output_find_sel(uv, &buck_voltage_range[buck]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200164 if (sel < 0)
165 return sel;
166
167 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100168 STPMIC1_BUCKX_MAIN_CR(buck),
169 STPMIC1_BUCK_VOUT_MASK,
170 sel << STPMIC1_BUCK_VOUT_SHIFT);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200171}
172
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100173static int stpmic1_buck_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200174{
175 int ret;
176
177 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100178 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200179 if (ret < 0)
180 return false;
181
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100182 return ret & STPMIC1_BUCK_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200183}
184
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100185static int stpmic1_buck_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200186{
187 struct dm_regulator_uclass_platdata *uc_pdata;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100188 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
189 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200190 int ret, uv;
191
192 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100193 if (stpmic1_buck_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200194 return 0;
195
196 if (enable) {
197 uc_pdata = dev_get_uclass_platdata(dev);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100198 uv = stpmic1_buck_get_value(dev);
199 if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
200 stpmic1_buck_set_value(dev, uc_pdata->min_uV);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200201 }
202
203 ret = pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100204 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
205 STPMIC1_BUCK_ENA, enable ? STPMIC1_BUCK_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200206 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200207
208 return ret;
209}
210
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100211static int stpmic1_buck_get_mode(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200212{
213 int ret;
214
215 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100216 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200217 if (ret < 0)
218 return ret;
219
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100220 return ret & STPMIC1_BUCK_PREG_MODE ? STPMIC1_PREG_MODE_LP :
221 STPMIC1_PREG_MODE_HP;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200222}
223
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100224static int stpmic1_buck_set_mode(struct udevice *dev, int mode)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200225{
226 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100227 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
228 STPMIC1_BUCK_PREG_MODE,
229 mode ? STPMIC1_BUCK_PREG_MODE : 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200230}
231
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100232static int stpmic1_buck_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200233{
234 struct dm_regulator_uclass_platdata *uc_pdata;
235
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100236 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_BUCK)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200237 return -EINVAL;
238
239 uc_pdata = dev_get_uclass_platdata(dev);
240
241 uc_pdata->type = REGULATOR_TYPE_BUCK;
242 uc_pdata->mode = (struct dm_regulator_mode *)buck_modes;
243 uc_pdata->mode_count = ARRAY_SIZE(buck_modes);
244
245 return 0;
246}
247
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100248static const struct dm_regulator_ops stpmic1_buck_ops = {
249 .get_value = stpmic1_buck_get_value,
250 .set_value = stpmic1_buck_set_value,
251 .get_enable = stpmic1_buck_get_enable,
252 .set_enable = stpmic1_buck_set_enable,
253 .get_mode = stpmic1_buck_get_mode,
254 .set_mode = stpmic1_buck_set_mode,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200255};
256
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100257U_BOOT_DRIVER(stpmic1_buck) = {
258 .name = "stpmic1_buck",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200259 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100260 .ops = &stpmic1_buck_ops,
261 .probe = stpmic1_buck_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200262};
263
264/*
265 * LDO regulators
266 */
267
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100268static const struct stpmic1_range ldo12_ranges[] = {
269 STPMIC1_RANGE(1700000, 0, 7, 0),
270 STPMIC1_RANGE(1700000, 8, 24, 100000),
271 STPMIC1_RANGE(3300000, 25, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200272};
273
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100274static const struct stpmic1_range ldo3_ranges[] = {
275 STPMIC1_RANGE(1700000, 0, 7, 0),
276 STPMIC1_RANGE(1700000, 8, 24, 100000),
277 STPMIC1_RANGE(3300000, 25, 30, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200278 /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */
279};
280
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100281static const struct stpmic1_range ldo5_ranges[] = {
282 STPMIC1_RANGE(1700000, 0, 7, 0),
283 STPMIC1_RANGE(1700000, 8, 30, 100000),
284 STPMIC1_RANGE(3900000, 31, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200285};
286
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100287static const struct stpmic1_range ldo6_ranges[] = {
288 STPMIC1_RANGE(900000, 0, 24, 100000),
289 STPMIC1_RANGE(3300000, 25, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200290};
291
292/* LDO: 1,2,3,4,5,6 - voltage ranges */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100293static const struct stpmic1_output ldo_voltage_range[] = {
294 STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
295 STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
296 STPMIC1_OUTPUT(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)),
297 STPMIC1_OUTPUT(NULL, 0),
298 STPMIC1_OUTPUT(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)),
299 STPMIC1_OUTPUT(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200300};
301
302/* LDO modes */
303static const struct dm_regulator_mode ldo_modes[] = {
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100304 STPMIC1_MODE(STPMIC1_LDO_MODE_NORMAL,
305 STPMIC1_LDO_MODE_NORMAL, "NORMAL"),
306 STPMIC1_MODE(STPMIC1_LDO_MODE_BYPASS,
307 STPMIC1_LDO_MODE_BYPASS, "BYPASS"),
308 STPMIC1_MODE(STPMIC1_LDO_MODE_SINK_SOURCE,
309 STPMIC1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200310};
311
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100312static int stpmic1_ldo_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200313{
314 int sel, ldo = dev->driver_data - 1;
315
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100316 sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200317 if (sel < 0)
318 return sel;
319
320 /* ldo4 => 3,3V */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100321 if (ldo == STPMIC1_LDO4)
322 return STPMIC1_LDO4_UV;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200323
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100324 sel &= STPMIC1_LDO12356_VOUT_MASK;
325 sel >>= STPMIC1_LDO12356_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200326
327 /* ldo3, sel = 31 => BUCK2/2 */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100328 if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL)
329 return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200330
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100331 return stpmic1_output_find_uv(sel, &ldo_voltage_range[ldo]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200332}
333
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100334static int stpmic1_ldo_set_value(struct udevice *dev, int uv)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200335{
336 int sel, ldo = dev->driver_data - 1;
337
338 /* ldo4 => not possible */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100339 if (ldo == STPMIC1_LDO4)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200340 return -EINVAL;
341
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100342 sel = stpmic1_output_find_sel(uv, &ldo_voltage_range[ldo]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200343 if (sel < 0)
344 return sel;
345
346 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100347 STPMIC1_LDOX_MAIN_CR(ldo),
348 STPMIC1_LDO12356_VOUT_MASK,
349 sel << STPMIC1_LDO12356_VOUT_SHIFT);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200350}
351
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100352static int stpmic1_ldo_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200353{
354 int ret;
355
356 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100357 STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200358 if (ret < 0)
359 return false;
360
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100361 return ret & STPMIC1_LDO_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200362}
363
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100364static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200365{
366 struct dm_regulator_uclass_platdata *uc_pdata;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100367 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
368 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200369 int ret, uv;
370
371 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100372 if (stpmic1_ldo_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200373 return 0;
374
375 if (enable) {
376 uc_pdata = dev_get_uclass_platdata(dev);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100377 uv = stpmic1_ldo_get_value(dev);
378 if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
379 stpmic1_ldo_set_value(dev, uc_pdata->min_uV);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200380 }
381
382 ret = pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100383 STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1),
384 STPMIC1_LDO_ENA, enable ? STPMIC1_LDO_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200385 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200386
387 return ret;
388}
389
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100390static int stpmic1_ldo_get_mode(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200391{
392 int ret, ldo = dev->driver_data - 1;
393
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100394 if (ldo != STPMIC1_LDO3)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200395 return -EINVAL;
396
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100397 ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200398 if (ret < 0)
399 return ret;
400
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100401 if (ret & STPMIC1_LDO3_MODE)
402 return STPMIC1_LDO_MODE_BYPASS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200403
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100404 ret &= STPMIC1_LDO12356_VOUT_MASK;
405 ret >>= STPMIC1_LDO12356_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200406
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100407 return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE :
408 STPMIC1_LDO_MODE_NORMAL;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200409}
410
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100411static int stpmic1_ldo_set_mode(struct udevice *dev, int mode)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200412{
413 int ret, ldo = dev->driver_data - 1;
414
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100415 if (ldo != STPMIC1_LDO3)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200416 return -EINVAL;
417
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100418 ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200419 if (ret < 0)
420 return ret;
421
422 switch (mode) {
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100423 case STPMIC1_LDO_MODE_SINK_SOURCE:
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100424 ret &= ~STPMIC1_LDO12356_VOUT_MASK;
425 ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT;
Patrick Delaunay92be6832019-06-21 15:26:53 +0200426 /* fallthrough */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100427 case STPMIC1_LDO_MODE_NORMAL:
428 ret &= ~STPMIC1_LDO3_MODE;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200429 break;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100430 case STPMIC1_LDO_MODE_BYPASS:
431 ret |= STPMIC1_LDO3_MODE;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200432 break;
433 }
434
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100435 return pmic_reg_write(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo), ret);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200436}
437
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100438static int stpmic1_ldo_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200439{
440 struct dm_regulator_uclass_platdata *uc_pdata;
441
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100442 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_LDO)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200443 return -EINVAL;
444
445 uc_pdata = dev_get_uclass_platdata(dev);
446
447 uc_pdata->type = REGULATOR_TYPE_LDO;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100448 if (dev->driver_data - 1 == STPMIC1_LDO3) {
Christophe Kerello069f0b62018-04-26 17:13:09 +0200449 uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes;
450 uc_pdata->mode_count = ARRAY_SIZE(ldo_modes);
451 } else {
452 uc_pdata->mode_count = 0;
453 }
454
455 return 0;
456}
457
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100458static const struct dm_regulator_ops stpmic1_ldo_ops = {
459 .get_value = stpmic1_ldo_get_value,
460 .set_value = stpmic1_ldo_set_value,
461 .get_enable = stpmic1_ldo_get_enable,
462 .set_enable = stpmic1_ldo_set_enable,
463 .get_mode = stpmic1_ldo_get_mode,
464 .set_mode = stpmic1_ldo_set_mode,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200465};
466
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100467U_BOOT_DRIVER(stpmic1_ldo) = {
468 .name = "stpmic1_ldo",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200469 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100470 .ops = &stpmic1_ldo_ops,
471 .probe = stpmic1_ldo_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200472};
473
474/*
475 * VREF DDR regulator
476 */
477
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100478static int stpmic1_vref_ddr_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200479{
480 /* BUCK2/2 */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100481 return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200482}
483
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100484static int stpmic1_vref_ddr_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200485{
486 int ret;
487
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100488 ret = pmic_reg_read(dev->parent, STPMIC1_REFDDR_MAIN_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200489 if (ret < 0)
490 return false;
491
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100492 return ret & STPMIC1_VREF_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200493}
494
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100495static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200496{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100497 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
498 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200499 int ret;
500
501 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100502 if (stpmic1_vref_ddr_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200503 return 0;
504
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100505 ret = pmic_clrsetbits(dev->parent, STPMIC1_REFDDR_MAIN_CR,
506 STPMIC1_VREF_ENA, enable ? STPMIC1_VREF_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200507 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200508
509 return ret;
510}
511
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100512static int stpmic1_vref_ddr_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200513{
514 struct dm_regulator_uclass_platdata *uc_pdata;
515
516 uc_pdata = dev_get_uclass_platdata(dev);
517
518 uc_pdata->type = REGULATOR_TYPE_FIXED;
519 uc_pdata->mode_count = 0;
520
521 return 0;
522}
523
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100524static const struct dm_regulator_ops stpmic1_vref_ddr_ops = {
525 .get_value = stpmic1_vref_ddr_get_value,
526 .get_enable = stpmic1_vref_ddr_get_enable,
527 .set_enable = stpmic1_vref_ddr_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200528};
529
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100530U_BOOT_DRIVER(stpmic1_vref_ddr) = {
531 .name = "stpmic1_vref_ddr",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200532 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100533 .ops = &stpmic1_vref_ddr_ops,
534 .probe = stpmic1_vref_ddr_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200535};
536
537/*
538 * BOOST regulator
539 */
540
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100541static int stpmic1_boost_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200542{
543 int ret;
544
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100545 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200546 if (ret < 0)
547 return false;
548
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100549 return ret & STPMIC1_BST_ON ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200550}
551
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100552static int stpmic1_boost_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200553{
554 int ret;
555
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100556 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200557 if (ret < 0)
558 return ret;
559
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100560 if (!enable && ret & STPMIC1_PWR_SW_ON)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200561 return -EINVAL;
562
563 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100564 if (!!(ret & STPMIC1_BST_ON) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200565 return 0;
566
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100567 ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
568 STPMIC1_BST_ON,
569 enable ? STPMIC1_BST_ON : 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200570 if (enable)
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100571 mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200572
573 return ret;
574}
575
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100576static int stpmic1_boost_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200577{
578 struct dm_regulator_uclass_platdata *uc_pdata;
579
580 uc_pdata = dev_get_uclass_platdata(dev);
581
582 uc_pdata->type = REGULATOR_TYPE_FIXED;
583 uc_pdata->mode_count = 0;
584
585 return 0;
586}
587
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100588static const struct dm_regulator_ops stpmic1_boost_ops = {
589 .get_enable = stpmic1_boost_get_enable,
590 .set_enable = stpmic1_boost_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200591};
592
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100593U_BOOT_DRIVER(stpmic1_boost) = {
594 .name = "stpmic1_boost",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200595 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100596 .ops = &stpmic1_boost_ops,
597 .probe = stpmic1_boost_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200598};
599
600/*
601 * USB power switch
602 */
603
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100604static int stpmic1_pwr_sw_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200605{
606 uint mask = 1 << dev->driver_data;
607 int ret;
608
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100609 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200610 if (ret < 0)
611 return false;
612
613 return ret & mask ? true : false;
614}
615
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100616static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200617{
618 uint mask = 1 << dev->driver_data;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100619 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
620 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200621 int ret;
622
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100623 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200624 if (ret < 0)
625 return ret;
626
627 /* if regulator is already in the wanted state, nothing to do */
628 if (!!(ret & mask) == enable)
629 return 0;
630
631 /* Boost management */
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100632 if (enable && !(ret & STPMIC1_BST_ON)) {
633 pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
634 STPMIC1_BST_ON, STPMIC1_BST_ON);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100635 mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100636 } else if (!enable && ret & STPMIC1_BST_ON &&
637 (ret & STPMIC1_PWR_SW_ON) != STPMIC1_PWR_SW_ON) {
638 pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
639 STPMIC1_BST_ON, 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200640 }
641
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100642 ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200643 mask, enable ? mask : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200644 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200645
646 return ret;
647}
648
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100649static int stpmic1_pwr_sw_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200650{
651 struct dm_regulator_uclass_platdata *uc_pdata;
652
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100653 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_PWR_SW)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200654 return -EINVAL;
655
656 uc_pdata = dev_get_uclass_platdata(dev);
657
658 uc_pdata->type = REGULATOR_TYPE_FIXED;
659 uc_pdata->mode_count = 0;
660
661 return 0;
662}
663
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100664static const struct dm_regulator_ops stpmic1_pwr_sw_ops = {
665 .get_enable = stpmic1_pwr_sw_get_enable,
666 .set_enable = stpmic1_pwr_sw_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200667};
668
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100669U_BOOT_DRIVER(stpmic1_pwr_sw) = {
670 .name = "stpmic1_pwr_sw",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200671 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100672 .ops = &stpmic1_pwr_sw_ops,
673 .probe = stpmic1_pwr_sw_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200674};