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