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 <i2c.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 */
36 struct output_range {
37 	int min;
38 	int max;
39 	int step;
40 };
41 
42 /* BUCK: 1,2 - voltage range */
43 static 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 */
49 static 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 */
54 static 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 */
61 static 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 */
67 static 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 */
72 static 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 
out_get_value(struct udevice * dev,int output_count,int reg_type,struct output_range * range)79 int 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 
out_set_value(struct udevice * dev,int output_count,int reg_type,struct output_range * range,int value)106 static 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 
out_get_mode(struct udevice * dev)141 static 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 
out_set_mode(struct udevice * dev,int mode)167 static 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 
buck_get_voltage(struct udevice * dev)202 static 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 
buck_set_voltage(struct udevice * dev,int uV)208 static 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 
buck_get_current(struct udevice * dev)214 static 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 
buck_set_current(struct udevice * dev,int uA)224 static 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 
buck_get_enable(struct udevice * dev)234 static 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 
buck_set_enable(struct udevice * dev,bool enable)242 static 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 
sandbox_buck_probe(struct udevice * dev)247 static 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 
260 static 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 
271 U_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 
ldo_get_voltage(struct udevice * dev)278 static 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 
ldo_set_voltage(struct udevice * dev,int uV)284 static 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 
ldo_get_current(struct udevice * dev)290 static 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 
ldo_set_current(struct udevice * dev,int uA)300 static 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 
ldo_get_enable(struct udevice * dev)310 static 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 
ldo_set_enable(struct udevice * dev,bool enable)318 static 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 
sandbox_ldo_probe(struct udevice * dev)323 static 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 
336 static 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 
347 U_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