blob: 50ef2a21d1816857ef28fb92899f6c34dcea523c [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>
10#include <power/pmic.h>
11#include <power/regulator.h>
Patrick Delaunayd46c22b2019-02-04 11:26:16 +010012#include <power/stpmic1.h>
Christophe Kerello069f0b62018-04-26 17:13:09 +020013
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010014struct stpmic1_range {
Christophe Kerello069f0b62018-04-26 17:13:09 +020015 int min_uv;
16 int min_sel;
17 int max_sel;
18 int step;
19};
20
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010021struct stpmic1_output {
22 const struct stpmic1_range *ranges;
Christophe Kerello069f0b62018-04-26 17:13:09 +020023 int nbranges;
24};
25
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010026#define STPMIC1_MODE(_id, _val, _name) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020027 .id = _id, \
28 .register_value = _val, \
29 .name = _name, \
30}
31
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010032#define STPMIC1_RANGE(_min_uv, _min_sel, _max_sel, _step) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020033 .min_uv = _min_uv, \
34 .min_sel = _min_sel, \
35 .max_sel = _max_sel, \
36 .step = _step, \
37}
38
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010039#define STPMIC1_OUTPUT(_ranges, _nbranges) { \
Christophe Kerello069f0b62018-04-26 17:13:09 +020040 .ranges = _ranges, \
41 .nbranges = _nbranges, \
42}
43
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010044static int stpmic1_output_find_uv(int sel,
45 const struct stpmic1_output *output)
Christophe Kerello069f0b62018-04-26 17:13:09 +020046{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010047 const struct stpmic1_range *range;
Christophe Kerello069f0b62018-04-26 17:13:09 +020048 int i;
49
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010050 for (i = 0, range = output->ranges;
51 i < output->nbranges; i++, range++) {
Christophe Kerello069f0b62018-04-26 17:13:09 +020052 if (sel >= range->min_sel && sel <= range->max_sel)
53 return range->min_uv +
54 (sel - range->min_sel) * range->step;
55 }
56
57 return -EINVAL;
58}
59
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010060static int stpmic1_output_find_sel(int uv,
61 const struct stpmic1_output *output)
Christophe Kerello069f0b62018-04-26 17:13:09 +020062{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010063 const struct stpmic1_range *range;
Christophe Kerello069f0b62018-04-26 17:13:09 +020064 int i;
65
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010066 for (i = 0, range = output->ranges;
67 i < output->nbranges; i++, range++) {
Christophe Kerello069f0b62018-04-26 17:13:09 +020068 if (uv == range->min_uv && !range->step)
69 return range->min_sel;
70
71 if (uv >= range->min_uv &&
72 uv <= range->min_uv +
73 (range->max_sel - range->min_sel) * range->step)
74 return range->min_sel +
75 (uv - range->min_uv) / range->step;
76 }
77
78 return -EINVAL;
79}
80
81/*
82 * BUCK regulators
83 */
84
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010085static const struct stpmic1_range buck1_ranges[] = {
86 STPMIC1_RANGE(725000, 0, 4, 0),
87 STPMIC1_RANGE(725000, 5, 36, 25000),
88 STPMIC1_RANGE(1500000, 37, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +020089};
90
Patrick Delaunay42f01aa2019-02-04 11:26:17 +010091static const struct stpmic1_range buck2_ranges[] = {
92 STPMIC1_RANGE(1000000, 0, 17, 0),
93 STPMIC1_RANGE(1050000, 18, 19, 0),
94 STPMIC1_RANGE(1100000, 20, 21, 0),
95 STPMIC1_RANGE(1150000, 22, 23, 0),
96 STPMIC1_RANGE(1200000, 24, 25, 0),
97 STPMIC1_RANGE(1250000, 26, 27, 0),
98 STPMIC1_RANGE(1300000, 28, 29, 0),
99 STPMIC1_RANGE(1350000, 30, 31, 0),
100 STPMIC1_RANGE(1400000, 32, 33, 0),
101 STPMIC1_RANGE(1450000, 34, 35, 0),
102 STPMIC1_RANGE(1500000, 36, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200103};
104
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100105static const struct stpmic1_range buck3_ranges[] = {
106 STPMIC1_RANGE(1000000, 0, 19, 0),
107 STPMIC1_RANGE(1100000, 20, 23, 0),
108 STPMIC1_RANGE(1200000, 24, 27, 0),
109 STPMIC1_RANGE(1300000, 28, 31, 0),
110 STPMIC1_RANGE(1400000, 32, 35, 0),
111 STPMIC1_RANGE(1500000, 36, 55, 100000),
112 STPMIC1_RANGE(3400000, 56, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200113};
114
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100115static const struct stpmic1_range buck4_ranges[] = {
116 STPMIC1_RANGE(600000, 0, 27, 25000),
117 STPMIC1_RANGE(1300000, 28, 29, 0),
118 STPMIC1_RANGE(1350000, 30, 31, 0),
119 STPMIC1_RANGE(1400000, 32, 33, 0),
120 STPMIC1_RANGE(1450000, 34, 35, 0),
121 STPMIC1_RANGE(1500000, 36, 60, 100000),
122 STPMIC1_RANGE(3900000, 61, 63, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200123};
124
125/* BUCK: 1,2,3,4 - voltage ranges */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100126static const struct stpmic1_output buck_voltage_range[] = {
127 STPMIC1_OUTPUT(buck1_ranges, ARRAY_SIZE(buck1_ranges)),
128 STPMIC1_OUTPUT(buck2_ranges, ARRAY_SIZE(buck2_ranges)),
129 STPMIC1_OUTPUT(buck3_ranges, ARRAY_SIZE(buck3_ranges)),
130 STPMIC1_OUTPUT(buck4_ranges, ARRAY_SIZE(buck4_ranges)),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200131};
132
133/* BUCK modes */
134static const struct dm_regulator_mode buck_modes[] = {
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100135 STPMIC1_MODE(STPMIC1_PREG_MODE_HP, STPMIC1_PREG_MODE_HP, "HP"),
136 STPMIC1_MODE(STPMIC1_PREG_MODE_LP, STPMIC1_PREG_MODE_LP, "LP"),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200137};
138
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100139static int stpmic1_buck_get_uv(struct udevice *dev, int buck)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200140{
141 int sel;
142
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100143 sel = pmic_reg_read(dev, STPMIC1_BUCKX_MAIN_CR(buck));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200144 if (sel < 0)
145 return sel;
146
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100147 sel &= STPMIC1_BUCK_VOUT_MASK;
148 sel >>= STPMIC1_BUCK_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200149
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100150 return stpmic1_output_find_uv(sel, &buck_voltage_range[buck]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200151}
152
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100153static int stpmic1_buck_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200154{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100155 return stpmic1_buck_get_uv(dev->parent, dev->driver_data - 1);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200156}
157
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100158static int stpmic1_buck_set_value(struct udevice *dev, int uv)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200159{
160 int sel, buck = dev->driver_data - 1;
161
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100162 sel = stpmic1_output_find_sel(uv, &buck_voltage_range[buck]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200163 if (sel < 0)
164 return sel;
165
166 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100167 STPMIC1_BUCKX_MAIN_CR(buck),
168 STPMIC1_BUCK_VOUT_MASK,
169 sel << STPMIC1_BUCK_VOUT_SHIFT);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200170}
171
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100172static int stpmic1_buck_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200173{
174 int ret;
175
176 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100177 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200178 if (ret < 0)
179 return false;
180
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100181 return ret & STPMIC1_BUCK_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200182}
183
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100184static int stpmic1_buck_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200185{
186 struct dm_regulator_uclass_platdata *uc_pdata;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100187 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
188 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200189 int ret, uv;
190
191 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100192 if (stpmic1_buck_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200193 return 0;
194
195 if (enable) {
196 uc_pdata = dev_get_uclass_platdata(dev);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100197 uv = stpmic1_buck_get_value(dev);
198 if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
199 stpmic1_buck_set_value(dev, uc_pdata->min_uV);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200200 }
201
202 ret = pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100203 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
204 STPMIC1_BUCK_ENA, enable ? STPMIC1_BUCK_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200205 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200206
207 return ret;
208}
209
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100210static int stpmic1_buck_get_mode(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200211{
212 int ret;
213
214 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100215 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200216 if (ret < 0)
217 return ret;
218
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100219 return ret & STPMIC1_BUCK_PREG_MODE ? STPMIC1_PREG_MODE_LP :
220 STPMIC1_PREG_MODE_HP;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200221}
222
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100223static int stpmic1_buck_set_mode(struct udevice *dev, int mode)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200224{
225 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100226 STPMIC1_BUCKX_MAIN_CR(dev->driver_data - 1),
227 STPMIC1_BUCK_PREG_MODE,
228 mode ? STPMIC1_BUCK_PREG_MODE : 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200229}
230
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100231static int stpmic1_buck_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200232{
233 struct dm_regulator_uclass_platdata *uc_pdata;
234
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100235 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_BUCK)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200236 return -EINVAL;
237
238 uc_pdata = dev_get_uclass_platdata(dev);
239
240 uc_pdata->type = REGULATOR_TYPE_BUCK;
241 uc_pdata->mode = (struct dm_regulator_mode *)buck_modes;
242 uc_pdata->mode_count = ARRAY_SIZE(buck_modes);
243
244 return 0;
245}
246
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100247static const struct dm_regulator_ops stpmic1_buck_ops = {
248 .get_value = stpmic1_buck_get_value,
249 .set_value = stpmic1_buck_set_value,
250 .get_enable = stpmic1_buck_get_enable,
251 .set_enable = stpmic1_buck_set_enable,
252 .get_mode = stpmic1_buck_get_mode,
253 .set_mode = stpmic1_buck_set_mode,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200254};
255
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100256U_BOOT_DRIVER(stpmic1_buck) = {
257 .name = "stpmic1_buck",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200258 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100259 .ops = &stpmic1_buck_ops,
260 .probe = stpmic1_buck_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200261};
262
263/*
264 * LDO regulators
265 */
266
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100267static const struct stpmic1_range ldo12_ranges[] = {
268 STPMIC1_RANGE(1700000, 0, 7, 0),
269 STPMIC1_RANGE(1700000, 8, 24, 100000),
270 STPMIC1_RANGE(3300000, 25, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200271};
272
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100273static const struct stpmic1_range ldo3_ranges[] = {
274 STPMIC1_RANGE(1700000, 0, 7, 0),
275 STPMIC1_RANGE(1700000, 8, 24, 100000),
276 STPMIC1_RANGE(3300000, 25, 30, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200277 /* Sel 31 is special case when LDO3 is in mode sync_source (BUCK2/2) */
278};
279
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100280static const struct stpmic1_range ldo5_ranges[] = {
281 STPMIC1_RANGE(1700000, 0, 7, 0),
282 STPMIC1_RANGE(1700000, 8, 30, 100000),
283 STPMIC1_RANGE(3900000, 31, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200284};
285
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100286static const struct stpmic1_range ldo6_ranges[] = {
287 STPMIC1_RANGE(900000, 0, 24, 100000),
288 STPMIC1_RANGE(3300000, 25, 31, 0),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200289};
290
291/* LDO: 1,2,3,4,5,6 - voltage ranges */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100292static const struct stpmic1_output ldo_voltage_range[] = {
293 STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
294 STPMIC1_OUTPUT(ldo12_ranges, ARRAY_SIZE(ldo12_ranges)),
295 STPMIC1_OUTPUT(ldo3_ranges, ARRAY_SIZE(ldo3_ranges)),
296 STPMIC1_OUTPUT(NULL, 0),
297 STPMIC1_OUTPUT(ldo5_ranges, ARRAY_SIZE(ldo5_ranges)),
298 STPMIC1_OUTPUT(ldo6_ranges, ARRAY_SIZE(ldo6_ranges)),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200299};
300
301/* LDO modes */
302static const struct dm_regulator_mode ldo_modes[] = {
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100303 STPMIC1_MODE(STPMIC1_LDO_MODE_NORMAL,
304 STPMIC1_LDO_MODE_NORMAL, "NORMAL"),
305 STPMIC1_MODE(STPMIC1_LDO_MODE_BYPASS,
306 STPMIC1_LDO_MODE_BYPASS, "BYPASS"),
307 STPMIC1_MODE(STPMIC1_LDO_MODE_SINK_SOURCE,
308 STPMIC1_LDO_MODE_SINK_SOURCE, "SINK SOURCE"),
Christophe Kerello069f0b62018-04-26 17:13:09 +0200309};
310
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100311static int stpmic1_ldo_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200312{
313 int sel, ldo = dev->driver_data - 1;
314
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100315 sel = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200316 if (sel < 0)
317 return sel;
318
319 /* ldo4 => 3,3V */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100320 if (ldo == STPMIC1_LDO4)
321 return STPMIC1_LDO4_UV;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200322
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100323 sel &= STPMIC1_LDO12356_VOUT_MASK;
324 sel >>= STPMIC1_LDO12356_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200325
326 /* ldo3, sel = 31 => BUCK2/2 */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100327 if (ldo == STPMIC1_LDO3 && sel == STPMIC1_LDO3_DDR_SEL)
328 return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200329
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100330 return stpmic1_output_find_uv(sel, &ldo_voltage_range[ldo]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200331}
332
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100333static int stpmic1_ldo_set_value(struct udevice *dev, int uv)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200334{
335 int sel, ldo = dev->driver_data - 1;
336
337 /* ldo4 => not possible */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100338 if (ldo == STPMIC1_LDO4)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200339 return -EINVAL;
340
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100341 sel = stpmic1_output_find_sel(uv, &ldo_voltage_range[ldo]);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200342 if (sel < 0)
343 return sel;
344
345 return pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100346 STPMIC1_LDOX_MAIN_CR(ldo),
347 STPMIC1_LDO12356_VOUT_MASK,
348 sel << STPMIC1_LDO12356_VOUT_SHIFT);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200349}
350
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100351static int stpmic1_ldo_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200352{
353 int ret;
354
355 ret = pmic_reg_read(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100356 STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200357 if (ret < 0)
358 return false;
359
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100360 return ret & STPMIC1_LDO_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200361}
362
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100363static int stpmic1_ldo_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200364{
365 struct dm_regulator_uclass_platdata *uc_pdata;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100366 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
367 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200368 int ret, uv;
369
370 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100371 if (stpmic1_ldo_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200372 return 0;
373
374 if (enable) {
375 uc_pdata = dev_get_uclass_platdata(dev);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100376 uv = stpmic1_ldo_get_value(dev);
377 if (uv < uc_pdata->min_uV || uv > uc_pdata->max_uV)
378 stpmic1_ldo_set_value(dev, uc_pdata->min_uV);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200379 }
380
381 ret = pmic_clrsetbits(dev->parent,
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100382 STPMIC1_LDOX_MAIN_CR(dev->driver_data - 1),
383 STPMIC1_LDO_ENA, enable ? STPMIC1_LDO_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200384 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200385
386 return ret;
387}
388
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100389static int stpmic1_ldo_get_mode(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200390{
391 int ret, ldo = dev->driver_data - 1;
392
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100393 if (ldo != STPMIC1_LDO3)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200394 return -EINVAL;
395
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100396 ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200397 if (ret < 0)
398 return ret;
399
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100400 if (ret & STPMIC1_LDO3_MODE)
401 return STPMIC1_LDO_MODE_BYPASS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200402
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100403 ret &= STPMIC1_LDO12356_VOUT_MASK;
404 ret >>= STPMIC1_LDO12356_VOUT_SHIFT;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200405
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100406 return ret == STPMIC1_LDO3_DDR_SEL ? STPMIC1_LDO_MODE_SINK_SOURCE :
407 STPMIC1_LDO_MODE_NORMAL;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200408}
409
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100410static int stpmic1_ldo_set_mode(struct udevice *dev, int mode)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200411{
412 int ret, ldo = dev->driver_data - 1;
413
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100414 if (ldo != STPMIC1_LDO3)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200415 return -EINVAL;
416
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100417 ret = pmic_reg_read(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo));
Christophe Kerello069f0b62018-04-26 17:13:09 +0200418 if (ret < 0)
419 return ret;
420
421 switch (mode) {
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100422 case STPMIC1_LDO_MODE_SINK_SOURCE:
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100423 ret &= ~STPMIC1_LDO12356_VOUT_MASK;
424 ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100425 case STPMIC1_LDO_MODE_NORMAL:
426 ret &= ~STPMIC1_LDO3_MODE;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200427 break;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100428 case STPMIC1_LDO_MODE_BYPASS:
429 ret |= STPMIC1_LDO3_MODE;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200430 break;
431 }
432
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100433 return pmic_reg_write(dev->parent, STPMIC1_LDOX_MAIN_CR(ldo), ret);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200434}
435
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100436static int stpmic1_ldo_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200437{
438 struct dm_regulator_uclass_platdata *uc_pdata;
439
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100440 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_LDO)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200441 return -EINVAL;
442
443 uc_pdata = dev_get_uclass_platdata(dev);
444
445 uc_pdata->type = REGULATOR_TYPE_LDO;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100446 if (dev->driver_data - 1 == STPMIC1_LDO3) {
Christophe Kerello069f0b62018-04-26 17:13:09 +0200447 uc_pdata->mode = (struct dm_regulator_mode *)ldo_modes;
448 uc_pdata->mode_count = ARRAY_SIZE(ldo_modes);
449 } else {
450 uc_pdata->mode_count = 0;
451 }
452
453 return 0;
454}
455
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100456static const struct dm_regulator_ops stpmic1_ldo_ops = {
457 .get_value = stpmic1_ldo_get_value,
458 .set_value = stpmic1_ldo_set_value,
459 .get_enable = stpmic1_ldo_get_enable,
460 .set_enable = stpmic1_ldo_set_enable,
461 .get_mode = stpmic1_ldo_get_mode,
462 .set_mode = stpmic1_ldo_set_mode,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200463};
464
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100465U_BOOT_DRIVER(stpmic1_ldo) = {
466 .name = "stpmic1_ldo",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200467 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100468 .ops = &stpmic1_ldo_ops,
469 .probe = stpmic1_ldo_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200470};
471
472/*
473 * VREF DDR regulator
474 */
475
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100476static int stpmic1_vref_ddr_get_value(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200477{
478 /* BUCK2/2 */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100479 return stpmic1_buck_get_uv(dev->parent, STPMIC1_BUCK2) / 2;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200480}
481
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100482static int stpmic1_vref_ddr_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200483{
484 int ret;
485
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100486 ret = pmic_reg_read(dev->parent, STPMIC1_REFDDR_MAIN_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200487 if (ret < 0)
488 return false;
489
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100490 return ret & STPMIC1_VREF_ENA ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200491}
492
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100493static int stpmic1_vref_ddr_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200494{
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100495 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
496 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200497 int ret;
498
499 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100500 if (stpmic1_vref_ddr_get_enable(dev) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200501 return 0;
502
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100503 ret = pmic_clrsetbits(dev->parent, STPMIC1_REFDDR_MAIN_CR,
504 STPMIC1_VREF_ENA, enable ? STPMIC1_VREF_ENA : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200505 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200506
507 return ret;
508}
509
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100510static int stpmic1_vref_ddr_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200511{
512 struct dm_regulator_uclass_platdata *uc_pdata;
513
514 uc_pdata = dev_get_uclass_platdata(dev);
515
516 uc_pdata->type = REGULATOR_TYPE_FIXED;
517 uc_pdata->mode_count = 0;
518
519 return 0;
520}
521
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100522static const struct dm_regulator_ops stpmic1_vref_ddr_ops = {
523 .get_value = stpmic1_vref_ddr_get_value,
524 .get_enable = stpmic1_vref_ddr_get_enable,
525 .set_enable = stpmic1_vref_ddr_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200526};
527
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100528U_BOOT_DRIVER(stpmic1_vref_ddr) = {
529 .name = "stpmic1_vref_ddr",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200530 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100531 .ops = &stpmic1_vref_ddr_ops,
532 .probe = stpmic1_vref_ddr_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200533};
534
535/*
536 * BOOST regulator
537 */
538
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100539static int stpmic1_boost_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200540{
541 int ret;
542
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100543 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200544 if (ret < 0)
545 return false;
546
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100547 return ret & STPMIC1_BST_ON ? true : false;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200548}
549
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100550static int stpmic1_boost_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200551{
552 int ret;
553
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100554 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200555 if (ret < 0)
556 return ret;
557
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100558 if (!enable && ret & STPMIC1_PWR_SW_ON)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200559 return -EINVAL;
560
561 /* if regulator is already in the wanted state, nothing to do */
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100562 if (!!(ret & STPMIC1_BST_ON) == enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200563 return 0;
564
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100565 ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
566 STPMIC1_BST_ON,
567 enable ? STPMIC1_BST_ON : 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200568 if (enable)
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100569 mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200570
571 return ret;
572}
573
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100574static int stpmic1_boost_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200575{
576 struct dm_regulator_uclass_platdata *uc_pdata;
577
578 uc_pdata = dev_get_uclass_platdata(dev);
579
580 uc_pdata->type = REGULATOR_TYPE_FIXED;
581 uc_pdata->mode_count = 0;
582
583 return 0;
584}
585
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100586static const struct dm_regulator_ops stpmic1_boost_ops = {
587 .get_enable = stpmic1_boost_get_enable,
588 .set_enable = stpmic1_boost_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200589};
590
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100591U_BOOT_DRIVER(stpmic1_boost) = {
592 .name = "stpmic1_boost",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200593 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100594 .ops = &stpmic1_boost_ops,
595 .probe = stpmic1_boost_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200596};
597
598/*
599 * USB power switch
600 */
601
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100602static int stpmic1_pwr_sw_get_enable(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200603{
604 uint mask = 1 << dev->driver_data;
605 int ret;
606
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100607 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200608 if (ret < 0)
609 return false;
610
611 return ret & mask ? true : false;
612}
613
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100614static int stpmic1_pwr_sw_set_enable(struct udevice *dev, bool enable)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200615{
616 uint mask = 1 << dev->driver_data;
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100617 int delay = enable ? STPMIC1_DEFAULT_START_UP_DELAY_MS :
618 STPMIC1_DEFAULT_STOP_DELAY_MS;
Christophe Kerello069f0b62018-04-26 17:13:09 +0200619 int ret;
620
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100621 ret = pmic_reg_read(dev->parent, STPMIC1_BST_SW_CR);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200622 if (ret < 0)
623 return ret;
624
625 /* if regulator is already in the wanted state, nothing to do */
626 if (!!(ret & mask) == enable)
627 return 0;
628
629 /* Boost management */
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100630 if (enable && !(ret & STPMIC1_BST_ON)) {
631 pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
632 STPMIC1_BST_ON, STPMIC1_BST_ON);
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100633 mdelay(STPMIC1_USB_BOOST_START_UP_DELAY_MS);
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100634 } else if (!enable && ret & STPMIC1_BST_ON &&
635 (ret & STPMIC1_PWR_SW_ON) != STPMIC1_PWR_SW_ON) {
636 pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
637 STPMIC1_BST_ON, 0);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200638 }
639
Patrick Delaunaydb4ff0d2019-02-04 11:26:18 +0100640 ret = pmic_clrsetbits(dev->parent, STPMIC1_BST_SW_CR,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200641 mask, enable ? mask : 0);
Christophe Kerello844f9bf2018-06-27 11:59:47 +0200642 mdelay(delay);
Christophe Kerello069f0b62018-04-26 17:13:09 +0200643
644 return ret;
645}
646
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100647static int stpmic1_pwr_sw_probe(struct udevice *dev)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200648{
649 struct dm_regulator_uclass_platdata *uc_pdata;
650
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100651 if (!dev->driver_data || dev->driver_data > STPMIC1_MAX_PWR_SW)
Christophe Kerello069f0b62018-04-26 17:13:09 +0200652 return -EINVAL;
653
654 uc_pdata = dev_get_uclass_platdata(dev);
655
656 uc_pdata->type = REGULATOR_TYPE_FIXED;
657 uc_pdata->mode_count = 0;
658
659 return 0;
660}
661
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100662static const struct dm_regulator_ops stpmic1_pwr_sw_ops = {
663 .get_enable = stpmic1_pwr_sw_get_enable,
664 .set_enable = stpmic1_pwr_sw_set_enable,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200665};
666
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100667U_BOOT_DRIVER(stpmic1_pwr_sw) = {
668 .name = "stpmic1_pwr_sw",
Christophe Kerello069f0b62018-04-26 17:13:09 +0200669 .id = UCLASS_REGULATOR,
Patrick Delaunay42f01aa2019-02-04 11:26:17 +0100670 .ops = &stpmic1_pwr_sw_ops,
671 .probe = stpmic1_pwr_sw_probe,
Christophe Kerello069f0b62018-04-26 17:13:09 +0200672};