Skip to content

Commit f0168a9

Browse files
Keerthyjbroonie
authored andcommitted
regulator: lp87565: Add support for lp87565 PMIC regulators
The regulators set consists of 4 BUCKs. The output voltages are configurable and are meant to supply power to the main processor and other components. The ramp delay is configurable for all BUCKs. The BUCKs can be configured in single phase or multiphase modes. Signed-off-by: Keerthy <[email protected]> Signed-off-by: Mark Brown <[email protected]>
1 parent 2ea659a commit f0168a9

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

drivers/regulator/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,14 @@ config REGULATOR_LP8755
365365
chip contains six step-down DC/DC converters which can support
366366
9 mode multiphase configuration.
367367

368+
config REGULATOR_LP87565
369+
tristate "TI LP87565 Power regulators"
370+
depends on MFD_TI_LP87565 && OF
371+
help
372+
This driver supports LP87565 voltage regulator chips. LP87565
373+
provides four step-down converters. It supports software based
374+
voltage control for different voltage domains
375+
368376
config REGULATOR_LP8788
369377
tristate "TI LP8788 Power Regulators"
370378
depends on MFD_LP8788

drivers/regulator/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
4646
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
4747
obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
4848
obj-$(CONFIG_REGULATOR_LP873X) += lp873x-regulator.o
49+
obj-$(CONFIG_REGULATOR_LP87565) += lp87565-regulator.o
4950
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o
5051
obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
5152
obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o

