// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020 ROHM Semiconductors #include #include #include #include #include #include static int set_dvs_level(const struct regulator_desc *desc, struct device_node *np, struct regmap *regmap, char *prop, unsigned int reg, unsigned int mask, unsigned int omask, unsigned int oreg) { int ret, i; uint32_t uv; ret = of_property_read_u32(np, prop, &uv); if (ret) { if (ret != -EINVAL) return ret; return 0; } /* If voltage is set to 0 => disable */ if (uv == 0) { if (omask) return regmap_update_bits(regmap, oreg, omask, 0); } /* Some setups don't allow setting own voltage but do allow enabling */ if (!mask) { if (omask) return regmap_update_bits(regmap, oreg, omask, omask); return -EINVAL; } for (i = 0; i < desc->n_voltages; i++) { /* NOTE to next hacker - Does not support pickable ranges */ if (desc->linear_range_selectors_bitfield) return -EINVAL; if (desc->n_linear_ranges) ret = regulator_desc_list_voltage_linear_range(desc, i); else ret = regulator_desc_list_voltage_linear(desc, i); if (ret < 0) continue; if (ret == uv) { i <<= ffs(desc->vsel_mask) - 1; ret = regmap_update_bits(regmap, reg, mask, i); if (omask && !ret) ret = regmap_update_bits(regmap, oreg, omask, omask); break; } } return ret; } int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, struct device_node *np, const struct regulator_desc *desc, struct regmap *regmap) { int i, ret = 0; char *prop; unsigned int reg, mask, omask, oreg = desc->enable_reg; for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) { int bit; bit = BIT(i); if (dvs->level_map & bit) { switch (bit) { case ROHM_DVS_LEVEL_RUN: prop = "rohm,dvs-run-voltage"; reg = dvs->run_reg; mask = dvs->run_mask; omask = dvs->run_on_mask; break; case ROHM_DVS_LEVEL_IDLE: prop = "rohm,dvs-idle-voltage"; reg = dvs->idle_reg; mask = dvs->idle_mask; omask = dvs->idle_on_mask; break; case ROHM_DVS_LEVEL_SUSPEND: prop = "rohm,dvs-suspend-voltage"; reg = dvs->suspend_reg; mask = dvs->suspend_mask; omask = dvs->suspend_on_mask; break; case ROHM_DVS_LEVEL_LPSR: prop = "rohm,dvs-lpsr-voltage"; reg = dvs->lpsr_reg; mask = dvs->lpsr_mask; omask = dvs->lpsr_on_mask; break; case ROHM_DVS_LEVEL_SNVS: prop = "rohm,dvs-snvs-voltage"; reg = dvs->snvs_reg; mask = dvs->snvs_mask; omask = dvs->snvs_on_mask; break; default: return -EINVAL; } ret = set_dvs_level(desc, np, regmap, prop, reg, mask, omask, oreg); } } return ret; } EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); /* * Few ROHM PMIC ICs have constrains on voltage changing: * BD71837 - only buck 1-4 voltages can be changed when they are enabled. * Other bucks and all LDOs must be disabled when voltage is changed. * BD96801 - LDO voltage levels can be changed when LDOs are disabled. */ int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, unsigned int sel) { if (rdev->desc->ops->is_enabled(rdev)) return -EBUSY; return regulator_set_voltage_sel_regmap(rdev, sel); } EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Matti Vaittinen "); MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");