staticint bd9576_set_limit(conststruct linear_range *r, int num_ranges, struct regmap *regmap, int reg, int mask, int lim)
{ int ret; bool found; int sel = 0;
if (lim) {
ret = linear_range_get_selector_low_array(r, num_ranges,
lim, &sel, &found); if (ret) return ret;
if (!found)
dev_warn(regmap_get_device(regmap), "limit %d out of range. Setting lower\n",
lim);
}
if (r->ocw_rfet) {
range = voutS1_ocw_ranges;
num_ranges = ARRAY_SIZE(voutS1_ocw_ranges);
rfet = r->ocw_rfet / 1000;
} else {
range = voutS1_ocw_ranges_internal;
num_ranges = ARRAY_SIZE(voutS1_ocw_ranges_internal); /* Internal values are already micro-amperes */
rfet = 1000;
}
/* We abuse uvd fields for OCW on VoutS1 */ if (r->uvd_notif) { /* * If both warning and error are requested, prioritize * ERROR configuration
*/ if (check_ocp_flag_mismatch(rdev, severity, r)) return 0;
} else { bool warn = severity == REGULATOR_SEVERITY_WARN;
bd9576_fill_ocp_flags(r, warn);
}
}
/* * limits are given in uA, rfet is mOhm * Divide lim_uA by 1000 to get Vfet in uV. * (We expect both Rfet and limit uA to be magnitude of hundreds of * milli Amperes & milli Ohms => we should still have decent accuracy)
*/
Vfet = lim_uA/1000 * rfet;
staticint bd9576_set_uvp(struct regulator_dev *rdev, int lim_uV, int severity, bool enable)
{ struct bd957x_data *d; struct bd957x_regulator_data *r; int mask, reg;
if (severity == REGULATOR_SEVERITY_PROT) { if (!enable || lim_uV) return -EINVAL; return 0;
}
/* * BD9576 has enable control as a special value in limit reg. Can't * set limit but keep feature disabled or enable W/O given limit.
*/ if ((lim_uV && !enable) || (!lim_uV && enable)) return -EINVAL;
r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
d = rdev_get_drvdata(rdev);
mask = r->xvd_mask;
reg = r->uvd_reg; /* * Check that there is no mismatch for what the detection IRQs are to * be used.
*/ if (r->uvd_notif) { if (check_uvd_flag_mismatch(rdev, severity, r)) return 0;
} else {
bd9576_fill_uvd_flags(r, severity == REGULATOR_SEVERITY_WARN);
}
staticint bd9576_set_ovp(struct regulator_dev *rdev, int lim_uV, int severity, bool enable)
{ struct bd957x_data *d; struct bd957x_regulator_data *r; int mask, reg;
if (severity == REGULATOR_SEVERITY_PROT) { if (!enable || lim_uV) return -EINVAL; return 0;
}
/* * BD9576 has enable control as a special value in limit reg. Can't * set limit but keep feature disabled or enable W/O given limit.
*/ if ((lim_uV && !enable) || (!lim_uV && enable)) return -EINVAL;
r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
d = rdev_get_drvdata(rdev);
mask = r->xvd_mask;
reg = r->ovd_reg; /* * Check that there is no mismatch for what the detection IRQs are to * be used.
*/ if (r->ovd_notif) { if (check_ovd_flag_mismatch(rdev, severity, r)) return 0;
} else {
bd9576_fill_ovd_flags(r, severity == REGULATOR_SEVERITY_WARN);
}
staticint bd9576_set_tw(struct regulator_dev *rdev, int lim, int severity, bool enable)
{ struct bd957x_data *d; struct bd957x_regulator_data *r; int i;
/* * BD9576MUF has fixed temperature limits * The detection can only be enabled/disabled
*/ if (lim) return -EINVAL;
/* Protection can't be disabled */ if (severity == REGULATOR_SEVERITY_PROT) { if (!enable) return -EINVAL; else return 0;
}
r = container_of(rdev->desc, struct bd957x_regulator_data, desc);
d = rdev_get_drvdata(rdev);
/* * Check that there is no mismatch for what the detection IRQs are to * be used.
*/ if (r->temp_notif) if (check_temp_flag_mismatch(rdev, severity, r)) return 0;
if (enable) return regmap_update_bits(d->regmap, BD957X_REG_INT_THERM_MASK,
BD9576_THERM_IRQ_MASK_TW, 0);
/* * If any of the regulators is interested in thermal warning we keep IRQ * enabled.
*/ for (i = 0; i < BD9576_NUM_REGULATORS; i++) if (d->regulator_data[i].temp_notif) return 0;
staticint bd9576_renable(struct regulator_irq_data *rid, int reg, int mask)
{ int val, ret; struct bd957x_data *d = (struct bd957x_data *)rid->data;
ret = regmap_read(d->regmap, reg, &val); if (ret) return REGULATOR_FAILED_RETRY;
if (rid->opaque && rid->opaque == (val & mask)) { /* * It seems we stil have same status. Ack and return * information that we are still out of limits and core * should not enable IRQ
*/
regmap_write(d->regmap, reg, mask & val); return REGULATOR_ERROR_ON;
}
rid->opaque = 0; /* * Status was changed. Either prolem was solved or we have new issues. * Let's re-enable IRQs and be prepared to report problems again
*/ return REGULATOR_ERROR_CLEARED;
}
ret = regmap_read(d->regmap, BD957X_REG_INT_UVD_STAT, &val); if (ret) return REGULATOR_FAILED_RETRY;
*dev_mask = 0;
rid->opaque = val & UVD_IRQ_VALID_MASK;
/* * Go through the set status bits and report either error or warning * to the notifier depending on what was flagged in DT
*/
*dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
*dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1); /* * We (ab)use the uvd for OCW notification. DT parsing should * have added correct OCW flag to uvd_notif and uvd_err for S1
*/
*dev_mask |= ((val & BD9576_UVD_IRQ_MASK_VOUTS1_OCW) >> 1);
ret = regmap_read(d->regmap, BD957X_REG_INT_OVD_STAT, &val); if (ret) return REGULATOR_FAILED_RETRY;
rid->opaque = val & OVD_IRQ_VALID_MASK;
*dev_mask = 0;
if (!(val & OVD_IRQ_VALID_MASK)) return 0;
*dev_mask = val & BD9576_xVD_IRQ_MASK_VOUT1TO4; /* There is 1 bit gap in register after Vout1 .. Vout4 statuses */
*dev_mask |= ((val & BD9576_xVD_IRQ_MASK_VOUTL1) >> 1);
/* VOUT1 enable state judged by VOUT1_EN pin */ /* See if we have GPIO defined */
en = devm_fwnode_gpiod_get(&pdev->dev,
dev_fwnode(pdev->dev.parent), "rohm,vout1-en", GPIOD_OUT_LOW, "vout1-en");
/* VOUT1_OPS gpio ctrl */ /* * Regulator core prioritizes the ena_gpio over * enable/disable/is_enabled callbacks so no need to clear them * even if GPIO is used. So, we can still use same ops. * * In theory it is possible someone wants to set vout1-en LOW * during OTP loading and set VOUT1 to be controlled by GPIO - * but control the GPIO from some where else than this driver. * For that to work we should unset the is_enabled callback * here. * * I believe such case where rohm,vout1-en-low is set and * vout1-en-gpios is not is likely to be a misconfiguration. * So let's just err out for now.
*/ if (!IS_ERR(en))
config.ena_gpiod = en; else return dev_err_probe(&pdev->dev, PTR_ERR(en), "Failed to get VOUT1 control GPIO\n");
}
/* * If more than one PMIC needs to be controlled by same processor then * allocate the regulator data array here and use bd9576_regulators as * template. At the moment I see no such use-case so I spare some * bytes and use bd9576_regulators directly for non-constant configs * like DDR voltage selection.
*/
platform_set_drvdata(pdev, ic_data);
ddr_sel = device_property_read_bool(pdev->dev.parent, "rohm,ddr-sel-low"); if (ddr_sel)
ic_data->regulator_data[2].desc.fixed_uV = 1350000; else
ic_data->regulator_data[2].desc.fixed_uV = 1500000;
r->rdev = devm_regulator_register(&pdev->dev, desc,
&config); if (IS_ERR(r->rdev)) return dev_err_probe(&pdev->dev, PTR_ERR(r->rdev), "failed to register %s regulator\n",
desc->name); /* * Clear the VOUT1 GPIO setting - rest of the regulators do not * support GPIO control
*/
config.ena_gpiod = NULL;
if (!may_have_irqs) continue;
rdevs[i] = r->rdev; if (i < BD957X_VOUTS1)
ovd_devs[i] = r->rdev;
} if (may_have_irqs) { void *ret; /* * We can add both the possible error and warning flags here * because the core uses these only for status clearing and * if we use warnings - errors are always clear and the other * way around. We can also add CURRENT flag for all regulators * because it is never set if it is not supported. Same applies * to setting UVD for VoutS1 - it is not accidentally cleared * as it is never set.
*/ int uvd_errs = REGULATOR_ERROR_UNDER_VOLTAGE |
REGULATOR_ERROR_UNDER_VOLTAGE_WARN |
REGULATOR_ERROR_OVER_CURRENT |
REGULATOR_ERROR_OVER_CURRENT_WARN; int ovd_errs = REGULATOR_ERROR_OVER_VOLTAGE_WARN |
REGULATOR_ERROR_REGULATION_OUT; int temp_errs = REGULATOR_ERROR_OVER_TEMP |
REGULATOR_ERROR_OVER_TEMP_WARN; int irq;
/* Register notifiers - can fail if IRQ is not given */
ret = devm_regulator_irq_helper(&pdev->dev, &bd9576_notif_uvd,
irq, 0, uvd_errs, NULL,
&rdevs[0],
BD9576_NUM_REGULATORS); if (IS_ERR(ret)) { if (PTR_ERR(ret) == -EPROBE_DEFER) return -EPROBE_DEFER;
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.