Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * Driver for voltage controller regulators
  3 *
  4 * Copyright (C) 2017 Google, Inc.
  5 *
  6 * This software is licensed under the terms of the GNU General Public
  7 * License version 2, as published by the Free Software Foundation, and
  8 * may be copied, distributed, and modified under those terms.
  9 *
 10 * This program is distributed in the hope that it will be useful,
 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13 * GNU General Public License for more details.
 14 */
 15
 16#include <linux/delay.h>
 17#include <linux/err.h>
 18#include <linux/init.h>
 19#include <linux/module.h>
 20#include <linux/of.h>
 21#include <linux/of_device.h>
 22#include <linux/regulator/driver.h>
 23#include <linux/regulator/of_regulator.h>
 24#include <linux/sort.h>
 25
 26struct vctrl_voltage_range {
 27	int min_uV;
 28	int max_uV;
 29};
 30
 31struct vctrl_voltage_ranges {
 32	struct vctrl_voltage_range ctrl;
 33	struct vctrl_voltage_range out;
 34};
 35
 36struct vctrl_voltage_table {
 37	int ctrl;
 38	int out;
 39	int ovp_min_sel;
 40};
 41
 42struct vctrl_data {
 43	struct regulator_dev *rdev;
 44	struct regulator_desc desc;
 45	struct regulator *ctrl_reg;
 46	bool enabled;
 47	unsigned int min_slew_down_rate;
 48	unsigned int ovp_threshold;
 49	struct vctrl_voltage_ranges vrange;
 50	struct vctrl_voltage_table *vtable;
 51	unsigned int sel;
 52};
 53
 54static int vctrl_calc_ctrl_voltage(struct vctrl_data *vctrl, int out_uV)
 55{
 56	struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl;
 57	struct vctrl_voltage_range *out = &vctrl->vrange.out;
 58
 59	return ctrl->min_uV +
 60		DIV_ROUND_CLOSEST_ULL((s64)(out_uV - out->min_uV) *
 61				      (ctrl->max_uV - ctrl->min_uV),
 62				      out->max_uV - out->min_uV);
 63}
 64
 65static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV)
 66{
 67	struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl;
 68	struct vctrl_voltage_range *out = &vctrl->vrange.out;
 69
 70	if (ctrl_uV < 0) {
 71		pr_err("vctrl: failed to get control voltage\n");
 72		return ctrl_uV;
 73	}
 74
 75	if (ctrl_uV < ctrl->min_uV)
 76		return out->min_uV;
 77
 78	if (ctrl_uV > ctrl->max_uV)
 79		return out->max_uV;
 80
 81	return out->min_uV +
 82		DIV_ROUND_CLOSEST_ULL((s64)(ctrl_uV - ctrl->min_uV) *
 83				      (out->max_uV - out->min_uV),
 84				      ctrl->max_uV - ctrl->min_uV);
 85}
 86
 87static int vctrl_get_voltage(struct regulator_dev *rdev)
 88{
 89	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
 90	int ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg);
 91
 92	return vctrl_calc_output_voltage(vctrl, ctrl_uV);
 93}
 94
 95static int vctrl_set_voltage(struct regulator_dev *rdev,
 96			     int req_min_uV, int req_max_uV,
 97			     unsigned int *selector)
 98{
 99	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
100	struct regulator *ctrl_reg = vctrl->ctrl_reg;
101	int orig_ctrl_uV = regulator_get_voltage(ctrl_reg);
102	int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV);
103	int ret;
104
105	if (req_min_uV >= uV || !vctrl->ovp_threshold)
106		/* voltage rising or no OVP */
107		return regulator_set_voltage(
108			ctrl_reg,
109			vctrl_calc_ctrl_voltage(vctrl, req_min_uV),
110			vctrl_calc_ctrl_voltage(vctrl, req_max_uV));
111
112	while (uV > req_min_uV) {
113		int max_drop_uV = (uV * vctrl->ovp_threshold) / 100;
114		int next_uV;
115		int next_ctrl_uV;
116		int delay;
117
118		/* Make sure no infinite loop even in crazy cases */
119		if (max_drop_uV == 0)
120			max_drop_uV = 1;
121
122		next_uV = max_t(int, req_min_uV, uV - max_drop_uV);
123		next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV);
124
125		ret = regulator_set_voltage(ctrl_reg,
126					    next_ctrl_uV,
127					    next_ctrl_uV);
128		if (ret)
129			goto err;
130
131		delay = DIV_ROUND_UP(uV - next_uV, vctrl->min_slew_down_rate);
132		usleep_range(delay, delay + DIV_ROUND_UP(delay, 10));
133
134		uV = next_uV;
135	}
136
137	return 0;
138
139err:
140	/* Try to go back to original voltage */
141	regulator_set_voltage(ctrl_reg, orig_ctrl_uV, orig_ctrl_uV);
142
143	return ret;
144}
145
146static int vctrl_get_voltage_sel(struct regulator_dev *rdev)
147{
148	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
149
150	return vctrl->sel;
151}
152
153static int vctrl_set_voltage_sel(struct regulator_dev *rdev,
154				 unsigned int selector)
155{
156	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
157	struct regulator *ctrl_reg = vctrl->ctrl_reg;
158	unsigned int orig_sel = vctrl->sel;
159	int ret;
160
161	if (selector >= rdev->desc->n_voltages)
162		return -EINVAL;
163
164	if (selector >= vctrl->sel || !vctrl->ovp_threshold) {
165		/* voltage rising or no OVP */
166		ret = regulator_set_voltage(ctrl_reg,
167					    vctrl->vtable[selector].ctrl,
168					    vctrl->vtable[selector].ctrl);
169		if (!ret)
170			vctrl->sel = selector;
171
172		return ret;
173	}
174
175	while (vctrl->sel != selector) {
176		unsigned int next_sel;
177		int delay;
178
179		if (selector >= vctrl->vtable[vctrl->sel].ovp_min_sel)
180			next_sel = selector;
181		else
182			next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel;
183
184		ret = regulator_set_voltage(ctrl_reg,
185					    vctrl->vtable[next_sel].ctrl,
186					    vctrl->vtable[next_sel].ctrl);
187		if (ret) {
188			dev_err(&rdev->dev,
189				"failed to set control voltage to %duV\n",
190				vctrl->vtable[next_sel].ctrl);
191			goto err;
192		}
193		vctrl->sel = next_sel;
194
195		delay = DIV_ROUND_UP(vctrl->vtable[vctrl->sel].out -
196				     vctrl->vtable[next_sel].out,
197				     vctrl->min_slew_down_rate);
198		usleep_range(delay, delay + DIV_ROUND_UP(delay, 10));
199	}
200
201	return 0;
202
203err:
204	if (vctrl->sel != orig_sel) {
205		/* Try to go back to original voltage */
206		if (!regulator_set_voltage(ctrl_reg,
207					   vctrl->vtable[orig_sel].ctrl,
208					   vctrl->vtable[orig_sel].ctrl))
209			vctrl->sel = orig_sel;
210		else
211			dev_warn(&rdev->dev,
212				 "failed to restore original voltage\n");
213	}
214
215	return ret;
216}
217
218static int vctrl_list_voltage(struct regulator_dev *rdev,
219			      unsigned int selector)
220{
221	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
222
223	if (selector >= rdev->desc->n_voltages)
224		return -EINVAL;
225
226	return vctrl->vtable[selector].out;
227}
228
229static int vctrl_parse_dt(struct platform_device *pdev,
230			  struct vctrl_data *vctrl)
231{
232	int ret;
233	struct device_node *np = pdev->dev.of_node;
234	u32 pval;
235	u32 vrange_ctrl[2];
236
237	vctrl->ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl");
238	if (IS_ERR(vctrl->ctrl_reg))
239		return PTR_ERR(vctrl->ctrl_reg);
240
241	ret = of_property_read_u32(np, "ovp-threshold-percent", &pval);
242	if (!ret) {
243		vctrl->ovp_threshold = pval;
244		if (vctrl->ovp_threshold > 100) {
245			dev_err(&pdev->dev,
246				"ovp-threshold-percent (%u) > 100\n",
247				vctrl->ovp_threshold);
248			return -EINVAL;
249		}
250	}
251
252	ret = of_property_read_u32(np, "min-slew-down-rate", &pval);
253	if (!ret) {
254		vctrl->min_slew_down_rate = pval;
255
256		/* We use the value as int and as divider; sanity check */
257		if (vctrl->min_slew_down_rate == 0) {
258			dev_err(&pdev->dev,
259				"min-slew-down-rate must not be 0\n");
260			return -EINVAL;
261		} else if (vctrl->min_slew_down_rate > INT_MAX) {
262			dev_err(&pdev->dev, "min-slew-down-rate (%u) too big\n",
263				vctrl->min_slew_down_rate);
264			return -EINVAL;
265		}
266	}
267
268	if (vctrl->ovp_threshold && !vctrl->min_slew_down_rate) {
269		dev_err(&pdev->dev,
270			"ovp-threshold-percent requires min-slew-down-rate\n");
271		return -EINVAL;
272	}
273
274	ret = of_property_read_u32(np, "regulator-min-microvolt", &pval);
275	if (ret) {
276		dev_err(&pdev->dev,
277			"failed to read regulator-min-microvolt: %d\n", ret);
278		return ret;
279	}
280	vctrl->vrange.out.min_uV = pval;
281
282	ret = of_property_read_u32(np, "regulator-max-microvolt", &pval);
283	if (ret) {
284		dev_err(&pdev->dev,
285			"failed to read regulator-max-microvolt: %d\n", ret);
286		return ret;
287	}
288	vctrl->vrange.out.max_uV = pval;
289
290	ret = of_property_read_u32_array(np, "ctrl-voltage-range", vrange_ctrl,
291					 2);
292	if (ret) {
293		dev_err(&pdev->dev, "failed to read ctrl-voltage-range: %d\n",
294			ret);
295		return ret;
296	}
297
298	if (vrange_ctrl[0] >= vrange_ctrl[1]) {
299		dev_err(&pdev->dev, "ctrl-voltage-range is invalid: %d-%d\n",
300			vrange_ctrl[0], vrange_ctrl[1]);
301		return -EINVAL;
302	}
303
304	vctrl->vrange.ctrl.min_uV = vrange_ctrl[0];
305	vctrl->vrange.ctrl.max_uV = vrange_ctrl[1];
306
307	return 0;
308}
309
310static int vctrl_cmp_ctrl_uV(const void *a, const void *b)
311{
312	const struct vctrl_voltage_table *at = a;
313	const struct vctrl_voltage_table *bt = b;
314
315	return at->ctrl - bt->ctrl;
316}
317
318static int vctrl_init_vtable(struct platform_device *pdev)
319{
320	struct vctrl_data *vctrl = platform_get_drvdata(pdev);
321	struct regulator_desc *rdesc = &vctrl->desc;
322	struct regulator *ctrl_reg = vctrl->ctrl_reg;
323	struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl;
324	int n_voltages;
325	int ctrl_uV;
326	int i, idx_vt;
327
328	n_voltages = regulator_count_voltages(ctrl_reg);
329
330	rdesc->n_voltages = n_voltages;
331
332	/* determine number of steps within the range of the vctrl regulator */
333	for (i = 0; i < n_voltages; i++) {
334		ctrl_uV = regulator_list_voltage(ctrl_reg, i);
335
336		if (ctrl_uV < vrange_ctrl->min_uV ||
337		    ctrl_uV > vrange_ctrl->max_uV) {
338			rdesc->n_voltages--;
339			continue;
340		}
341	}
342
343	if (rdesc->n_voltages == 0) {
344		dev_err(&pdev->dev, "invalid configuration\n");
345		return -EINVAL;
346	}
347
348	vctrl->vtable = devm_kcalloc(&pdev->dev, rdesc->n_voltages,
349				     sizeof(struct vctrl_voltage_table),
350				     GFP_KERNEL);
351	if (!vctrl->vtable)
352		return -ENOMEM;
353
354	/* create mapping control <=> output voltage */
355	for (i = 0, idx_vt = 0; i < n_voltages; i++) {
356		ctrl_uV = regulator_list_voltage(ctrl_reg, i);
357
358		if (ctrl_uV < vrange_ctrl->min_uV ||
359		    ctrl_uV > vrange_ctrl->max_uV)
360			continue;
361
362		vctrl->vtable[idx_vt].ctrl = ctrl_uV;
363		vctrl->vtable[idx_vt].out =
364			vctrl_calc_output_voltage(vctrl, ctrl_uV);
365		idx_vt++;
366	}
367
368	/* we rely on the table to be ordered by ascending voltage */
369	sort(vctrl->vtable, rdesc->n_voltages,
370	     sizeof(struct vctrl_voltage_table), vctrl_cmp_ctrl_uV,
371	     NULL);
372
373	/* pre-calculate OVP-safe downward transitions */
374	for (i = rdesc->n_voltages - 1; i > 0; i--) {
375		int j;
376		int ovp_min_uV = (vctrl->vtable[i].out *
377				  (100 - vctrl->ovp_threshold)) / 100;
378
379		for (j = 0; j < i; j++) {
380			if (vctrl->vtable[j].out >= ovp_min_uV) {
381				vctrl->vtable[i].ovp_min_sel = j;
382				break;
383			}
384		}
385
386		if (j == i) {
387			dev_warn(&pdev->dev, "switching down from %duV may cause OVP shutdown\n",
388				vctrl->vtable[i].out);
389			/* use next lowest voltage */
390			vctrl->vtable[i].ovp_min_sel = i - 1;
391		}
392	}
393
394	return 0;
395}
396
397static int vctrl_enable(struct regulator_dev *rdev)
398{
399	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
400	int ret = regulator_enable(vctrl->ctrl_reg);
401
402	if (!ret)
403		vctrl->enabled = true;
404
405	return ret;
406}
407
408static int vctrl_disable(struct regulator_dev *rdev)
409{
410	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
411	int ret = regulator_disable(vctrl->ctrl_reg);
412
413	if (!ret)
414		vctrl->enabled = false;
415
416	return ret;
417}
418
419static int vctrl_is_enabled(struct regulator_dev *rdev)
420{
421	struct vctrl_data *vctrl = rdev_get_drvdata(rdev);
422
423	return vctrl->enabled;
424}
425
426static const struct regulator_ops vctrl_ops_cont = {
427	.enable		  = vctrl_enable,
428	.disable	  = vctrl_disable,
429	.is_enabled	  = vctrl_is_enabled,
430	.get_voltage	  = vctrl_get_voltage,
431	.set_voltage	  = vctrl_set_voltage,
432};
433
434static const struct regulator_ops vctrl_ops_non_cont = {
435	.enable		  = vctrl_enable,
436	.disable	  = vctrl_disable,
437	.is_enabled	  = vctrl_is_enabled,
438	.set_voltage_sel = vctrl_set_voltage_sel,
439	.get_voltage_sel = vctrl_get_voltage_sel,
440	.list_voltage    = vctrl_list_voltage,
441	.map_voltage     = regulator_map_voltage_iterate,
442};
443
444static int vctrl_probe(struct platform_device *pdev)
445{
446	struct device_node *np = pdev->dev.of_node;
447	struct vctrl_data *vctrl;
448	const struct regulator_init_data *init_data;
449	struct regulator_desc *rdesc;
450	struct regulator_config cfg = { };
451	struct vctrl_voltage_range *vrange_ctrl;
452	int ctrl_uV;
453	int ret;
454
455	vctrl = devm_kzalloc(&pdev->dev, sizeof(struct vctrl_data),
456			     GFP_KERNEL);
457	if (!vctrl)
458		return -ENOMEM;
459
460	platform_set_drvdata(pdev, vctrl);
461
462	ret = vctrl_parse_dt(pdev, vctrl);
463	if (ret)
464		return ret;
465
466	vrange_ctrl = &vctrl->vrange.ctrl;
467
468	rdesc = &vctrl->desc;
469	rdesc->name = "vctrl";
470	rdesc->type = REGULATOR_VOLTAGE;
471	rdesc->owner = THIS_MODULE;
472
473	if ((regulator_get_linear_step(vctrl->ctrl_reg) == 1) ||
474	    (regulator_count_voltages(vctrl->ctrl_reg) == -EINVAL)) {
475		rdesc->continuous_voltage_range = true;
476		rdesc->ops = &vctrl_ops_cont;
477	} else {
478		rdesc->ops = &vctrl_ops_non_cont;
479	}
480
481	init_data = of_get_regulator_init_data(&pdev->dev, np, rdesc);
482	if (!init_data)
483		return -ENOMEM;
484
485	cfg.of_node = np;
486	cfg.dev = &pdev->dev;
487	cfg.driver_data = vctrl;
488	cfg.init_data = init_data;
489
490	if (!rdesc->continuous_voltage_range) {
491		ret = vctrl_init_vtable(pdev);
492		if (ret)
493			return ret;
494
495		ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg);
496		if (ctrl_uV < 0) {
497			dev_err(&pdev->dev, "failed to get control voltage\n");
498			return ctrl_uV;
499		}
500
501		/* determine current voltage selector from control voltage */
502		if (ctrl_uV < vrange_ctrl->min_uV) {
503			vctrl->sel = 0;
504		} else if (ctrl_uV > vrange_ctrl->max_uV) {
505			vctrl->sel = rdesc->n_voltages - 1;
506		} else {
507			int i;
508
509			for (i = 0; i < rdesc->n_voltages; i++) {
510				if (ctrl_uV == vctrl->vtable[i].ctrl) {
511					vctrl->sel = i;
512					break;
513				}
514			}
515		}
516	}
517
518	vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg);
519	if (IS_ERR(vctrl->rdev)) {
520		ret = PTR_ERR(vctrl->rdev);
521		dev_err(&pdev->dev, "failed to register regulator: %d\n", ret);
522		return ret;
523	}
524
525	return 0;
526}
527
528static const struct of_device_id vctrl_of_match[] = {
529	{ .compatible = "vctrl-regulator", },
530	{},
531};
532MODULE_DEVICE_TABLE(of, vctrl_of_match);
533
534static struct platform_driver vctrl_driver = {
535	.probe		= vctrl_probe,
536	.driver		= {
537		.name		= "vctrl-regulator",
538		.of_match_table = of_match_ptr(vctrl_of_match),
539	},
540};
541
542module_platform_driver(vctrl_driver);
543
544MODULE_DESCRIPTION("Voltage Controlled Regulator Driver");
545MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");
546MODULE_LICENSE("GPL v2");