Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2020 ROHM Semiconductors #include <linux/errno.h> #include <linux/mfd/rohm-generic.h> #include <linux/module.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> 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 <matti.vaittinen@fi.rohmeurope.com>"); MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); |