]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blob - drivers/regulator/rohm-regulator.c
Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
[mirror_ubuntu-jammy-kernel.git] / drivers / regulator / rohm-regulator.c
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 /* If voltage is set to 0 => disable */
26 if (uv == 0) {
27 if (omask)
28 return regmap_update_bits(regmap, oreg, omask, 0);
29 }
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 }
37 for (i = 0; i < desc->n_voltages; i++) {
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);
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
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) {
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;
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;
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
115 MODULE_LICENSE("GPL v2");
116 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
117 MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");