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_MAX && !ret; i++) { 56 if (dvs->level_map & (1 << i)) { 57 switch (i + 1) { 58 case ROHM_DVS_LEVEL_RUN: 59 prop = "rohm,dvs-run-voltage"; 60 reg = dvs->run_reg; 61 mask = dvs->run_mask; 62 omask = dvs->run_on_mask; 63 break; 64 case ROHM_DVS_LEVEL_IDLE: 65 prop = "rohm,dvs-idle-voltage"; 66 reg = dvs->idle_reg; 67 mask = dvs->idle_mask; 68 omask = dvs->idle_on_mask; 69 break; 70 case ROHM_DVS_LEVEL_SUSPEND: 71 prop = "rohm,dvs-suspend-voltage"; 72 reg = dvs->suspend_reg; 73 mask = dvs->suspend_mask; 74 omask = dvs->suspend_on_mask; 75 break; 76 case ROHM_DVS_LEVEL_LPSR: 77 prop = "rohm,dvs-lpsr-voltage"; 78 reg = dvs->lpsr_reg; 79 mask = dvs->lpsr_mask; 80 omask = dvs->lpsr_on_mask; 81 break; 82 default: 83 return -EINVAL; 84 } 85 ret = set_dvs_level(desc, np, regmap, prop, reg, mask, 86 omask, oreg); 87 } 88 } 89 return ret; 90 } 91 EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); 92 93 MODULE_LICENSE("GPL v2"); 94 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 95 MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); 96