1// 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};
348