staticint vctrl_set_voltage(struct regulator_dev *rdev, int req_min_uV, int req_max_uV, unsignedint *selector)
{ struct vctrl_data *vctrl = rdev_get_drvdata(rdev); int orig_ctrl_uV; int uV; int ret;
if (req_min_uV >= uV || !vctrl->ovp_threshold) /* voltage rising or no OVP */ return regulator_set_voltage_rdev(rdev->supply->rdev,
vctrl_calc_ctrl_voltage(vctrl, req_min_uV),
vctrl_calc_ctrl_voltage(vctrl, req_max_uV),
PM_SUSPEND_ON);
while (uV > req_min_uV) { int max_drop_uV = (uV * vctrl->ovp_threshold) / 100; int next_uV; int next_ctrl_uV; int delay;
/* Make sure no infinite loop even in crazy cases */ if (max_drop_uV == 0)
max_drop_uV = 1;
if (selector >= rdev->desc->n_voltages) return -EINVAL;
if (selector >= vctrl->sel || !vctrl->ovp_threshold) { /* voltage rising or no OVP */
ret = regulator_set_voltage_rdev(rdev->supply->rdev,
vctrl->vtable[selector].ctrl,
vctrl->vtable[selector].ctrl,
PM_SUSPEND_ON); if (!ret)
vctrl->sel = selector;
return ret;
}
while (vctrl->sel != selector) { unsignedint next_sel; int delay;
ret = regulator_set_voltage_rdev(rdev->supply->rdev,
vctrl->vtable[next_sel].ctrl,
vctrl->vtable[next_sel].ctrl,
PM_SUSPEND_ON); if (ret) {
dev_err(&rdev->dev, "failed to set control voltage to %duV\n",
vctrl->vtable[next_sel].ctrl); goto err;
}
vctrl->sel = next_sel;
err: if (vctrl->sel != orig_sel) { /* Try to go back to original voltage */ if (!regulator_set_voltage_rdev(rdev->supply->rdev,
vctrl->vtable[orig_sel].ctrl,
vctrl->vtable[orig_sel].ctrl,
PM_SUSPEND_ON))
vctrl->sel = orig_sel; else
dev_warn(&rdev->dev, "failed to restore original voltage\n");
}
ret = of_property_read_u32(np, "ovp-threshold-percent", &pval); if (!ret) {
vctrl->ovp_threshold = pval; if (vctrl->ovp_threshold > 100) {
dev_err(&pdev->dev, "ovp-threshold-percent (%u) > 100\n",
vctrl->ovp_threshold); return -EINVAL;
}
}
ret = of_property_read_u32(np, "min-slew-down-rate", &pval); if (!ret) {
vctrl->min_slew_down_rate = pval;
/* We use the value as int and as divider; sanity check */ if (vctrl->min_slew_down_rate == 0) {
dev_err(&pdev->dev, "min-slew-down-rate must not be 0\n"); return -EINVAL;
} elseif (vctrl->min_slew_down_rate > INT_MAX) {
dev_err(&pdev->dev, "min-slew-down-rate (%u) too big\n",
vctrl->min_slew_down_rate); return -EINVAL;
}
}
staticint vctrl_init_vtable(struct platform_device *pdev, struct regulator *ctrl_reg)
{ struct vctrl_data *vctrl = platform_get_drvdata(pdev); struct regulator_desc *rdesc = &vctrl->desc; struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl; int n_voltages; int ctrl_uV; int i, idx_vt;
n_voltages = regulator_count_voltages(ctrl_reg);
rdesc->n_voltages = n_voltages;
/* determine number of steps within the range of the vctrl regulator */ for (i = 0; i < n_voltages; i++) {
ctrl_uV = regulator_list_voltage(ctrl_reg, i);
if (ctrl_uV < vrange_ctrl->min_uV ||
ctrl_uV > vrange_ctrl->max_uV)
rdesc->n_voltages--;
}
/* we rely on the table to be ordered by ascending voltage */
sort(vctrl->vtable, rdesc->n_voltages, sizeof(struct vctrl_voltage_table), vctrl_cmp_ctrl_uV,
NULL);
/* pre-calculate OVP-safe downward transitions */ for (i = rdesc->n_voltages - 1; i > 0; i--) { int j; int ovp_min_uV = (vctrl->vtable[i].out *
(100 - vctrl->ovp_threshold)) / 100;
for (j = 0; j < i; j++) { if (vctrl->vtable[j].out >= ovp_min_uV) {
vctrl->vtable[i].ovp_min_sel = j; break;
}
}
if (j == i) {
dev_warn(&pdev->dev, "switching down from %duV may cause OVP shutdown\n",
vctrl->vtable[i].out); /* use next lowest voltage */
vctrl->vtable[i].ovp_min_sel = i - 1;
}
}
if (!rdesc->continuous_voltage_range) {
ret = vctrl_init_vtable(pdev, ctrl_reg); if (ret) return ret;
/* Use locked consumer API when not in regulator framework */
ctrl_uV = regulator_get_voltage(ctrl_reg); if (ctrl_uV < 0) {
dev_err(&pdev->dev, "failed to get control voltage\n"); return ctrl_uV;
}
/* determine current voltage selector from control voltage */ if (ctrl_uV < vrange_ctrl->min_uV) {
vctrl->sel = 0;
} elseif (ctrl_uV > vrange_ctrl->max_uV) {
vctrl->sel = rdesc->n_voltages - 1;
} else { int i;
for (i = 0; i < rdesc->n_voltages; i++) { if (ctrl_uV == vctrl->vtable[i].ctrl) {
vctrl->sel = i; break;
}
}
}
}
/* Drop ctrl-supply here in favor of regulator core managed supply */
devm_regulator_put(ctrl_reg);
vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg); if (IS_ERR(vctrl->rdev)) {
ret = PTR_ERR(vctrl->rdev);
dev_err(&pdev->dev, "failed to register regulator: %d\n", ret); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.