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