drivers/regulator/lp87565-regulator.c

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*
2+
* Regulator driver for LP87565 PMIC
3+
*
4+
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License as published by the
8+
* Free Software Foundation; either version 2 of the License, or (at your
9+
* option) any later version.
10+
*/
11+
12+
#include <linux/module.h>
13+
#include <linux/platform_device.h>
14+
#include <linux/regmap.h>
15+
16+
#include <linux/mfd/lp87565.h>
17+
18+
#define LP87565_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \
19+
_delay, _lr, _cr) \
20+
[_id] = { \
21+
.desc = { \
22+
.name = _name, \
23+
.supply_name = _of "-in", \
24+
.id = _id, \
25+
.of_match = of_match_ptr(_of), \
26+
.regulators_node = of_match_ptr("regulators"),\
27+
.ops = &_ops, \
28+
.n_voltages = _n, \
29+
.type = REGULATOR_VOLTAGE, \
30+
.owner = THIS_MODULE, \
31+
.vsel_reg = _vr, \
32+
.vsel_mask = _vm, \
33+
.enable_reg = _er, \
34+
.enable_mask = _em, \
35+
.ramp_delay = _delay, \
36+
.linear_ranges = _lr, \
37+
.n_linear_ranges = ARRAY_SIZE(_lr), \
38+
}, \
39+
.ctrl2_reg = _cr, \
40+
}
41+
42+
struct lp87565_regulator {
43+
struct regulator_desc desc;
44+
unsigned int ctrl2_reg;
45+
};
46+
47+
static const struct lp87565_regulator regulators[];
48+
49+
static const struct regulator_linear_range buck0_1_2_3_ranges[] = {
50+
REGULATOR_LINEAR_RANGE(500000, 0x0, 0x17, 10000),
51+
REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000),
52+
REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000),
53+
};
54+
55+
static unsigned int lp87565_buck_ramp_delay[] = {
56+
30000, 15000, 10000, 7500, 3800, 1900, 940, 470
57+
};
58+
59+
/* LP87565 BUCK current limit */
60+
static const unsigned int lp87565_buck_uA[] = {
61+
1500000, 2000000, 2500000, 3000000, 3500000, 4000000, 4500000, 5000000,
62+
};
63+
64+
static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev,
65+
int ramp_delay)
66+
{
67+
int id = rdev_get_id(rdev);
68+
struct lp87565 *lp87565 = rdev_get_drvdata(rdev);
69+
unsigned int reg;
70+
int ret;
71+
72+
if (ramp_delay <= 470)
73+
reg = 7;
74+
else if (ramp_delay <= 940)
75+
reg = 6;
76+
else if (ramp_delay <= 1900)
77+
reg = 5;
78+
else if (ramp_delay <= 3800)
79+
reg = 4;
80+
else if (ramp_delay <= 7500)
81+
reg = 3;
82+
else if (ramp_delay <= 10000)
83+
reg = 2;
84+
else if (ramp_delay <= 15000)
85+
reg = 1;
86+
else
87+
reg = 0;
88+
89+
ret = regmap_update_bits(lp87565->regmap, regulators[id].ctrl2_reg,
90+
LP87565_BUCK_CTRL_2_SLEW_RATE,
91+
reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE));
92+
if (ret) {
93+
dev_err(lp87565->dev, "SLEW RATE write failed: %d\n", ret);
94+
return ret;
95+
}
96+
97+
rdev->constraints->ramp_delay = lp87565_buck_ramp_delay[reg];
98+
99+
return 0;
100+
}
101+
102+
static int lp87565_buck_set_current_limit(struct regulator_dev *rdev,
103+
int min_uA, int max_uA)
104+
{
105+
int id = rdev_get_id(rdev);
106+
struct lp87565 *lp87565 = rdev_get_drvdata(rdev);
107+
int i;
108+
109+
for (i = ARRAY_SIZE(lp87565_buck_uA) - 1; i >= 0; i--) {
110+
if (lp87565_buck_uA[i] >= min_uA &&
111+
lp87565_buck_uA[i] <= max_uA)
112+
return regmap_update_bits(lp87565->regmap,
113+
regulators[id].ctrl2_reg,
114+
LP87565_BUCK_CTRL_2_ILIM,
115+
i << __ffs(LP87565_BUCK_CTRL_2_ILIM));
116+
}
117+
118+
return -EINVAL;
119+
}
120+
121+
static int lp87565_buck_get_current_limit(struct regulator_dev *rdev)
122+
{
123+
int id = rdev_get_id(rdev);
124+
struct lp87565 *lp87565 = rdev_get_drvdata(rdev);
125+
int ret;
126+
unsigned int val;
127+
128+
ret = regmap_read(lp87565->regmap, regulators[id].ctrl2_reg, &val);
129+
if (ret)
130+
return ret;
131+
132+
val = (val & LP87565_BUCK_CTRL_2_ILIM) >>
133+
__ffs(LP87565_BUCK_CTRL_2_ILIM);
134+
135+
return (val < ARRAY_SIZE(lp87565_buck_uA)) ?
136+
lp87565_buck_uA[val] : -EINVAL;
137+
}
138+
139+
/* Operations permitted on BUCK0, BUCK1 */
140+
static struct regulator_ops lp87565_buck_ops = {
141+
.is_enabled = regulator_is_enabled_regmap,
142+
.enable = regulator_enable_regmap,
143+
.disable = regulator_disable_regmap,
144+
.get_voltage_sel = regulator_get_voltage_sel_regmap,
145+
.set_voltage_sel = regulator_set_voltage_sel_regmap,
146+
.list_voltage = regulator_list_voltage_linear_range,
147+
.map_voltage = regulator_map_voltage_linear_range,
148+
.set_voltage_time_sel = regulator_set_voltage_time_sel,
149+
.set_ramp_delay = lp87565_buck_set_ramp_delay,
150+
.set_current_limit = lp87565_buck_set_current_limit,
151+
.get_current_limit = lp87565_buck_get_current_limit,
152+
};
153+
154+
static const struct lp87565_regulator regulators[] = {
155+
LP87565_REGULATOR("BUCK0", LP87565_BUCK_0, "buck0", lp87565_buck_ops,
156+
256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET,
157+
LP87565_REG_BUCK0_CTRL_1,
158+
LP87565_BUCK_CTRL_1_EN, 3800,
159+
buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2),
160+
LP87565_REGULATOR("BUCK1", LP87565_BUCK_1, "buck1", lp87565_buck_ops,
161+
256, LP87565_REG_BUCK1_VOUT, LP87565_BUCK_VSET,
162+
LP87565_REG_BUCK1_CTRL_1,
163+
LP87565_BUCK_CTRL_1_EN, 3800,
164+
buck0_1_2_3_ranges, LP87565_REG_BUCK1_CTRL_2),
165+
LP87565_REGULATOR("BUCK2", LP87565_BUCK_2, "buck2", lp87565_buck_ops,
166+
256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET,
167+
LP87565_REG_BUCK2_CTRL_1,
168+
LP87565_BUCK_CTRL_1_EN, 3800,
169+
buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2),
170+
LP87565_REGULATOR("BUCK3", LP87565_BUCK_3, "buck3", lp87565_buck_ops,
171+
256, LP87565_REG_BUCK3_VOUT, LP87565_BUCK_VSET,
172+
LP87565_REG_BUCK3_CTRL_1,
173+
LP87565_BUCK_CTRL_1_EN, 3800,
174+
buck0_1_2_3_ranges, LP87565_REG_BUCK3_CTRL_2),
175+
LP87565_REGULATOR("BUCK10", LP87565_BUCK_10, "buck10", lp87565_buck_ops,
176+
256, LP87565_REG_BUCK0_VOUT, LP87565_BUCK_VSET,
177+
LP87565_REG_BUCK0_CTRL_1,
178+
LP87565_BUCK_CTRL_1_EN, 3800,
179+
buck0_1_2_3_ranges, LP87565_REG_BUCK0_CTRL_2),
180+
LP87565_REGULATOR("BUCK23", LP87565_BUCK_23, "buck23", lp87565_buck_ops,
181+
256, LP87565_REG_BUCK2_VOUT, LP87565_BUCK_VSET,
182+
LP87565_REG_BUCK2_CTRL_1,
183+
LP87565_BUCK_CTRL_1_EN, 3800,
184+
buck0_1_2_3_ranges, LP87565_REG_BUCK2_CTRL_2),
185+
};
186+
187+
static int lp87565_regulator_probe(struct platform_device *pdev)
188+
{
189+
struct lp87565 *lp87565 = dev_get_drvdata(pdev->dev.parent);
190+
struct regulator_config config = { };
191+
struct regulator_dev *rdev;
192+
int i, min_idx = LP87565_BUCK_1, max_idx = LP87565_BUCK_3;
193+
194+
platform_set_drvdata(pdev, lp87565);
195+
196+
config.dev = &pdev->dev;
197+
config.dev->of_node = lp87565->dev->of_node;
198+
config.driver_data = lp87565;
199+
config.regmap = lp87565->regmap;
200+
201+
if (lp87565->dev_type == LP87565_DEVICE_TYPE_LP87565_Q1) {
202+
min_idx = LP87565_BUCK_10;
203+
max_idx = LP87565_BUCK_23;
204+
}
205+
206+
for (i = min_idx; i <= max_idx; i++) {
207+
rdev = devm_regulator_register(&pdev->dev, &regulators[i].desc,
208+
&config);
209+
if (IS_ERR(rdev)) {
210+
dev_err(lp87565->dev, "failed to register %s regulator\n",
211+
pdev->name);
212+
return PTR_ERR(rdev);
213+
}
214+
}
215+
216+
return 0;
217+
}
218+
219+
static const struct platform_device_id lp87565_regulator_id_table[] = {
220+
{ "lp87565-regulator", },
221+
{ "lp87565-q1-regulator", },
222+
{ /* sentinel */ }
223+
};
224+
MODULE_DEVICE_TABLE(platform, lp87565_regulator_id_table);
225+
226+
static struct platform_driver lp87565_regulator_driver = {
227+
.driver = {
228+
.name = "lp87565-pmic",
229+
},
230+
.probe = lp87565_regulator_probe,
231+
.id_table = lp87565_regulator_id_table,
232+
};
233+
module_platform_driver(lp87565_regulator_driver);
234+
235+
MODULE_AUTHOR("J Keerthy <[email protected]>");
236+
MODULE_DESCRIPTION("LP87565 voltage regulator driver");
237+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)