blob: 87696662e110a3d4459f342f166145325b521de6 [file] [log] [blame]
Svyatoslav Ryhelce6381a2023-10-27 11:26:13 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright(C) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <dm.h>
7#include <power/pmic.h>
8#include <power/regulator.h>
9#include <power/tps80031.h>
10
11static const char tps80031_smps_reg[][TPS80031_SMPS_NUM] = {
12 { 0x54, 0x5a, 0x66, 0x42, 0x48 },
13 { 0x56, 0x5c, 0x68, 0x44, 0x4a },
14 { BIT(3), BIT(4), BIT(6), BIT(0), BIT(1) },
15};
16
17static const char tps80031_ldo_reg[][TPS80031_LDO_NUM] = {
18 { 0x9e, 0x86, 0x8e, 0x8a, 0x9a, 0x92, 0xa6, 0x96, 0xa2 },
19 { 0x9f, 0x87, 0x8f, 0x8b, 0x9b, 0x93, 0xa7, 0x97, 0xa3 },
20};
21
22static int tps80031_regulator_enable(struct udevice *dev, int op, bool *enable)
23{
24 struct dm_regulator_uclass_plat *uc_pdata =
25 dev_get_uclass_plat(dev);
26 u32 adr = uc_pdata->ctrl_reg;
27 int val, ret;
28
29 val = pmic_reg_read(dev->parent, adr);
30 if (val < 0)
31 return val;
32
33 if (op == PMIC_OP_GET) {
34 if (val & REGULATOR_MODE_ON)
35 *enable = true;
36 else
37 *enable = false;
38
39 return 0;
40 } else if (op == PMIC_OP_SET) {
41 val &= ~REGULATOR_STATUS_MASK;
42
43 if (*enable)
44 val |= REGULATOR_MODE_ON;
45
46 ret = pmic_reg_write(dev->parent, adr, val);
47 if (ret)
48 return ret;
49 }
50
51 return 0;
52}
53
54static int tps80031_get_enable(struct udevice *dev)
55{
56 bool enable = false;
57 int ret;
58
59 ret = tps80031_regulator_enable(dev, PMIC_OP_GET, &enable);
60 if (ret)
61 return ret;
62
63 return enable;
64}
65
66static int tps80031_set_enable(struct udevice *dev, bool enable)
67{
68 return tps80031_regulator_enable(dev, PMIC_OP_SET, &enable);
69}
70
71/**
72 * tps80031_ldo_volt2hex() - convert voltage in uV into
73 * applicable to register hex value
74 *
75 * @uV: voltage in uV
76 *
77 * Return: voltage in hex on success, -ve on failure
78 */
79static int tps80031_ldo_volt2hex(int uV)
80{
81 if (uV > LDO_VOLT_MAX)
82 return -EINVAL;
83
84 if (uV < LDO_VOLT_MIN)
85 uV = LDO_VOLT_MIN;
86
87 return DIV_ROUND_UP(uV - LDO_VOLT_BASE, 102000);
88}
89
90/**
91 * tps80031_ldo_hex2volt() - convert register hex value into
92 * actual voltage in uV
93 *
94 * @hex: hex value of register
95 *
96 * Return: voltage in uV on success, -ve on failure
97 */
98static int tps80031_ldo_hex2volt(int hex)
99{
100 if (hex > LDO_VOLT_MAX_HEX)
101 return -EINVAL;
102
103 if (hex < LDO_VOLT_MIN_HEX)
104 hex = LDO_VOLT_MIN_HEX;
105
106 return LDO_VOLT_BASE + hex * 102000;
107}
108
109static int tps80031_ldo_val(struct udevice *dev, int op, int *uV)
110{
111 struct dm_regulator_uclass_plat *uc_pdata =
112 dev_get_uclass_plat(dev);
113 u32 adr = uc_pdata->volt_reg;
114 int val, hex, ret;
115
116 val = pmic_reg_read(dev->parent, adr);
117 if (val < 0)
118 return val;
119
120 if (op == PMIC_OP_GET) {
121 *uV = 0;
122
123 ret = tps80031_ldo_hex2volt(val & LDO_VOLT_MASK);
124 if (ret < 0)
125 return ret;
126
127 *uV = ret;
128 return 0;
129 }
130
131 hex = tps80031_ldo_volt2hex(*uV);
132 if (hex < 0)
133 return hex;
134
135 val &= ~LDO_VOLT_MASK;
136
137 return pmic_reg_write(dev->parent, adr, val | hex);
138}
139
140static int tps80031_ldo_probe(struct udevice *dev)
141{
142 struct dm_regulator_uclass_plat *uc_pdata =
143 dev_get_uclass_plat(dev);
144
145 uc_pdata->type = REGULATOR_TYPE_LDO;
146
147 /* check for ldoln and ldousb cases */
148 if (!strcmp("ldoln", dev->name)) {
149 uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][7];
150 uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][7];
151 return 0;
152 }
153
154 if (!strcmp("ldousb", dev->name)) {
155 uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][8];
156 uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][8];
157 return 0;
158 }
159
160 if (dev->driver_data > 0) {
161 u8 idx = dev->driver_data - 1;
162
163 uc_pdata->ctrl_reg = tps80031_ldo_reg[CTRL][idx];
164 uc_pdata->volt_reg = tps80031_ldo_reg[VOLT][idx];
165 }
166
167 return 0;
168}
169
170static int ldo_get_value(struct udevice *dev)
171{
172 int uV;
173 int ret;
174
175 ret = tps80031_ldo_val(dev, PMIC_OP_GET, &uV);
176 if (ret)
177 return ret;
178
179 return uV;
180}
181
182static int ldo_set_value(struct udevice *dev, int uV)
183{
184 return tps80031_ldo_val(dev, PMIC_OP_SET, &uV);
185}
186
187static const struct dm_regulator_ops tps80031_ldo_ops = {
188 .get_value = ldo_get_value,
189 .set_value = ldo_set_value,
190 .get_enable = tps80031_get_enable,
191 .set_enable = tps80031_set_enable,
192};
193
194U_BOOT_DRIVER(tps80031_ldo) = {
195 .name = TPS80031_LDO_DRIVER,
196 .id = UCLASS_REGULATOR,
197 .ops = &tps80031_ldo_ops,
198 .probe = tps80031_ldo_probe,
199};
200
201struct tps80031_smps_priv {
202 int flags;
203};
204
205/* DCDC voltages for the selector of 0x39 to 0x3F */
206static int tps80031_dcdc_voltages[5] = {
207 1350000, 1500000, 1800000, 1900000, 2100000
208};
209
210/**
211 * tps80031_smps_volt2hex() - convert voltage in uV into
212 * applicable to register hex value
213 *
214 * @base: base voltage in uV
215 * @uV: voltage in uV
216 *
217 * Return: voltage in hex on success, -ve on failure
218 */
219static int tps80031_smps_volt2hex(u32 base, int uV)
220{
221 int i;
222
223 if (uV < base)
224 return 1;
225
226 if (uV > SMPS_VOLT_LINEAR) {
227 for (i = 0; i < ARRAY_SIZE(tps80031_dcdc_voltages); i++)
228 if (uV <= tps80031_dcdc_voltages[i])
229 break;
230
231 return SMPS_VOLT_NLINEAR_HEX + i;
232 }
233
234 return DIV_ROUND_UP(uV - base, 12500);
235}
236
237/**
238 * tps80031_smps_hex2volt() - convert register hex value into
239 * actual voltage in uV
240 *
241 * @base: base voltage in uV
242 * @hex: hex value of register
243 *
244 * Return: voltage in uV on success, -ve on failure
245 */
246static int tps80031_smps_hex2volt(u32 base, int hex)
247{
248 if (!hex)
249 return 0;
250
251 /* if reg value exceeds linear scale use table */
252 if (hex > SMPS_VOLT_LINEAR_HEX)
253 return tps80031_dcdc_voltages[hex - SMPS_VOLT_LINEAR_HEX];
254 else
255 return base + hex * 12500;
256}
257
258static int tps80031_smps_val(struct udevice *dev, int op, int *uV)
259{
260 struct dm_regulator_uclass_plat *uc_pdata =
261 dev_get_uclass_plat(dev);
262 struct tps80031_smps_priv *priv = dev_get_priv(dev);
263 u32 adr = uc_pdata->volt_reg;
264 int base, val, hex, ret;
265
266 /* If offset flag was set then base voltage is higher */
267 if (priv->flags & TPS80031_OFFSET_FLAG)
268 base = SMPS_VOLT_BASE_OFFSET;
269 else
270 base = SMPS_VOLT_BASE;
271
272 val = pmic_reg_read(dev->parent, adr);
273 if (val < 0)
274 return val;
275
276 if (op == PMIC_OP_GET) {
277 *uV = 0;
278
279 ret = tps80031_smps_hex2volt(base, val & SMPS_VOLT_MASK);
280 if (ret < 0)
281 return ret;
282
283 *uV = ret;
284 return 0;
285 }
286
287 hex = tps80031_smps_volt2hex(base, *uV);
288 if (hex < 0)
289 return hex;
290
291 val &= ~SMPS_VOLT_MASK;
292
293 return pmic_reg_write(dev->parent, adr, val | hex);
294}
295
296static int tps80031_smps_probe(struct udevice *dev)
297{
298 struct dm_regulator_uclass_plat *uc_pdata =
299 dev_get_uclass_plat(dev);
300 struct tps80031_smps_priv *priv = dev_get_priv(dev);
301 int idx = dev->driver_data - 1;
302 int val;
303
304 uc_pdata->type = REGULATOR_TYPE_BUCK;
305
306 uc_pdata->ctrl_reg = tps80031_smps_reg[CTRL][idx];
307 uc_pdata->volt_reg = tps80031_smps_reg[VOLT][idx];
308
309 /* Determine if smps regulator uses higher voltage */
310 val = pmic_reg_read(dev->parent, TPS80031_SMPS_OFFSET);
311 if (val & tps80031_smps_reg[OFFSET][idx])
312 priv->flags |= TPS80031_OFFSET_FLAG;
313
314 return 0;
315}
316
317static int smps_get_value(struct udevice *dev)
318{
319 int uV;
320 int ret;
321
322 ret = tps80031_smps_val(dev, PMIC_OP_GET, &uV);
323 if (ret)
324 return ret;
325
326 return uV;
327}
328
329static int smps_set_value(struct udevice *dev, int uV)
330{
331 return tps80031_smps_val(dev, PMIC_OP_SET, &uV);
332}
333
334static const struct dm_regulator_ops tps80031_smps_ops = {
335 .get_value = smps_get_value,
336 .set_value = smps_set_value,
337 .get_enable = tps80031_get_enable,
338 .set_enable = tps80031_set_enable,
339};
340
341U_BOOT_DRIVER(tps80031_smps) = {
342 .name = TPS80031_SMPS_DRIVER,
343 .id = UCLASS_REGULATOR,
344 .ops = &tps80031_smps_ops,
345 .probe = tps80031_smps_probe,
346 .priv_auto = sizeof(struct tps80031_smps_priv),
347};