Commit | Line | Data |
---|---|---|
21b72156 MV |
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 | ||
c2945541 MV |
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) { | |
21b72156 MV |
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"); |