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 | } |
Matti Vaittinen | 9cf37ce | 2021-04-05 14:43:26 +0300 | [diff] [blame] | 25 | /* If voltage is set to 0 => disable */ |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 26 | if (uv == 0) { |
| 27 | if (omask) |
| 28 | return regmap_update_bits(regmap, oreg, omask, 0); |
| 29 | } |
Matti Vaittinen | 9cf37ce | 2021-04-05 14:43:26 +0300 | [diff] [blame] | 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 | } |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 37 | for (i = 0; i < desc->n_voltages; i++) { |
Matti Vaittinen | 9cf37ce | 2021-04-05 14:43:26 +0300 | [diff] [blame] | 38 | /* NOTE to next hacker - Does not support pickable ranges */ |
| 39 | if (desc->linear_range_selectors) |
| 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); |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 45 | if (ret < 0) |
| 46 | continue; |
| 47 | if (ret == uv) { |
| 48 | i <<= ffs(desc->vsel_mask) - 1; |
| 49 | ret = regmap_update_bits(regmap, reg, mask, i); |
| 50 | if (omask && !ret) |
| 51 | ret = regmap_update_bits(regmap, oreg, omask, |
| 52 | omask); |
| 53 | break; |
| 54 | } |
| 55 | } |
| 56 | return ret; |
| 57 | } |
| 58 | |
| 59 | int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs, |
| 60 | struct device_node *np, |
| 61 | const struct regulator_desc *desc, |
| 62 | struct regmap *regmap) |
| 63 | { |
| 64 | int i, ret = 0; |
| 65 | char *prop; |
| 66 | unsigned int reg, mask, omask, oreg = desc->enable_reg; |
| 67 | |
Matti Vaittinen | c294554 | 2021-02-12 10:00:23 +0200 | [diff] [blame] | 68 | for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) { |
| 69 | int bit; |
| 70 | |
| 71 | bit = BIT(i); |
| 72 | if (dvs->level_map & bit) { |
| 73 | switch (bit) { |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 74 | case ROHM_DVS_LEVEL_RUN: |
| 75 | prop = "rohm,dvs-run-voltage"; |
| 76 | reg = dvs->run_reg; |
| 77 | mask = dvs->run_mask; |
| 78 | omask = dvs->run_on_mask; |
| 79 | break; |
| 80 | case ROHM_DVS_LEVEL_IDLE: |
| 81 | prop = "rohm,dvs-idle-voltage"; |
| 82 | reg = dvs->idle_reg; |
| 83 | mask = dvs->idle_mask; |
| 84 | omask = dvs->idle_on_mask; |
| 85 | break; |
| 86 | case ROHM_DVS_LEVEL_SUSPEND: |
| 87 | prop = "rohm,dvs-suspend-voltage"; |
| 88 | reg = dvs->suspend_reg; |
| 89 | mask = dvs->suspend_mask; |
| 90 | omask = dvs->suspend_on_mask; |
| 91 | break; |
| 92 | case ROHM_DVS_LEVEL_LPSR: |
| 93 | prop = "rohm,dvs-lpsr-voltage"; |
| 94 | reg = dvs->lpsr_reg; |
| 95 | mask = dvs->lpsr_mask; |
| 96 | omask = dvs->lpsr_on_mask; |
| 97 | break; |
Matti Vaittinen | 80a711706 | 2021-04-05 14:43:44 +0300 | [diff] [blame] | 98 | case ROHM_DVS_LEVEL_SNVS: |
| 99 | prop = "rohm,dvs-snvs-voltage"; |
| 100 | reg = dvs->snvs_reg; |
| 101 | mask = dvs->snvs_mask; |
| 102 | omask = dvs->snvs_on_mask; |
| 103 | break; |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 104 | default: |
| 105 | return -EINVAL; |
| 106 | } |
| 107 | ret = set_dvs_level(desc, np, regmap, prop, reg, mask, |
| 108 | omask, oreg); |
| 109 | } |
| 110 | } |
| 111 | return ret; |
| 112 | } |
| 113 | EXPORT_SYMBOL(rohm_regulator_set_dvs_levels); |
| 114 | |
Matti Vaittinen | 8b6e885 | 2021-11-18 13:48:47 +0200 | [diff] [blame] | 115 | /* |
| 116 | * Few ROHM PMIC ICs have constrains on voltage changing: |
| 117 | * BD71837 - only buck 1-4 voltages can be changed when they are enabled. |
| 118 | * Other bucks and all LDOs must be disabled when voltage is changed. |
| 119 | * BD96801 - LDO voltage levels can be changed when LDOs are disabled. |
| 120 | */ |
| 121 | int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev, |
| 122 | unsigned int sel) |
| 123 | { |
| 124 | if (rdev->desc->ops->is_enabled(rdev)) |
| 125 | return -EBUSY; |
| 126 | |
| 127 | return regulator_set_voltage_sel_regmap(rdev, sel); |
| 128 | } |
| 129 | EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted); |
| 130 | |
Matti Vaittinen | 21b7215 | 2020-01-20 15:44:45 +0200 | [diff] [blame] | 131 | MODULE_LICENSE("GPL v2"); |
| 132 | MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); |
| 133 | MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers"); |