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/max77663.h>
10
11/* fist row is control registers, second is voltage registers */
12static const char max77663_sd_reg[][MAX77663_SD_NUM] = {
13	{ 0x1d, 0x1e, 0x1f, 0x20, 0x21 },
14	{ 0x16, 0x17, 0x18, 0x19, 0x2a },
15};
16
17static const char max77663_ldo_reg[MAX77663_LDO_NUM] = {
18	0x23, 0x25, 0x27, 0x29, 0x2b, 0x2d, 0x2f, 0x31, 0x33
19};
20
21static int max77663_sd_enable(struct udevice *dev, int op, bool *enable)
22{
23	struct dm_regulator_uclass_plat *uc_pdata =
24					dev_get_uclass_plat(dev);
25	u32 adr = uc_pdata->ctrl_reg;
26	int val, ret;
27
28	val = pmic_reg_read(dev->parent, adr);
29	if (val < 0)
30		return val;
31
32	if (op == PMIC_OP_GET) {
33		if (val & SD_STATUS_MASK)
34			*enable = true;
35		else
36			*enable = false;
37
38		return 0;
39	} else if (op == PMIC_OP_SET) {
40		val &= ~SD_STATUS_MASK;
41
42		if (*enable)
43			val |= SD_STATUS_MASK;
44
45		ret = pmic_reg_write(dev->parent, adr, val);
46		if (ret)
47			return ret;
48	}
49
50	return 0;
51}
52
53/**
54 * max77663_*_volt2hex() - convert voltage in uV into
55 *			   applicable to register hex value
56 *
57 * @idx:	regulator index
58 * @uV:		voltage in uV
59 *
60 * Return: voltage in hex on success, -ve on failure
61 */
62static int max77663_sd_volt2hex(int idx, int uV)
63{
64	switch (idx) {
65	case 0:
66		/* SD0 has max voltage 1.4V */
67		if (uV > SD0_VOLT_MAX)
68			return -EINVAL;
69		break;
70	case 1:
71		/* SD1 has max voltage 1.55V */
72		if (uV > SD1_VOLT_MAX)
73			return -EINVAL;
74		break;
75	default:
76		/* SD2 and SD3 have max voltage 3.79V */
77		if (uV > SD_VOLT_MAX)
78			return -EINVAL;
79		break;
80	};
81
82	if (uV < SD_VOLT_MIN)
83		uV = SD_VOLT_MIN;
84
85	return (uV - SD_VOLT_BASE) / 12500;
86}
87
88/**
89 * max77663_*_hex2volt() - convert register hex value into
90 *			   actual voltage in uV
91 *
92 * @idx:	regulator index
93 * @hex:	hex value of register
94 *
95 * Return: voltage in uV on success, -ve on failure
96 */
97static int max77663_sd_hex2volt(int idx, int hex)
98{
99	switch (idx) {
100	case 0:
101		/* SD0 has max voltage 1.4V */
102		if (hex > SD0_VOLT_MAX_HEX)
103			return -EINVAL;
104		break;
105	case 1:
106		/* SD1 has max voltage 1.55V */
107		if (hex > SD1_VOLT_MAX_HEX)
108			return -EINVAL;
109		break;
110	default:
111		/* SD2 and SD3 have max voltage 3.79V */
112		if (hex > SD_VOLT_MAX_HEX)
113			return -EINVAL;
114		break;
115	};
116
117	if (hex < SD_VOLT_MIN_HEX)
118		hex = SD_VOLT_MIN_HEX;
119
120	return SD_VOLT_BASE + hex * 12500;
121}
122
123static int max77663_sd_val(struct udevice *dev, int op, int *uV)
124{
125	struct dm_regulator_uclass_plat *uc_pdata =
126					dev_get_uclass_plat(dev);
127	u32 adr = uc_pdata->volt_reg;
128	int idx = dev->driver_data;
129	int hex, ret;
130
131	if (op == PMIC_OP_GET) {
132		hex = pmic_reg_read(dev->parent, adr);
133		if (hex < 0)
134			return hex;
135
136		*uV = 0;
137
138		ret = max77663_sd_hex2volt(idx, hex);
139		if (ret < 0)
140			return ret;
141		*uV = ret;
142
143		return 0;
144	}
145
146	/* SD regulators use entire register for voltage */
147	hex = max77663_sd_volt2hex(idx, *uV);
148	if (hex < 0)
149		return hex;
150
151	return pmic_reg_write(dev->parent, adr, hex);
152}
153
154static int max77663_sd_probe(struct udevice *dev)
155{
156	struct dm_regulator_uclass_plat *uc_pdata =
157					dev_get_uclass_plat(dev);
158	int idx = dev->driver_data;
159
160	uc_pdata->type = REGULATOR_TYPE_BUCK;
161	uc_pdata->ctrl_reg = max77663_sd_reg[0][idx];
162	uc_pdata->volt_reg = max77663_sd_reg[1][idx];
163
164	return 0;
165}
166
167static int sd_get_value(struct udevice *dev)
168{
169	int uV;
170	int ret;
171
172	ret = max77663_sd_val(dev, PMIC_OP_GET, &uV);
173	if (ret)
174		return ret;
175
176	return uV;
177}
178
179static int sd_set_value(struct udevice *dev, int uV)
180{
181	return max77663_sd_val(dev, PMIC_OP_SET, &uV);
182}
183
184static int sd_get_enable(struct udevice *dev)
185{
186	bool enable = false;
187	int ret;
188
189	ret = max77663_sd_enable(dev, PMIC_OP_GET, &enable);
190	if (ret)
191		return ret;
192
193	return enable;
194}
195
196static int sd_set_enable(struct udevice *dev, bool enable)
197{
198	return max77663_sd_enable(dev, PMIC_OP_SET, &enable);
199}
200
201static const struct dm_regulator_ops max77663_sd_ops = {
202	.get_value  = sd_get_value,
203	.set_value  = sd_set_value,
204	.get_enable = sd_get_enable,
205	.set_enable = sd_set_enable,
206};
207
208U_BOOT_DRIVER(max77663_sd) = {
209	.name = MAX77663_SD_DRIVER,
210	.id = UCLASS_REGULATOR,
211	.ops = &max77663_sd_ops,
212	.probe = max77663_sd_probe,
213};
214
215static int max77663_ldo_enable(struct udevice *dev, int op, bool *enable)
216{
217	struct dm_regulator_uclass_plat *uc_pdata =
218					dev_get_uclass_plat(dev);
219	u32 adr = uc_pdata->ctrl_reg;
220	int val, ret;
221
222	val = pmic_reg_read(dev->parent, adr);
223	if (val < 0)
224		return val;
225
226	if (op == PMIC_OP_GET) {
227		if (val & LDO_STATUS_MASK)
228			*enable = true;
229		else
230			*enable = false;
231
232		return 0;
233	} else if (op == PMIC_OP_SET) {
234		val &= ~LDO_STATUS_MASK;
235
236		if (*enable)
237			val |= LDO_STATUS_MASK;
238
239		ret = pmic_reg_write(dev->parent, adr, val);
240		if (ret)
241			return ret;
242	}
243
244	return 0;
245}
246
247static int max77663_ldo_volt2hex(int idx, int uV)
248{
249	switch (idx) {
250	case 0:
251	case 1:
252		if (uV > LDO01_VOLT_MAX)
253			return -EINVAL;
254
255		return (uV - LDO_VOLT_BASE) / 25000;
256	case 4:
257		if (uV > LDO4_VOLT_MAX)
258			return -EINVAL;
259
260		return (uV - LDO_VOLT_BASE) / 12500;
261	default:
262		if (uV > LDO_VOLT_MAX)
263			return -EINVAL;
264
265		return (uV - LDO_VOLT_BASE) / 50000;
266	};
267}
268
269static int max77663_ldo_hex2volt(int idx, int hex)
270{
271	if (hex > LDO_VOLT_MAX_HEX)
272		return -EINVAL;
273
274	switch (idx) {
275	case 0:
276	case 1:
277		return (hex * 25000) + LDO_VOLT_BASE;
278	case 4:
279		return (hex * 12500) + LDO_VOLT_BASE;
280	default:
281		return (hex * 50000) + LDO_VOLT_BASE;
282	};
283}
284
285static int max77663_ldo_val(struct udevice *dev, int op, int *uV)
286{
287	struct dm_regulator_uclass_plat *uc_pdata =
288					dev_get_uclass_plat(dev);
289	u32 adr = uc_pdata->ctrl_reg;
290	int idx = dev->driver_data;
291	int hex, val, ret;
292
293	val = pmic_reg_read(dev->parent, adr);
294	if (val < 0)
295		return val;
296
297	if (op == PMIC_OP_GET) {
298		*uV = 0;
299
300		ret = max77663_ldo_hex2volt(idx, val & LDO_VOLT_MASK);
301		if (ret < 0)
302			return ret;
303
304		*uV = ret;
305		return 0;
306	}
307
308	hex = max77663_ldo_volt2hex(idx, *uV);
309	if (hex < 0)
310		return hex;
311
312	val &= ~LDO_VOLT_MASK;
313
314	return pmic_reg_write(dev->parent, adr, val | hex);
315}
316
317static int max77663_ldo_probe(struct udevice *dev)
318{
319	struct dm_regulator_uclass_plat *uc_pdata =
320					dev_get_uclass_plat(dev);
321	int idx = dev->driver_data;
322
323	uc_pdata->type = REGULATOR_TYPE_LDO;
324	uc_pdata->ctrl_reg = max77663_ldo_reg[idx];
325
326	return 0;
327}
328
329static int ldo_get_value(struct udevice *dev)
330{
331	int uV;
332	int ret;
333
334	ret = max77663_ldo_val(dev, PMIC_OP_GET, &uV);
335	if (ret)
336		return ret;
337
338	return uV;
339}
340
341static int ldo_set_value(struct udevice *dev, int uV)
342{
343	return max77663_ldo_val(dev, PMIC_OP_SET, &uV);
344}
345
346static int ldo_get_enable(struct udevice *dev)
347{
348	bool enable = false;
349	int ret;
350
351	ret = max77663_ldo_enable(dev, PMIC_OP_GET, &enable);
352	if (ret)
353		return ret;
354
355	return enable;
356}
357
358static int ldo_set_enable(struct udevice *dev, bool enable)
359{
360	return max77663_ldo_enable(dev, PMIC_OP_SET, &enable);
361}
362
363static const struct dm_regulator_ops max77663_ldo_ops = {
364	.get_value  = ldo_get_value,
365	.set_value  = ldo_set_value,
366	.get_enable = ldo_get_enable,
367	.set_enable = ldo_set_enable,
368};
369
370U_BOOT_DRIVER(max77663_ldo) = {
371	.name = MAX77663_LDO_DRIVER,
372	.id = UCLASS_REGULATOR,
373	.ops = &max77663_ldo_ops,
374	.probe = max77663_ldo_probe,
375};
376