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 26 if (uv == 0) { 27 if (omask) 28 return regmap_update_bits(regmap, oreg, omask, 0); 29 } 30 for (i = 0; i < desc->n_voltages; i++) { 31 ret = regulator_desc_list_voltage_linear_range(desc, i); 32 if (ret < 0) 33 continue; 34 if (ret == uv) { 35 i <<= ffs(desc->vsel_mask) - 1; 36 ret = regmap_update_bits(regmap, reg, mask, i); 37 if (omask && !ret) 38 ret = regmap_update_bits(regmap, oreg, omask, 39 omask); 40 break; 41 } 42 } 43 return ret; 44 } 45 46 int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, 47 struct device_node *np, 48 const struct regulator_desc *desc, 49 struct regmap *regmap) 50 { 51 int i, ret = 0; 52 char *prop; 53 unsigned int reg, mask, omask, oreg = desc->enable_reg; 54 55 for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) { 56 int bit; 57 58 bit = BIT(i); 59 if (dvs->level_map & bit) { 60 switch (bit) { 61 case ROHM_DVS_LEVEL_RUN: 62 prop = "rohm,dvs-run-voltage"; 63 reg = dvs->run_reg; 64 mask = dvs->run_mask; 65 omask = dvs->run_on_mask; 66 break; 67 case ROHM_DVS_LEVEL_IDLE: 68 prop = "rohm,dvs-idle-voltage"; 69 reg = dvs->idle_reg; 70 mask = dvs->idle_mask; 71 omask = dvs->idle_on_mask; 72 break; 73 case ROHM_DVS_LEVEL_SUSPEND: 74 prop = "rohm,dvs-suspend-voltage"; 75 reg = dvs->suspend_reg; 76 mask = dvs->suspend_mask; 77 omask = dvs->suspend_on_mask; 78 break; 79 case ROHM_DVS_LEVEL_LPSR: 80 prop = "rohm,dvs-lpsr-voltage"; 81 reg = dvs->lpsr_reg; 82 mask = dvs->lpsr_mask; 83 omask = dvs->lpsr_on_mask; 84 break; 85 default: 86 return -EINVAL; 87 } 88 ret = set_dvs_level(desc, np, regmap, prop, reg, mask, 89 omask, oreg); 90 } 91 } 92 return ret; 93 } 94 EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); 95 96 MODULE_LICENSE("GPL v2"); 97 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 98 MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); 99