^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) // Copyright (C) 2020 ROHM Semiconductors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/mfd/rohm-generic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/regulator/driver.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) static int set_dvs_level(const struct regulator_desc *desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct device_node *np, struct regmap *regmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) char *prop, unsigned int reg, unsigned int mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) unsigned int omask, unsigned int oreg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) uint32_t uv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) ret = of_property_read_u32(np, prop, &uv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) if (ret != -EINVAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (uv == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) if (omask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) return regmap_update_bits(regmap, oreg, omask, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) for (i = 0; i < desc->n_voltages; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) ret = regulator_desc_list_voltage_linear_range(desc, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (ret == uv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) i <<= ffs(desc->vsel_mask) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) ret = regmap_update_bits(regmap, reg, mask, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (omask && !ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) ret = regmap_update_bits(regmap, oreg, omask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) omask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) struct device_node *np,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) const struct regulator_desc *desc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct regmap *regmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) char *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) unsigned int reg, mask, omask, oreg = desc->enable_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) int bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) bit = BIT(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (dvs->level_map & bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) switch (bit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) case ROHM_DVS_LEVEL_RUN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) prop = "rohm,dvs-run-voltage";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) reg = dvs->run_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) mask = dvs->run_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) omask = dvs->run_on_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) case ROHM_DVS_LEVEL_IDLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) prop = "rohm,dvs-idle-voltage";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) reg = dvs->idle_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) mask = dvs->idle_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) omask = dvs->idle_on_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) case ROHM_DVS_LEVEL_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) prop = "rohm,dvs-suspend-voltage";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) reg = dvs->suspend_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) mask = dvs->suspend_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) omask = dvs->suspend_on_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) case ROHM_DVS_LEVEL_LPSR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) prop = "rohm,dvs-lpsr-voltage";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) reg = dvs->lpsr_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) mask = dvs->lpsr_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) omask = dvs->lpsr_on_mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) omask, oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");