1 /*
2  * (C) Copyright 2017
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/lp87565.h>
18 
19 DECLARE_GLOBAL_DATA_PTR;
20 
21 static const char lp87565_buck_ctrl1[LP87565_BUCK_NUM] = {0x2, 0x4, 0x6, 0x8, 0x2, 0x6};
22 static const char lp87565_buck_vout[LP87565_BUCK_NUM] = {0xA, 0xC, 0xE, 0x10, 0xA, 0xE };
23 
24 static int lp87565_buck_enable(struct udevice *dev, int op, bool *enable)
25 {
26 	int ret;
27 	unsigned int adr;
28 	struct dm_regulator_uclass_platdata *uc_pdata;
29 
30 	uc_pdata = dev_get_uclass_platdata(dev);
31 	adr = uc_pdata->ctrl_reg;
32 
33 	ret = pmic_reg_read(dev->parent, adr);
34 	if (ret < 0)
35 		return ret;
36 
37 	if (op == PMIC_OP_GET) {
38 		ret &= LP87565_BUCK_MODE_MASK;
39 
40 		if (ret)
41 			*enable = true;
42 		else
43 			*enable = false;
44 
45 		return 0;
46 	} else if (op == PMIC_OP_SET) {
47 		if (*enable)
48 			ret |= LP87565_BUCK_MODE_MASK;
49 		else
50 			ret &= ~LP87565_BUCK_MODE_MASK;
51 		ret = pmic_reg_write(dev->parent, adr, ret);
52 		if (ret)
53 			return ret;
54 	}
55 
56 	return 0;
57 }
58 
59 static int lp87565_buck_volt2val(int uV)
60 {
61 	if (uV > LP87565_BUCK_VOLT_MAX)
62 		return -EINVAL;
63 	else if (uV > 1400000)
64 		return (uV - 1420000) / 20000 + 0x9E;
65 	else if (uV > 730000)
66 		return (uV - 735000) / 5000 + 0x18;
67 	else if (uV >= 500000)
68 		return (uV - 500000) / 10000;
69 	else
70 		return -EINVAL;
71 }
72 
73 static int lp87565_buck_val2volt(int val)
74 {
75 	if (val > LP87565_BUCK_VOLT_MAX_HEX)
76 		return -EINVAL;
77 	else if (val > 0x9D)
78 		return 1400000 + (val - 0x9D) * 20000;
79 	else if (val > 0x17)
80 		return 730000 + (val - 0x17) * 5000;
81 	else if (val >= 0x0)
82 		return 500000 + val * 10000;
83 	else
84 		return -EINVAL;
85 }
86 
87 static int lp87565_buck_val(struct udevice *dev, int op, int *uV)
88 {
89 	unsigned int hex, adr;
90 	int ret;
91 	struct dm_regulator_uclass_platdata *uc_pdata;
92 
93 	uc_pdata = dev_get_uclass_platdata(dev);
94 
95 	if (op == PMIC_OP_GET)
96 		*uV = 0;
97 
98 	adr = uc_pdata->volt_reg;
99 
100 	ret = pmic_reg_read(dev->parent, adr);
101 	if (ret < 0)
102 		return ret;
103 
104 	if (op == PMIC_OP_GET) {
105 		ret &= LP87565_BUCK_VOLT_MASK;
106 		ret = lp87565_buck_val2volt(ret);
107 		if (ret < 0)
108 			return ret;
109 		*uV = ret;
110 
111 		return 0;
112 	}
113 
114 	hex = lp87565_buck_volt2val(*uV);
115 	if (hex < 0)
116 		return hex;
117 
118 	ret &= 0x0;
119 	ret = hex;
120 
121 	ret = pmic_reg_write(dev->parent, adr, ret);
122 
123 	return ret;
124 }
125 
126 static int lp87565_buck_probe(struct udevice *dev)
127 {
128 	struct dm_regulator_uclass_platdata *uc_pdata;
129 	int idx;
130 
131 	uc_pdata = dev_get_uclass_platdata(dev);
132 	uc_pdata->type = REGULATOR_TYPE_BUCK;
133 
134 	idx = dev->driver_data;
135 	if (idx == 0 || idx == 1 || idx == 2 || idx == 3) {
136 		debug("Single phase regulator\n");
137 	} else if (idx == 23) {
138 		idx = 5;
139 	} else if (idx == 10) {
140 		idx = 4;
141 	} else {
142 		printf("Wrong ID for regulator\n");
143 		return -EINVAL;
144 	}
145 
146 	uc_pdata->ctrl_reg = lp87565_buck_ctrl1[idx];
147 	uc_pdata->volt_reg = lp87565_buck_vout[idx];
148 
149 	return 0;
150 }
151 
152 static int buck_get_value(struct udevice *dev)
153 {
154 	int uV;
155 	int ret;
156 
157 	ret = lp87565_buck_val(dev, PMIC_OP_GET, &uV);
158 	if (ret)
159 		return ret;
160 
161 	return uV;
162 }
163 
164 static int buck_set_value(struct udevice *dev, int uV)
165 {
166 	return lp87565_buck_val(dev, PMIC_OP_SET, &uV);
167 }
168 
169 static bool buck_get_enable(struct udevice *dev)
170 {
171 	bool enable = false;
172 	int ret;
173 
174 
175 	ret = lp87565_buck_enable(dev, PMIC_OP_GET, &enable);
176 	if (ret)
177 		return ret;
178 
179 	return enable;
180 }
181 
182 static int buck_set_enable(struct udevice *dev, bool enable)
183 {
184 	return lp87565_buck_enable(dev, PMIC_OP_SET, &enable);
185 }
186 
187 static const struct dm_regulator_ops lp87565_buck_ops = {
188 	.get_value  = buck_get_value,
189 	.set_value  = buck_set_value,
190 	.get_enable = buck_get_enable,
191 	.set_enable = buck_set_enable,
192 };
193 
194 U_BOOT_DRIVER(lp87565_buck) = {
195 	.name = LP87565_BUCK_DRIVER,
196 	.id = UCLASS_REGULATOR,
197 	.ops = &lp87565_buck_ops,
198 	.probe = lp87565_buck_probe,
199 };
200