1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2020 ROHM Semiconductors 3 4 #include <linux/errno.h> 5 #include <linux/mfd/rohm-generic.h> 6 #include <linux/module.h> 7 #include <linux/of.h> 8 #include <linux/regmap.h> 9 #include <linux/regulator/driver.h> 10 11 static int set_dvs_level(const struct regulator_desc *desc, 12 struct device_node *np, struct regmap *regmap, 13 char *prop, unsigned int reg, unsigned int mask, 14 unsigned int omask, unsigned int oreg) 15 { 16 int ret, i; 17 uint32_t uv; 18 19 ret = of_property_read_u32(np, prop, &uv); 20 if (ret) { 21 if (ret != -EINVAL) 22 return ret; 23 return 0; 24 } 25 /* If voltage is set to 0 => disable */ 26 if (uv == 0) { 27 if (omask) 28 return regmap_update_bits(regmap, oreg, omask, 0); 29 } 30 /* Some setups don't allow setting own voltage but do allow enabling */ 31 if (!mask) { 32 if (omask) 33 return regmap_update_bits(regmap, oreg, omask, omask); 34 35 return -EINVAL; 36 } 37 for (i = 0; i < desc->n_voltages; i++) { 38 /* NOTE to next hacker - Does not support pickable ranges */ 39 if (desc->linear_range_selectors_bitfield) 40 return -EINVAL; 41 if (desc->n_linear_ranges) 42 ret = regulator_desc_list_voltage_linear_range(desc, i); 43 else 44 ret = regulator_desc_list_voltage_linear(desc, i); 45 if (ret < 0) 46 continue; 47 if (ret == uv) { 48 i <<= ffs(desc->vsel_mask) - 1; 49 50 ret = regmap_update_bits(regmap, reg, mask, i); 51 if (omask && !ret) 52 ret = regmap_update_bits(regmap, oreg, omask, 53 omask); 54 break; 55 } 56 } 57 if (i == desc->n_voltages) 58 pr_warn("Unsupported %s voltage %u\n", prop, uv); 59 60 return ret; 61 } 62 63 int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, 64 struct device_node *np, 65 const struct regulator_desc *desc, 66 struct regmap *regmap) 67 { 68 int i, ret = 0; 69 char *prop; 70 unsigned int reg, mask, omask, oreg = desc->enable_reg; 71 72 for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) { 73 int bit; 74 75 bit = BIT(i); 76 if (dvs->level_map & bit) { 77 switch (bit) { 78 case ROHM_DVS_LEVEL_RUN: 79 prop = "rohm,dvs-run-voltage"; 80 reg = dvs->run_reg; 81 mask = dvs->run_mask; 82 omask = dvs->run_on_mask; 83 break; 84 case ROHM_DVS_LEVEL_IDLE: 85 prop = "rohm,dvs-idle-voltage"; 86 reg = dvs->idle_reg; 87 mask = dvs->idle_mask; 88 omask = dvs->idle_on_mask; 89 break; 90 case ROHM_DVS_LEVEL_SUSPEND: 91 prop = "rohm,dvs-suspend-voltage"; 92 reg = dvs->suspend_reg; 93 mask = dvs->suspend_mask; 94 omask = dvs->suspend_on_mask; 95 break; 96 case ROHM_DVS_LEVEL_LPSR: 97 prop = "rohm,dvs-lpsr-voltage"; 98 reg = dvs->lpsr_reg; 99 mask = dvs->lpsr_mask; 100 omask = dvs->lpsr_on_mask; 101 break; 102 case ROHM_DVS_LEVEL_SNVS: 103 prop = "rohm,dvs-snvs-voltage"; 104 reg = dvs->snvs_reg; 105 mask = dvs->snvs_mask; 106 omask = dvs->snvs_on_mask; 107 break; 108 default: 109 return -EINVAL; 110 } 111 ret = set_dvs_level(desc, np, regmap, prop, reg, mask, 112 omask, oreg); 113 } 114 } 115 return ret; 116 } 117 EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); 118 119 /* 120 * Few ROHM PMIC ICs have constrains on voltage changing: 121 * BD71837 - only buck 1-4 voltages can be changed when they are enabled. 122 * Other bucks and all LDOs must be disabled when voltage is changed. 123 * BD96801 - LDO voltage levels can be changed when LDOs are disabled. 124 */ 125 int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, 126 unsigned int sel) 127 { 128 if (rdev->desc->ops->is_enabled(rdev)) 129 return -EBUSY; 130 131 return regulator_set_voltage_sel_regmap(rdev, sel); 132 } 133 EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); 134 135 MODULE_LICENSE("GPL v2"); 136 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 137 MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); 138