aboutsummaryrefslogtreecommitdiff
path: root/drivers/regulator/rohm-regulator.c
blob: f97a9a51ee7650bddfc16cbd972847244d1d3b91 (plain)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// 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;
			case ROHM_DVS_LEVEL_SNVS:
				prop = "rohm,dvs-snvs-voltage";
				reg = dvs->snvs_reg;
				mask = dvs->snvs_mask;
				omask = dvs->snvs_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);

/*
 * Few ROHM PMIC ICs have constrains on voltage changing:
 * BD71837 - only buck 1-4 voltages can be changed when they are enabled.
 * Other bucks and all LDOs must be disabled when voltage is changed.
 * BD96801 - LDO voltage levels can be changed when LDOs are disabled.
 */
int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
					      unsigned int sel)
{
	if (rdev->desc->ops->is_enabled(rdev))
		return -EBUSY;

	return regulator_set_voltage_sel_regmap(rdev, sel);
}
EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");