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