Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 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"); |