val = wm831x_reg_read(wm831x, reg); if (val < 0) return val;
val = (val & WM831X_DC1_ON_MODE_MASK) >> WM831X_DC1_ON_MODE_SHIFT;
switch (val) { case WM831X_DCDC_MODE_FAST: return REGULATOR_MODE_FAST; case WM831X_DCDC_MODE_NORMAL: return REGULATOR_MODE_NORMAL; case WM831X_DCDC_MODE_STANDBY: return REGULATOR_MODE_STANDBY; case WM831X_DCDC_MODE_IDLE: return REGULATOR_MODE_IDLE; default:
BUG(); return -EINVAL;
}
}
staticint wm831x_dcdc_set_mode_int(struct wm831x *wm831x, int reg, unsignedint mode)
{ int val;
switch (mode) { case REGULATOR_MODE_FAST:
val = WM831X_DCDC_MODE_FAST; break; case REGULATOR_MODE_NORMAL:
val = WM831X_DCDC_MODE_NORMAL; break; case REGULATOR_MODE_STANDBY:
val = WM831X_DCDC_MODE_STANDBY; break; case REGULATOR_MODE_IDLE:
val = WM831X_DCDC_MODE_IDLE; break; default: return -EINVAL;
}
return wm831x_set_bits(wm831x, reg, WM831X_DC1_ON_MODE_MASK,
val << WM831X_DC1_ON_MODE_SHIFT);
}
/* First, check for errors */
ret = wm831x_reg_read(wm831x, WM831X_DCDC_UV_STATUS); if (ret < 0) return ret;
if (ret & (1 << rdev_get_id(rdev))) {
dev_dbg(wm831x->dev, "DCDC%d under voltage\n",
rdev_get_id(rdev) + 1); return REGULATOR_STATUS_ERROR;
}
/* DCDC1 and DCDC2 can additionally detect high voltage/current */ if (rdev_get_id(rdev) < 2) { if (ret & (WM831X_DC1_OV_STS << rdev_get_id(rdev))) {
dev_dbg(wm831x->dev, "DCDC%d over voltage\n",
rdev_get_id(rdev) + 1); return REGULATOR_STATUS_ERROR;
}
if (ret & (WM831X_DC1_HC_STS << rdev_get_id(rdev))) {
dev_dbg(wm831x->dev, "DCDC%d over current\n",
rdev_get_id(rdev) + 1); return REGULATOR_STATUS_ERROR;
}
}
/* Is the regulator on? */
ret = wm831x_reg_read(wm831x, WM831X_DCDC_STATUS); if (ret < 0) return ret; if (!(ret & (1 << rdev_get_id(rdev)))) return REGULATOR_STATUS_OFF;
/* TODO: When we handle hardware control modes so we can report the
* current mode. */ return REGULATOR_STATUS_ON;
}
/* Should wait for DVS state change to be asserted if we have * a GPIO for it, for now assume the device is configured * for the fastest possible transition.
*/
/* If this value is already set then do a GPIO update if we can */ if (dcdc->dvs_gpiod && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0);
if (dcdc->dvs_gpiod && dcdc->dvs_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 1);
/* Always set the ON status to the minimum voltage */
ret = wm831x_set_bits(wm831x, on_reg, WM831X_DC1_ON_VSEL_MASK, vsel); if (ret < 0) return ret;
dcdc->on_vsel = vsel;
if (!dcdc->dvs_gpiod) return ret;
/* Kick the voltage transition now */
ret = wm831x_buckv_set_dvs(rdev, 0); if (ret < 0) return ret;
/* * If this VSEL is higher than the last one we've seen then * remember it as the DVS VSEL. This is optimised for CPUfreq * usage where we want to get to the highest voltage very * quickly.
*/ if (vsel > dcdc->dvs_vsel) {
ret = wm831x_set_bits(wm831x, dvs_reg,
WM831X_DC1_DVS_VSEL_MASK,
vsel); if (ret == 0)
dcdc->dvs_vsel = vsel; else
dev_warn(wm831x->dev, "Failed to set DCDC DVS VSEL: %d\n", ret);
}
/* * Set up DVS control. We just log errors since we can still run * (with reduced performance) if we fail.
*/ staticvoid wm831x_buckv_dvs_init(struct platform_device *pdev, struct wm831x_dcdc *dcdc, struct wm831x_buckv_pdata *pdata)
{ struct wm831x *wm831x = dcdc->wm831x; int ret;
u16 ctrl;
if (!pdata) return;
/* gpiolib won't let us read the GPIO status so pick the higher * of the two existing voltages so we take it as platform data.
*/
dcdc->dvs_gpio_state = pdata->dvs_init_state;
dcdc->dvs_gpiod = devm_gpiod_get(&pdev->dev, "dvs",
dcdc->dvs_gpio_state ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW); if (IS_ERR(dcdc->dvs_gpiod)) {
dev_err(wm831x->dev, "Failed to get %s DVS GPIO: %ld\n",
dcdc->name, PTR_ERR(dcdc->dvs_gpiod)); return;
}
switch (pdata->dvs_control_src) { case 1:
ctrl = 2 << WM831X_DC1_DVS_SRC_SHIFT; break; case 2:
ctrl = 3 << WM831X_DC1_DVS_SRC_SHIFT; break; default:
dev_err(wm831x->dev, "Invalid DVS control source %d for %s\n",
pdata->dvs_control_src, dcdc->name); return;
}
/* If DVS_VSEL is set to the minimum value then raise it to ON_VSEL * to make bootstrapping a bit smoother.
*/ if (!dcdc->dvs_vsel) {
ret = wm831x_set_bits(wm831x,
dcdc->base + WM831X_DCDC_DVS_CONTROL,
WM831X_DC1_DVS_VSEL_MASK, dcdc->on_vsel); if (ret == 0)
dcdc->dvs_vsel = dcdc->on_vsel; else
dev_warn(wm831x->dev, "Failed to set DVS_VSEL: %d\n",
ret);
}
ret = wm831x_set_bits(wm831x, dcdc->base + WM831X_DCDC_DVS_CONTROL,
WM831X_DC1_DVS_SRC_MASK, ctrl); if (ret < 0) {
dev_err(wm831x->dev, "Failed to set %s DVS source: %d\n",
dcdc->name, ret);
}
}
dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), GFP_KERNEL); if (!dcdc) return -ENOMEM;
dcdc->wm831x = wm831x;
/* For current parts this is correct; probably need to revisit * in future.
*/
snprintf(dcdc->name, sizeof(dcdc->name), "EPE%d", id + 1);
dcdc->desc.name = dcdc->name;
dcdc->desc.id = id + WM831X_EPE_BASE; /* Offset in DCDC registers */
dcdc->desc.ops = &wm831x_epe_ops;
dcdc->desc.type = REGULATOR_VOLTAGE;
dcdc->desc.owner = THIS_MODULE;
dcdc->desc.enable_reg = WM831X_DCDC_ENABLE;
dcdc->desc.enable_mask = 1 << dcdc->desc.id;
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.