1204431Sraj// SPDX-License-Identifier: GPL-2.0+
2204431Sraj/*
3204431Sraj * (C) Copyright 2016
4204431Sraj * Texas Instruments Incorporated, <www.ti.com>
5204431Sraj *
6204431Sraj * Keerthy <j-keerthy@ti.com>
7204431Sraj */
8204431Sraj
9204431Sraj#include <common.h>
10204431Sraj#include <fdtdec.h>
11204431Sraj#include <errno.h>
12204431Sraj#include <dm.h>
13204431Sraj#include <power/pmic.h>
14204431Sraj#include <power/regulator.h>
15204431Sraj#include <power/palmas.h>
16204431Sraj
17204431Sraj#define	REGULATOR_ON		0x1
18204431Sraj#define	REGULATOR_OFF		0x0
19204431Sraj
20204431Sraj#define	SMPS_MODE_MASK		0x3
21204431Sraj#define	SMPS_MODE_SHIFT		0x0
22204431Sraj#define	LDO_MODE_MASK		0x1
23204431Sraj#define	LDO_MODE_SHIFT		0x0
24204431Sraj
25204431Srajstatic const char palmas_smps_ctrl[][PALMAS_SMPS_NUM] = {
26204431Sraj	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38, 0x3c},
27204431Sraj	{0x20, 0x24, 0x28, 0x2c, 0x30, 0x34, 0x38},
28204431Sraj	{0x20, 0x24, 0x2c, 0x30, 0x38},
29204431Sraj};
30204431Sraj
31204431Srajstatic const char palmas_smps_volt[][PALMAS_SMPS_NUM] = {
32204431Sraj	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b, 0x3c},
33204431Sraj	{0x23, 0x27, 0x2b, 0x2f, 0x33, 0x37, 0x3b},
34204431Sraj	{0x23, 0x27, 0x2f, 0x33, 0x3B}
35204431Sraj};
36204431Sraj
37204431Srajstatic const char palmas_ldo_ctrl[][PALMAS_LDO_NUM] = {
38204431Sraj	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
39204431Sraj	{0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64},
40204431Sraj	{0x50, 0x52, 0x54, 0x5e, 0x62}
41204431Sraj};
42204431Sraj
43204431Srajstatic const char palmas_ldo_volt[][PALMAS_LDO_NUM] = {
44204431Sraj	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
45204431Sraj	{0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x5f, 0x61, 0x63, 0x65},
46204431Sraj	{0x51, 0x53, 0x55, 0x5f, 0x63}
47204431Sraj};
48204431Sraj
49204431Srajstatic int palmas_smps_enable(struct udevice *dev, int op, bool *enable)
50204431Sraj{
51204431Sraj	int ret;
52204431Sraj	unsigned int adr;
53204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
54204431Sraj
55238742Simp	uc_pdata = dev_get_uclass_plat(dev);
56238742Simp	adr = uc_pdata->ctrl_reg;
57238742Simp
58204431Sraj	ret = pmic_reg_read(dev->parent, adr);
59204431Sraj		if (ret < 0)
60204431Sraj			return ret;
61204431Sraj
62204431Sraj	if (op == PMIC_OP_GET) {
63204431Sraj		ret &= PALMAS_SMPS_STATUS_MASK;
64204431Sraj
65204431Sraj		if (ret)
66204431Sraj			*enable = true;
67204431Sraj		else
68204431Sraj			*enable = false;
69204431Sraj
70204431Sraj		return 0;
71204431Sraj	} else if (op == PMIC_OP_SET) {
72204431Sraj		if (*enable)
73204431Sraj			ret |= PALMAS_SMPS_MODE_MASK;
74204431Sraj		else
75204431Sraj			ret &= ~(PALMAS_SMPS_MODE_MASK);
76204431Sraj
77204431Sraj		ret = pmic_reg_write(dev->parent, adr, ret);
78204431Sraj		if (ret)
79204431Sraj			return ret;
80204431Sraj	}
81204431Sraj
82204431Sraj	return 0;
83204431Sraj}
84204431Sraj
85204431Srajstatic int palmas_smps_volt2hex(int uV)
86204431Sraj{
87204431Sraj	if (uV > PALMAS_LDO_VOLT_MAX)
88204431Sraj		return -EINVAL;
89204431Sraj
90204431Sraj	if (uV > 1650000)
91204431Sraj		return (uV - 1000000) / 20000 + 0x6;
92238742Simp
93204431Sraj	if (uV == 500000)
94204431Sraj		return 0x6;
95204431Sraj	else
96204431Sraj		return 0x6 + ((uV - 500000) / 10000);
97238742Simp}
98204431Sraj
99204431Srajstatic int palmas_smps_hex2volt(int hex, bool range)
100204431Sraj{
101204431Sraj	unsigned int uV = 0;
102238742Simp
103204431Sraj	if (hex > PALMAS_SMPS_VOLT_MAX_HEX)
104204431Sraj		return -EINVAL;
105204431Sraj
106204431Sraj	if (hex < 0x7)
107204431Sraj		uV = 500000;
108204431Sraj	else
109204431Sraj		uV = 500000 + (hex - 0x6) * 10000;
110204431Sraj
111204431Sraj	if (range)
112204431Sraj		uV *= 2;
113204431Sraj
114204431Sraj	return uV;
115204431Sraj}
116204431Sraj
117204431Srajstatic int palmas_smps_val(struct udevice *dev, int op, int *uV)
118204431Sraj{
119204431Sraj	unsigned int hex, adr;
120204431Sraj	int ret;
121204431Sraj	bool range;
122204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
123204431Sraj
124204431Sraj	uc_pdata = dev_get_uclass_plat(dev);
125204431Sraj
126204431Sraj	if (op == PMIC_OP_GET)
127204431Sraj		*uV = 0;
128204431Sraj
129204431Sraj	adr = uc_pdata->volt_reg;
130204433Sraj
131204433Sraj	ret = pmic_reg_read(dev->parent, adr);
132204433Sraj	if (ret < 0)
133204433Sraj		return ret;
134204433Sraj
135204433Sraj	if (op == PMIC_OP_GET) {
136204433Sraj		if (ret & PALMAS_SMPS_RANGE_MASK)
137204433Sraj			range =  true;
138204431Sraj		else
139204431Sraj			range = false;
140204431Sraj
141204431Sraj		ret &= PALMAS_SMPS_VOLT_MASK;
142204433Sraj		ret = palmas_smps_hex2volt(ret, range);
143204433Sraj		if (ret < 0)
144204433Sraj			return ret;
145204431Sraj		*uV = ret;
146204431Sraj
147204431Sraj		return 0;
148204431Sraj	}
149204431Sraj
150204431Sraj	hex = palmas_smps_volt2hex(*uV);
151204431Sraj	if (hex < 0)
152204431Sraj		return hex;
153204431Sraj
154204431Sraj	ret &= ~PALMAS_SMPS_VOLT_MASK;
155204431Sraj	ret |= hex;
156204431Sraj	if (*uV > 1650000)
157204431Sraj		ret |= PALMAS_SMPS_RANGE_MASK;
158204431Sraj
159204431Sraj	return pmic_reg_write(dev->parent, adr, ret);
160204431Sraj}
161204431Sraj
162204431Srajstatic int palmas_ldo_bypass_enable(struct udevice *dev, bool enabled)
163204431Sraj{
164204431Sraj	int type = dev_get_driver_data(dev_get_parent(dev));
165204431Sraj	struct dm_regulator_uclass_plat *p;
166204431Sraj	unsigned int adr;
167204431Sraj	int reg;
168204431Sraj
169204433Sraj	if (type == TPS65917) {
170204431Sraj		/* bypass available only on LDO1 and LDO2 */
171204431Sraj		if (dev->driver_data > 2)
172204431Sraj			return -ENOTSUPP;
173204431Sraj	} else if (type == TPS659038) {
174204431Sraj		/* bypass available only on LDO9 */
175204431Sraj		if (dev->driver_data != 9)
176204431Sraj			return -ENOTSUPP;
177204431Sraj	}
178204431Sraj
179204431Sraj	p = dev_get_uclass_plat(dev);
180204431Sraj	adr = p->ctrl_reg;
181204431Sraj
182204433Sraj	reg = pmic_reg_read(dev->parent, adr);
183204431Sraj	if (reg < 0)
184204431Sraj		return reg;
185204431Sraj
186204431Sraj	if (enabled)
187204431Sraj		reg |= PALMAS_LDO_BYPASS_EN;
188204431Sraj	else
189204431Sraj		reg &= ~PALMAS_LDO_BYPASS_EN;
190204431Sraj
191204431Sraj	return pmic_reg_write(dev->parent, adr, reg);
192204431Sraj}
193204431Sraj
194238742Simpstatic int palmas_ldo_enable(struct udevice *dev, int op, bool *enable)
195204431Sraj{
196204431Sraj	int ret;
197238742Simp	unsigned int adr;
198204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
199238742Simp
200238742Simp	uc_pdata = dev_get_uclass_plat(dev);
201238742Simp	adr = uc_pdata->ctrl_reg;
202204431Sraj
203204433Sraj	ret = pmic_reg_read(dev->parent, adr);
204204433Sraj		if (ret < 0)
205204431Sraj			return ret;
206204431Sraj
207238742Simp	if (op == PMIC_OP_GET) {
208204431Sraj		ret &= PALMAS_LDO_STATUS_MASK;
209204431Sraj
210238742Simp		if (ret)
211204431Sraj			*enable = true;
212204433Sraj		else
213204433Sraj			*enable = false;
214238742Simp
215238742Simp		return 0;
216238742Simp	} else if (op == PMIC_OP_SET) {
217204431Sraj		if (*enable)
218204431Sraj			ret |= PALMAS_LDO_MODE_MASK;
219204431Sraj		else
220238742Simp			ret &= ~(PALMAS_LDO_MODE_MASK);
221204431Sraj
222204431Sraj		ret = pmic_reg_write(dev->parent, adr, ret);
223238742Simp		if (ret)
224204431Sraj			return ret;
225238742Simp
226238742Simp		ret = palmas_ldo_bypass_enable(dev, false);
227238742Simp		if (ret && (ret != -ENOTSUPP))
228204431Sraj			return ret;
229204433Sraj	}
230204433Sraj
231204431Sraj	return 0;
232204431Sraj}
233204431Sraj
234204431Srajstatic int palmas_ldo_volt2hex(int uV)
235204431Sraj{
236204431Sraj	if (uV > PALMAS_LDO_VOLT_MAX)
237204431Sraj		return -EINVAL;
238204431Sraj
239204431Sraj	return (uV - 850000) / 50000;
240204431Sraj}
241204431Sraj
242204431Srajstatic int palmas_ldo_hex2volt(int hex)
243204431Sraj{
244204431Sraj	if (hex > PALMAS_LDO_VOLT_MAX_HEX)
245204431Sraj		return -EINVAL;
246204431Sraj
247204431Sraj	if (!hex)
248204431Sraj		return 0;
249204431Sraj
250204431Sraj	return (hex * 50000) + 850000;
251204431Sraj}
252204431Sraj
253204431Srajstatic int palmas_ldo_val(struct udevice *dev, int op, int *uV)
254204431Sraj{
255204431Sraj	unsigned int hex, adr;
256204431Sraj	int ret;
257204431Sraj
258204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
259204431Sraj
260204431Sraj	if (op == PMIC_OP_GET)
261204431Sraj		*uV = 0;
262204431Sraj
263204431Sraj	uc_pdata = dev_get_uclass_plat(dev);
264261215Simp
265204431Sraj	adr = uc_pdata->volt_reg;
266261215Simp
267261215Simp	ret = pmic_reg_read(dev->parent, adr);
268261215Simp	if (ret < 0)
269238742Simp		return ret;
270204431Sraj
271204431Sraj	if (op == PMIC_OP_GET) {
272204431Sraj		ret &= PALMAS_LDO_VOLT_MASK;
273204431Sraj		ret = palmas_ldo_hex2volt(ret);
274204431Sraj		if (ret < 0)
275204431Sraj			return ret;
276204431Sraj		*uV = ret;
277204431Sraj		return 0;
278204431Sraj	}
279204431Sraj
280204431Sraj	hex = palmas_ldo_volt2hex(*uV);
281204431Sraj	if (hex < 0)
282261215Simp		return hex;
283204431Sraj
284204431Sraj	ret &= ~PALMAS_LDO_VOLT_MASK;
285204431Sraj	ret |= hex;
286238742Simp	if (*uV > 1650000)
287204431Sraj		ret |= 0x80;
288204431Sraj
289204431Sraj	return pmic_reg_write(dev->parent, adr, ret);
290204431Sraj}
291204431Sraj
292204431Srajstatic int palmas_ldo_probe(struct udevice *dev)
293204431Sraj{
294204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
295204431Sraj	struct udevice *parent;
296204431Sraj
297204431Sraj	uc_pdata = dev_get_uclass_plat(dev);
298204431Sraj
299204431Sraj	parent = dev_get_parent(dev);
300204431Sraj	int type = dev_get_driver_data(parent);
301204431Sraj
302204431Sraj	uc_pdata->type = REGULATOR_TYPE_LDO;
303204431Sraj
304204431Sraj	/* check for ldoln and ldousb cases */
305204431Sraj	if (!strcmp("ldoln", dev->name)) {
306204431Sraj		uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][9];
307204431Sraj		uc_pdata->volt_reg = palmas_ldo_volt[type][9];
308204431Sraj		return 0;
309204431Sraj	}
310204431Sraj
311204431Sraj	if (!strcmp("ldousb", dev->name)) {
312204431Sraj		uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][10];
313238742Simp		uc_pdata->volt_reg = palmas_ldo_volt[type][10];
314204431Sraj		return 0;
315204431Sraj	}
316204431Sraj
317204431Sraj	if (dev->driver_data > 0) {
318204431Sraj		u8 idx = dev->driver_data - 1;
319204431Sraj		uc_pdata->ctrl_reg = palmas_ldo_ctrl[type][idx];
320204431Sraj		uc_pdata->volt_reg = palmas_ldo_volt[type][idx];
321204431Sraj	}
322204431Sraj
323204431Sraj	return 0;
324204431Sraj}
325204431Sraj
326204431Srajstatic int ldo_get_value(struct udevice *dev)
327204431Sraj{
328204431Sraj	int uV;
329204431Sraj	int ret;
330204431Sraj
331204431Sraj	ret = palmas_ldo_val(dev, PMIC_OP_GET, &uV);
332204431Sraj	if (ret)
333204431Sraj		return ret;
334204431Sraj
335204431Sraj	return uV;
336204431Sraj}
337204431Sraj
338204431Srajstatic int ldo_set_value(struct udevice *dev, int uV)
339204431Sraj{
340204431Sraj	return palmas_ldo_val(dev, PMIC_OP_SET, &uV);
341204431Sraj}
342204431Sraj
343204431Srajstatic int ldo_get_enable(struct udevice *dev)
344204431Sraj{
345204431Sraj	bool enable = false;
346204431Sraj	int ret;
347204431Sraj
348204431Sraj	ret = palmas_ldo_enable(dev, PMIC_OP_GET, &enable);
349204431Sraj	if (ret)
350204431Sraj		return ret;
351204431Sraj
352204431Sraj	return enable;
353204431Sraj}
354204431Sraj
355204431Srajstatic int ldo_set_enable(struct udevice *dev, bool enable)
356204431Sraj{
357204431Sraj	return palmas_ldo_enable(dev, PMIC_OP_SET, &enable);
358204431Sraj}
359204431Sraj
360204431Srajstatic int palmas_smps_probe(struct udevice *dev)
361204431Sraj{
362204431Sraj	struct dm_regulator_uclass_plat *uc_pdata;
363204431Sraj	struct udevice *parent;
364204431Sraj	int idx;
365204431Sraj
366204431Sraj	uc_pdata = dev_get_uclass_plat(dev);
367204431Sraj
368204431Sraj	parent = dev_get_parent(dev);
369204431Sraj	int type = dev_get_driver_data(parent);
370204431Sraj
371204431Sraj	uc_pdata->type = REGULATOR_TYPE_BUCK;
372204431Sraj
373204431Sraj	switch (type) {
374204431Sraj	case PALMAS:
375204431Sraj	case TPS659038:
376204431Sraj		switch (dev->driver_data) {
377204431Sraj		case 123:
378204431Sraj		case 12:
379204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][0];
380204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][0];
381204431Sraj			break;
382204431Sraj		case 3:
383204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][1];
384204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][1];
385204431Sraj			break;
386204431Sraj		case 45:
387204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][2];
388204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][2];
389204431Sraj			break;
390204431Sraj		case 6:
391204431Sraj		case 7:
392204431Sraj		case 8:
393204431Sraj		case 9:
394204431Sraj		case 10:
395204431Sraj			idx = dev->driver_data - 3;
396204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
397204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
398204431Sraj			break;
399204431Sraj
400204431Sraj		default:
401204431Sraj			printf("Wrong ID for regulator\n");
402204431Sraj		}
403204431Sraj		break;
404204431Sraj
405204431Sraj	case TPS65917:
406204431Sraj		switch (dev->driver_data) {
407204431Sraj		case 1:
408204431Sraj		case 2:
409204431Sraj		case 3:
410204431Sraj		case 4:
411204431Sraj		case 5:
412204431Sraj			idx = dev->driver_data - 1;
413204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
414204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
415204431Sraj			break;
416204431Sraj		case 12:
417204431Sraj			idx = 0;
418204431Sraj			uc_pdata->ctrl_reg = palmas_smps_ctrl[type][idx];
419204431Sraj			uc_pdata->volt_reg = palmas_smps_volt[type][idx];
420204431Sraj			break;
421204431Sraj		default:
422204431Sraj			printf("Wrong ID for regulator\n");
423204431Sraj		}
424204431Sraj		break;
425204431Sraj
426204431Sraj	default:
427204431Sraj			printf("Invalid PMIC ID\n");
428204431Sraj	}
429204431Sraj
430204431Sraj	return 0;
431204431Sraj}
432204431Sraj
433204431Srajstatic int smps_get_value(struct udevice *dev)
434204433Sraj{
435204433Sraj	int uV;
436204433Sraj	int ret;
437204433Sraj
438204433Sraj	ret = palmas_smps_val(dev, PMIC_OP_GET, &uV);
439204433Sraj	if (ret)
440204433Sraj		return ret;
441204431Sraj
442204431Sraj	return uV;
443204431Sraj}
444204431Sraj
445204431Srajstatic int smps_set_value(struct udevice *dev, int uV)
446204431Sraj{
447204431Sraj	return palmas_smps_val(dev, PMIC_OP_SET, &uV);
448204431Sraj}
449204431Sraj
450204431Srajstatic int smps_get_enable(struct udevice *dev)
451204431Sraj{
452204431Sraj	bool enable = false;
453204431Sraj	int ret;
454204431Sraj
455204431Sraj	ret = palmas_smps_enable(dev, PMIC_OP_GET, &enable);
456204431Sraj	if (ret)
457204431Sraj		return ret;
458204431Sraj
459204431Sraj	return enable;
460204431Sraj}
461204431Sraj
462204431Srajstatic int smps_set_enable(struct udevice *dev, bool enable)
463204431Sraj{
464204431Sraj	return palmas_smps_enable(dev, PMIC_OP_SET, &enable);
465204431Sraj}
466204431Sraj
467204431Srajstatic const struct dm_regulator_ops palmas_ldo_ops = {
468204431Sraj	.get_value  = ldo_get_value,
469204431Sraj	.set_value  = ldo_set_value,
470204431Sraj	.get_enable = ldo_get_enable,
471204431Sraj	.set_enable = ldo_set_enable,
472204431Sraj};
473204431Sraj
474204431SrajU_BOOT_DRIVER(palmas_ldo) = {
475204431Sraj	.name = PALMAS_LDO_DRIVER,
476204431Sraj	.id = UCLASS_REGULATOR,
477204431Sraj	.ops = &palmas_ldo_ops,
478204431Sraj	.probe = palmas_ldo_probe,
479204431Sraj};
480204431Sraj
481204431Srajstatic const struct dm_regulator_ops palmas_smps_ops = {
482204433Sraj	.get_value  = smps_get_value,
483204433Sraj	.set_value  = smps_set_value,
484204433Sraj	.get_enable = smps_get_enable,
485204433Sraj	.set_enable = smps_set_enable,
486204433Sraj};
487204433Sraj
488204433SrajU_BOOT_DRIVER(palmas_smps) = {
489204431Sraj	.name = PALMAS_SMPS_DRIVER,
490204433Sraj	.id = UCLASS_REGULATOR,
491204433Sraj	.ops = &palmas_smps_ops,
492204431Sraj	.probe = palmas_smps_probe,
493204433Sraj};
494204433Sraj