blob: 78909f701894fbcd6c47808ef63e9f6604a29aff [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Keerthyffed0ea2016-09-30 09:20:44 +05302/*
3 * (C) Copyright 2016
4 * Texas Instruments Incorporated, <www.ti.com>
5 *
6 * Keerthy <j-keerthy@ti.com>
Keerthyffed0ea2016-09-30 09:20:44 +05307 */
8
9#include <common.h>
10#include <fdtdec.h>
11#include <errno.h>
12#include <dm.h>
13#include <i2c.h>
14#include <power/pmic.h>
15#include <power/regulator.h>
16#include <power/palmas.h>
17
Keerthyffed0ea2016-09-30 09:20:44 +053018#define REGULATOR_ON 0x1
19#define REGULATOR_OFF 0x0
20
21#define SMPS_MODE_MASK 0x3
22#define SMPS_MODE_SHIFT 0x0
23#define LDO_MODE_MASK 0x1
24#define LDO_MODE_SHIFT 0x0
25
26static const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
27 {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
28 {0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
29 {0x20, 0x24, 0x2c, 0x30, 0x38},
30};
31
32static const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
33 {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
34 {0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
35 {0x23, 0x27, 0x2f, 0x33, 0x3B}
36};
37
38static const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
39 {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
40 {0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
41 {0x50, 0x52, 0x54, 0x5e, 0x62}
42};
43
44static const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
45 {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
46 {0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
47 {0x51, 0x53, 0x55, 0x5f, 0x63}
48};
49
50static int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
51{
52 int ret;
53 unsigned int adr;
54 struct dm_regulator_uclass_platdata *uc_pdata;
55
56 uc_pdata = dev_get_uclass_platdata(dev);
57 adr = uc_pdata->ctrl_reg;
58
59 ret = pmic_reg_read(dev->parent, adr);
60 if (ret < 0)
61 return ret;
62
63 if (op == PMIC_OP_GET) {
64 ret &= PALMAS_SMPS_STATUS_MASK;
65
66 if (ret)
67 *enable = true;
68 else
69 *enable = false;
70
71 return 0;
72 } else if (op == PMIC_OP_SET) {
73 if (*enable)
74 ret |= PALMAS_SMPS_MODE_MASK;
75 else
76 ret &= ~(PALMAS_SMPS_MODE_MASK);
77
78 ret = pmic_reg_write(dev->parent, adr, ret);
79 if (ret)
80 return ret;
81 }
82
83 return 0;
84}
85
86static int palmas_smps_volt2hex(int uV)
87{
88 if (uV > PALMAS_LDO_VOLT_MAX)
89 return -EINVAL;
90
91 if (uV > 1650000)
92 return (uV - 1000000) / 20000 + 0x6;
93
94 if (uV == 500000)
95 return 0x6;
96 else
97 return 0x6 + ((uV - 500000) / 10000);
98}
99
100static int palmas_smps_hex2volt(int hex, bool range)
101{
102 unsigned int uV = 0;
103
104 if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
105 return -EINVAL;
106
107 if (hex < 0x7)
108 uV = 500000;
109 else
110 uV = 500000 + (hex - 0x6) * 10000;
111
112 if (range)
113 uV *= 2;
114
115 return uV;
116}
117
118static int palmas_smps_val(struct udevice *dev, int op, int *uV)
119{
120 unsigned int hex, adr;
121 int ret;
122 bool range;
123 struct dm_regulator_uclass_platdata *uc_pdata;
124
125 uc_pdata = dev_get_uclass_platdata(dev);
126
127 if (op == PMIC_OP_GET)
128 *uV = 0;
129
130 adr = uc_pdata->volt_reg;
131
132 ret = pmic_reg_read(dev->parent, adr);
133 if (ret < 0)
134 return ret;
135
136 if (op == PMIC_OP_GET) {
137 if (ret & PALMAS_SMPS_RANGE_MASK)
138 range = true;
139 else
140 range = false;
141
142 ret &= PALMAS_SMPS_VOLT_MASK;
143 ret = palmas_smps_hex2volt(ret, range);
144 if (ret < 0)
145 return ret;
146 *uV = ret;
147
148 return 0;
149 }
150
151 hex = palmas_smps_volt2hex(*uV);
152 if (hex < 0)
153 return hex;
154
155 ret &= ~PALMAS_SMPS_VOLT_MASK;
156 ret |= hex;
157 if (*uV > 1650000)
158 ret |= PALMAS_SMPS_RANGE_MASK;
159
160 return pmic_reg_write(dev->parent, adr, ret);
161}
162
Jean-Jacques Hiblot91827412017-07-12 11:42:47 +0200163static int palmas_ldo_bypass_enable(struct udevice *dev, bool enabled)
164{
165 int type = dev_get_driver_data(dev_get_parent(dev));
166 struct dm_regulator_uclass_platdata *p;
167 unsigned int adr;
168 int reg;
169
170 if (type == TPS65917) {
171 /* bypass available only on LDO1 and LDO2 */
172 if (dev->driver_data > 2)
173 return -ENOTSUPP;
174 } else if (type == TPS659038) {
175 /* bypass available only on LDO9 */
176 if (dev->driver_data != 9)
177 return -ENOTSUPP;
178 }
179
180 p = dev_get_uclass_platdata(dev);
181 adr = p->ctrl_reg;
182
183 reg = pmic_reg_read(dev->parent, adr);
184 if (reg < 0)
185 return reg;
186
187 if (enabled)
188 reg |= PALMAS_LDO_BYPASS_EN;
189 else
190 reg &= ~PALMAS_LDO_BYPASS_EN;
191
192 return pmic_reg_write(dev->parent, adr, reg);
193}
194
Keerthyffed0ea2016-09-30 09:20:44 +0530195static int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
196{
197 int ret;
198 unsigned int adr;
199 struct dm_regulator_uclass_platdata *uc_pdata;
200
201 uc_pdata = dev_get_uclass_platdata(dev);
202 adr = uc_pdata->ctrl_reg;
203
204 ret = pmic_reg_read(dev->parent, adr);
205 if (ret < 0)
206 return ret;
207
208 if (op == PMIC_OP_GET) {
209 ret &= PALMAS_LDO_STATUS_MASK;
210
211 if (ret)
212 *enable = true;
213 else
214 *enable = false;
215
216 return 0;
217 } else if (op == PMIC_OP_SET) {
218 if (*enable)
219 ret |= PALMAS_LDO_MODE_MASK;
220 else
221 ret &= ~(PALMAS_LDO_MODE_MASK);
222
223 ret = pmic_reg_write(dev->parent, adr, ret);
224 if (ret)
225 return ret;
Jean-Jacques Hiblot91827412017-07-12 11:42:47 +0200226
227 ret = palmas_ldo_bypass_enable(dev, false);
228 if (ret && (ret != -ENOTSUPP))
229 return ret;
Keerthyffed0ea2016-09-30 09:20:44 +0530230 }
231
232 return 0;
233}
234
235static int palmas_ldo_volt2hex(int uV)
236{
237 if (uV > PALMAS_LDO_VOLT_MAX)
238 return -EINVAL;
239
240 return (uV - 850000) / 50000;
241}
242
243static int palmas_ldo_hex2volt(int hex)
244{
245 if (hex > PALMAS_LDO_VOLT_MAX_HEX)
246 return -EINVAL;
247
248 if (!hex)
249 return 0;
250
251 return (hex * 50000) + 850000;
252}
253
254static int palmas_ldo_val(struct udevice *dev, int op, int *uV)
255{
256 unsigned int hex, adr;
257 int ret;
258
259 struct dm_regulator_uclass_platdata *uc_pdata;
260
261 if (op == PMIC_OP_GET)
262 *uV = 0;
263
264 uc_pdata = dev_get_uclass_platdata(dev);
265
266 adr = uc_pdata->volt_reg;
267
268 ret = pmic_reg_read(dev->parent, adr);
269 if (ret < 0)
270 return ret;
271
272 if (op == PMIC_OP_GET) {
273 ret &= PALMAS_LDO_VOLT_MASK;
274 ret = palmas_ldo_hex2volt(ret);
275 if (ret < 0)
276 return ret;
277 *uV = ret;
278 return 0;
279 }
280
281 hex = palmas_ldo_volt2hex(*uV);
282 if (hex < 0)
283 return hex;
284
285 ret &= ~PALMAS_LDO_VOLT_MASK;
286 ret |= hex;
287 if (*uV > 1650000)
288 ret |= 0x80;
289
290 return pmic_reg_write(dev->parent, adr, ret);
291}
292
293static int palmas_ldo_probe(struct udevice *dev)
294{
295 struct dm_regulator_uclass_platdata *uc_pdata;
296 struct udevice *parent;
297
298 uc_pdata = dev_get_uclass_platdata(dev);
299
300 parent = dev_get_parent(dev);
301 int type = dev_get_driver_data(parent);
302
303 uc_pdata->type = REGULATOR_TYPE_LDO;
304
305 if (dev->driver_data) {
306 u8 idx = dev->driver_data - 1;
307 uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
308 uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
309 } else {
310 /* check for ldoln and ldousb cases */
311 if (!strcmp("ldoln", dev->name)) {
312 uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
313 uc_pdata->volt_reg = palmas_ldo_volt[type][9];
314 } else if (!strcmp("ldousb", dev->name)) {
315 uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
316 uc_pdata->volt_reg = palmas_ldo_volt[type][10];
317 }
318 }
319
320 return 0;
321}
322
323static int ldo_get_value(struct udevice *dev)
324{
325 int uV;
326 int ret;
327
328 ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
329 if (ret)
330 return ret;
331
332 return uV;
333}
334
335static int ldo_set_value(struct udevice *dev, int uV)
336{
337 return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
338}
339
Keerthye8de8912017-06-13 09:53:49 +0530340static int ldo_get_enable(struct udevice *dev)
Keerthyffed0ea2016-09-30 09:20:44 +0530341{
342 bool enable = false;
343 int ret;
344
345 ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
346 if (ret)
347 return ret;
348
349 return enable;
350}
351
352static int ldo_set_enable(struct udevice *dev, bool enable)
353{
354 return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
355}
356
357static int palmas_smps_probe(struct udevice *dev)
358{
359 struct dm_regulator_uclass_platdata *uc_pdata;
360 struct udevice *parent;
361 int idx;
362
363 uc_pdata = dev_get_uclass_platdata(dev);
364
365 parent = dev_get_parent(dev);
366 int type = dev_get_driver_data(parent);
367
368 uc_pdata->type = REGULATOR_TYPE_BUCK;
369
370 switch (type) {
371 case PALMAS:
372 case TPS659038:
373 switch (dev->driver_data) {
374 case 123:
375 case 12:
376 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
377 uc_pdata->volt_reg = palmas_smps_volt[type][0];
378 break;
379 case 3:
380 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
381 uc_pdata->volt_reg = palmas_smps_volt[type][1];
382 break;
383 case 45:
384 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
385 uc_pdata->volt_reg = palmas_smps_volt[type][2];
386 break;
387 case 6:
388 case 7:
389 case 8:
390 case 9:
391 case 10:
Keerthyc89f7ce2017-02-03 17:04:08 +0530392 idx = dev->driver_data - 3;
Keerthyffed0ea2016-09-30 09:20:44 +0530393 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
394 uc_pdata->volt_reg = palmas_smps_volt[type][idx];
395 break;
396
397 default:
398 printf("Wrong ID for regulator\n");
399 }
400 break;
401
402 case TPS65917:
403 switch (dev->driver_data) {
404 case 1:
405 case 2:
406 case 3:
407 case 4:
408 case 5:
409 idx = dev->driver_data - 1;
410 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
411 uc_pdata->volt_reg = palmas_smps_volt[type][idx];
412 break;
Keerthy879cbd02017-06-02 10:51:51 +0530413 case 12:
414 idx = 0;
415 uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
416 uc_pdata->volt_reg = palmas_smps_volt[type][idx];
417 break;
Keerthyffed0ea2016-09-30 09:20:44 +0530418 default:
419 printf("Wrong ID for regulator\n");
420 }
421 break;
422
423 default:
424 printf("Invalid PMIC ID\n");
425 }
426
427 return 0;
428}
429
430static int smps_get_value(struct udevice *dev)
431{
432 int uV;
433 int ret;
434
435 ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
436 if (ret)
437 return ret;
438
439 return uV;
440}
441
442static int smps_set_value(struct udevice *dev, int uV)
443{
444 return palmas_smps_val(dev, PMIC_OP_SET, &uV);
445}
446
Keerthye8de8912017-06-13 09:53:49 +0530447static int smps_get_enable(struct udevice *dev)
Keerthyffed0ea2016-09-30 09:20:44 +0530448{
449 bool enable = false;
450 int ret;
451
452 ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
453 if (ret)
454 return ret;
455
456 return enable;
457}
458
459static int smps_set_enable(struct udevice *dev, bool enable)
460{
461 return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
462}
463
464static const struct dm_regulator_ops palmas_ldo_ops = {
465 .get_value = ldo_get_value,
466 .set_value = ldo_set_value,
467 .get_enable = ldo_get_enable,
468 .set_enable = ldo_set_enable,
469};
470
471U_BOOT_DRIVER(palmas_ldo) = {
472 .name = PALMAS_LDO_DRIVER,
473 .id = UCLASS_REGULATOR,
474 .ops = &palmas_ldo_ops,
475 .probe = palmas_ldo_probe,
476};
477
478static const struct dm_regulator_ops palmas_smps_ops = {
479 .get_value = smps_get_value,
480 .set_value = smps_set_value,
481 .get_enable = smps_get_enable,
482 .set_enable = smps_set_enable,
483};
484
485U_BOOT_DRIVER(palmas_smps) = {
486 .name = PALMAS_SMPS_DRIVER,
487 .id = UCLASS_REGULATOR,
488 .ops = &palmas_smps_ops,
489 .probe = palmas_smps_probe,
490};