1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *  Copyright (C) 2015 Samsung Electronics
4 *  Przemyslaw Marczak  <p.marczak@samsung.com>
5 */
6
7#include <common.h>
8#include <fdtdec.h>
9#include <errno.h>
10#include <dm.h>
11#include <linux/printk.h>
12#include <power/pmic.h>
13#include <power/regulator.h>
14#include <power/sandbox_pmic.h>
15
16#define MODE(_id, _val, _name) [_id] = {  \
17	.id = _id,                \
18	.register_value = _val,   \
19	.name = _name,            \
20}
21
22#define RANGE(_min, _max, _step) { \
23	.min = _min,               \
24	.max = _max,               \
25	.step = _step,             \
26}
27
28/*
29 * struct output_range - helper structure type to define the range of output
30 * operating values (current/voltage), limited by the PMIC IC design.
31 *
32 * @min  - minimum value
33 * @max  - maximum value
34 * @step - step value
35*/
36struct output_range {
37	int min;
38	int max;
39	int step;
40};
41
42/* BUCK: 1,2 - voltage range */
43static struct output_range buck_voltage_range[] = {
44	RANGE(OUT_BUCK1_UV_MIN, OUT_BUCK1_UV_MAX, OUT_BUCK1_UV_STEP),
45	RANGE(OUT_BUCK2_UV_MIN, OUT_BUCK2_UV_MAX, OUT_BUCK2_UV_STEP),
46};
47
48/* BUCK: 1 - current range */
49static struct output_range buck_current_range[] = {
50	RANGE(OUT_BUCK1_UA_MIN, OUT_BUCK1_UA_MAX, OUT_BUCK1_UA_STEP),
51};
52
53/* BUCK operating modes */
54static struct dm_regulator_mode sandbox_buck_modes[] = {
55	MODE(BUCK_OM_OFF, OM2REG(BUCK_OM_OFF), "OFF"),
56	MODE(BUCK_OM_ON, OM2REG(BUCK_OM_ON), "ON"),
57	MODE(BUCK_OM_PWM, OM2REG(BUCK_OM_PWM), "PWM"),
58};
59
60/* LDO: 1,2 - voltage range */
61static struct output_range ldo_voltage_range[] = {
62	RANGE(OUT_LDO1_UV_MIN, OUT_LDO1_UV_MAX, OUT_LDO1_UV_STEP),
63	RANGE(OUT_LDO2_UV_MIN, OUT_LDO2_UV_MAX, OUT_LDO2_UV_STEP),
64};
65
66/* LDO: 1 - current range */
67static struct output_range ldo_current_range[] = {
68	RANGE(OUT_LDO1_UA_MIN, OUT_LDO1_UA_MAX, OUT_LDO1_UA_STEP),
69};
70
71/* LDO operating modes */
72static struct dm_regulator_mode sandbox_ldo_modes[] = {
73	MODE(LDO_OM_OFF, OM2REG(LDO_OM_OFF), "OFF"),
74	MODE(LDO_OM_ON, OM2REG(LDO_OM_ON), "ON"),
75	MODE(LDO_OM_SLEEP, OM2REG(LDO_OM_SLEEP), "SLEEP"),
76	MODE(LDO_OM_STANDBY, OM2REG(LDO_OM_STANDBY), "STANDBY"),
77};
78
79int out_get_value(struct udevice *dev, int output_count, int reg_type,
80		  struct output_range *range)
81{
82	uint8_t reg_val;
83	uint reg;
84	int ret;
85
86	if (dev->driver_data > output_count) {
87		pr_err("Unknown regulator number: %lu for PMIC %s!",
88		      dev->driver_data, dev->name);
89		return -EINVAL;
90	}
91
92	reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type;
93	ret = pmic_read(dev->parent, reg, &reg_val, 1);
94	if (ret) {
95		pr_err("PMIC read failed: %d\n",  ret);
96		return ret;
97	}
98
99	ret =  REG2VAL(range[dev->driver_data - 1].min,
100		       range[dev->driver_data - 1].step,
101		       reg_val);
102
103	return ret;
104}
105
106static int out_set_value(struct udevice *dev, int output_count, int reg_type,
107			 struct output_range *range, int value)
108{
109	uint8_t reg_val;
110	uint reg;
111	int ret;
112	int max_value;
113
114	if (dev->driver_data > output_count) {
115		pr_err("Unknown regulator number: %lu for PMIC %s!",
116		      dev->driver_data, dev->name);
117		return -EINVAL;
118	}
119
120	max_value = range[dev->driver_data - 1].max;
121	if (value > max_value) {
122		pr_err("Wrong value for %s: %lu. Max is: %d.",
123		      dev->name, dev->driver_data, max_value);
124		return -EINVAL;
125	}
126
127	reg_val = VAL2REG(range[dev->driver_data - 1].min,
128			  range[dev->driver_data - 1].step,
129			  value);
130
131	reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type;
132	ret = pmic_write(dev->parent, reg, &reg_val, 1);
133	if (ret) {
134		pr_err("PMIC write failed: %d\n",  ret);
135		return ret;
136	}
137
138	return 0;
139}
140
141static int out_get_mode(struct udevice *dev)
142{
143	struct dm_regulator_uclass_plat *uc_pdata;
144	uint8_t reg_val;
145	uint reg;
146	int ret;
147	int i;
148
149	uc_pdata = dev_get_uclass_plat(dev);
150
151	reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM;
152	ret = pmic_read(dev->parent, reg, &reg_val, 1);
153	if (ret) {
154		pr_err("PMIC read failed: %d\n",  ret);
155		return ret;
156	}
157
158	for (i = 0; i < uc_pdata->mode_count; i++) {
159		if (reg_val == uc_pdata->mode[i].register_value)
160			return uc_pdata->mode[i].id;
161	}
162
163	pr_err("Unknown operation mode for %s!", dev->name);
164	return -EINVAL;
165}
166
167static int out_set_mode(struct udevice *dev, int mode)
168{
169	struct dm_regulator_uclass_plat *uc_pdata;
170	int reg_val = -1;
171	uint reg;
172	int ret;
173	int i;
174
175	uc_pdata = dev_get_uclass_plat(dev);
176
177	if (mode >= uc_pdata->mode_count)
178		return -EINVAL;
179
180	for (i = 0; i < uc_pdata->mode_count; i++) {
181		if (mode == uc_pdata->mode[i].id) {
182			reg_val = uc_pdata->mode[i].register_value;
183			break;
184		}
185	}
186
187	if (reg_val == -1) {
188		pr_err("Unknown operation mode for %s!", dev->name);
189		return -EINVAL;
190	}
191
192	reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM;
193	ret = pmic_write(dev->parent, reg, (uint8_t *)&reg_val, 1);
194	if (ret) {
195		pr_err("PMIC write failed: %d\n",  ret);
196		return ret;
197	}
198
199	return 0;
200}
201
202static int buck_get_voltage(struct udevice *dev)
203{
204	return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV,
205			      buck_voltage_range);
206}
207
208static int buck_set_voltage(struct udevice *dev, int uV)
209{
210	return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV,
211			      buck_voltage_range, uV);
212}
213
214static int buck_get_current(struct udevice *dev)
215{
216	/* BUCK2 - unsupported */
217	if (dev->driver_data == 2)
218		return -ENOSYS;
219
220	return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA,
221			      buck_current_range);
222}
223
224static int buck_set_current(struct udevice *dev, int uA)
225{
226	/* BUCK2 - unsupported */
227	if (dev->driver_data == 2)
228		return -ENOSYS;
229
230	return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA,
231			      buck_current_range, uA);
232}
233
234static int buck_get_enable(struct udevice *dev)
235{
236	if (out_get_mode(dev) == BUCK_OM_OFF)
237		return false;
238
239	return true;
240}
241
242static int buck_set_enable(struct udevice *dev, bool enable)
243{
244	return out_set_mode(dev, enable ? BUCK_OM_ON : BUCK_OM_OFF);
245}
246
247static int sandbox_buck_probe(struct udevice *dev)
248{
249	struct dm_regulator_uclass_plat *uc_pdata;
250
251	uc_pdata = dev_get_uclass_plat(dev);
252
253	uc_pdata->type = REGULATOR_TYPE_BUCK;
254	uc_pdata->mode = sandbox_buck_modes;
255	uc_pdata->mode_count = ARRAY_SIZE(sandbox_buck_modes);
256
257	return 0;
258}
259
260static const struct dm_regulator_ops sandbox_buck_ops = {
261	.get_value   = buck_get_voltage,
262	.set_value   = buck_set_voltage,
263	.get_current = buck_get_current,
264	.set_current = buck_set_current,
265	.get_enable  = buck_get_enable,
266	.set_enable  = buck_set_enable,
267	.get_mode    = out_get_mode,
268	.set_mode    = out_set_mode,
269};
270
271U_BOOT_DRIVER(sandbox_buck) = {
272	.name = SANDBOX_BUCK_DRIVER,
273	.id = UCLASS_REGULATOR,
274	.ops = &sandbox_buck_ops,
275	.probe = sandbox_buck_probe,
276};
277
278static int ldo_get_voltage(struct udevice *dev)
279{
280	return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV,
281			     ldo_voltage_range);
282}
283
284static int ldo_set_voltage(struct udevice *dev, int uV)
285{
286	return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV,
287			     ldo_voltage_range, uV);
288}
289
290static int ldo_get_current(struct udevice *dev)
291{
292	/* LDO2 - unsupported */
293	if (dev->driver_data == 2)
294		return -ENOSYS;
295
296	return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA,
297			     ldo_current_range);
298}
299
300static int ldo_set_current(struct udevice *dev, int uA)
301{
302	/* LDO2 - unsupported */
303	if (dev->driver_data == 2)
304		return -ENOSYS;
305
306	return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA,
307			     ldo_current_range, uA);
308}
309
310static int ldo_get_enable(struct udevice *dev)
311{
312	if (out_get_mode(dev) == LDO_OM_OFF)
313		return false;
314
315	return true;
316}
317
318static int ldo_set_enable(struct udevice *dev, bool enable)
319{
320	return out_set_mode(dev, enable ? LDO_OM_ON : LDO_OM_OFF);
321}
322
323static int sandbox_ldo_probe(struct udevice *dev)
324{
325	struct dm_regulator_uclass_plat *uc_pdata;
326
327	uc_pdata = dev_get_uclass_plat(dev);
328
329	uc_pdata->type = REGULATOR_TYPE_LDO;
330	uc_pdata->mode = sandbox_ldo_modes;
331	uc_pdata->mode_count = ARRAY_SIZE(sandbox_ldo_modes);
332
333	return 0;
334}
335
336static const struct dm_regulator_ops sandbox_ldo_ops = {
337	.get_value   = ldo_get_voltage,
338	.set_value   = ldo_set_voltage,
339	.get_current = ldo_get_current,
340	.set_current = ldo_set_current,
341	.get_enable  = ldo_get_enable,
342	.set_enable  = ldo_set_enable,
343	.get_mode    = out_get_mode,
344	.set_mode    = out_set_mode,
345};
346
347U_BOOT_DRIVER(sandbox_ldo) = {
348	.name = SANDBOX_LDO_DRIVER,
349	.id = UCLASS_REGULATOR,
350	.ops = &sandbox_ldo_ops,
351	.probe = sandbox_ldo_probe,
352};
353