Skip to content

Commit cf27b7d

Browse files
committed
regulator: Add support for TPS6287x
Merge series from Mårten Lindahl <marten.lindahl@axis.com>: This series adds basic support for TI's TPS62870/TPS62871/TPS62872/ TPS62873 high-frequency single-channel step-down converters with an I2C interface. The devices can operate in power save mode for maximum efficiency, or forced-PWM mode for best transient performance and lowest output voltage ripple. All chip variants have four output voltage ranges and the driver changes active range depending on the requested voltage setting. There are differences in the electrical characteristics and packaging between the variants, but the register interfaces are identical.
2 parents f050e56 + 7b0518f commit cf27b7d

4 files changed

Lines changed: 252 additions & 0 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/regulator/ti,tps62870.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: TI TPS62870/TPS62871/TPS62872/TPS62873 voltage regulator
8+
9+
maintainers:
10+
- Mårten Lindahl <marten.lindahl@axis.com>
11+
12+
allOf:
13+
- $ref: regulator.yaml#
14+
15+
properties:
16+
compatible:
17+
enum:
18+
- ti,tps62870
19+
- ti,tps62871
20+
- ti,tps62872
21+
- ti,tps62873
22+
23+
reg:
24+
maxItems: 1
25+
26+
regulator-initial-mode:
27+
enum: [ 1, 2 ]
28+
description: 1 - Forced PWM mode, 2 - Low power mode
29+
30+
required:
31+
- compatible
32+
- reg
33+
34+
unevaluatedProperties: false
35+
36+
examples:
37+
- |
38+
i2c {
39+
#address-cells = <1>;
40+
#size-cells = <0>;
41+
42+
regulator@41 {
43+
compatible = "ti,tps62873";
44+
reg = <0x41>;
45+
regulator-name = "+0.75V";
46+
regulator-min-microvolt = <400000>;
47+
regulator-max-microvolt = <1675000>;
48+
regulator-initial-mode = <1>;
49+
};
50+
};
51+
52+
...

drivers/regulator/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,17 @@ config REGULATOR_TPS6286X
13971397
high-frequency synchronous step-down converters with an I2C
13981398
interface.
13991399

1400+
config REGULATOR_TPS6287X
1401+
tristate "TI TPS6287x Power Regulator"
1402+
depends on I2C && OF
1403+
select REGMAP_I2C
1404+
help
1405+
This driver supports TPS6287x voltage regulator chips. These are
1406+
pin-to-pin high-frequency synchronous step-down dc-dc converters
1407+
with an I2C interface.
1408+
1409+
If built as a module it will be called tps6287x-regulator.
1410+
14001411
config REGULATOR_TPS65023
14011412
tristate "TI TPS65023 Power regulators"
14021413
depends on I2C

drivers/regulator/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o
163163
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
164164
obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o
165165
obj-$(CONFIG_REGULATOR_TPS6286X) += tps6286x-regulator.o
166+
obj-$(CONFIG_REGULATOR_TPS6287X) += tps6287x-regulator.o
166167
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
167168
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
168169
obj-$(CONFIG_REGULATOR_TPS65086) += tps65086-regulator.o
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2023 Axis Communications AB
4+
*
5+
* Driver for Texas Instruments TPS6287x PMIC.
6+
* Datasheet: https://www.ti.com/lit/ds/symlink/tps62873.pdf
7+
*/
8+
9+
#include <linux/err.h>
10+
#include <linux/i2c.h>
11+
#include <linux/module.h>
12+
#include <linux/of_device.h>
13+
#include <linux/regmap.h>
14+
#include <linux/regulator/of_regulator.h>
15+
#include <linux/regulator/machine.h>
16+
#include <linux/regulator/driver.h>
17+
#include <linux/bitfield.h>
18+
#include <linux/linear_range.h>
19+
20+
#define TPS6287X_VSET 0x00
21+
#define TPS6287X_CTRL1 0x01
22+
#define TPS6287X_CTRL1_VRAMP GENMASK(1, 0)
23+
#define TPS6287X_CTRL1_FPWMEN BIT(4)
24+
#define TPS6287X_CTRL1_SWEN BIT(5)
25+
#define TPS6287X_CTRL2 0x02
26+
#define TPS6287X_CTRL2_VRANGE GENMASK(3, 2)
27+
#define TPS6287X_CTRL3 0x03
28+
#define TPS6287X_STATUS 0x04
29+
30+
static const struct regmap_config tps6287x_regmap_config = {
31+
.reg_bits = 8,
32+
.val_bits = 8,
33+
.max_register = TPS6287X_STATUS,
34+
};
35+
36+
static const struct linear_range tps6287x_voltage_ranges[] = {
37+
LINEAR_RANGE(400000, 0, 0xFF, 1250),
38+
LINEAR_RANGE(400000, 0, 0xFF, 2500),
39+
LINEAR_RANGE(400000, 0, 0xFF, 5000),
40+
LINEAR_RANGE(800000, 0, 0xFF, 10000),
41+
};
42+
43+
static const unsigned int tps6287x_voltage_range_sel[] = {
44+
0x0, 0x4, 0x8, 0xC
45+
};
46+
47+
static const unsigned int tps6287x_ramp_table[] = {
48+
10000, 5000, 1250, 500
49+
};
50+
51+
static int tps6287x_set_mode(struct regulator_dev *rdev, unsigned int mode)
52+
{
53+
unsigned int val;
54+
55+
switch (mode) {
56+
case REGULATOR_MODE_NORMAL:
57+
val = 0;
58+
break;
59+
case REGULATOR_MODE_FAST:
60+
val = TPS6287X_CTRL1_FPWMEN;
61+
break;
62+
default:
63+
return -EINVAL;
64+
}
65+
66+
return regmap_update_bits(rdev->regmap, TPS6287X_CTRL1,
67+
TPS6287X_CTRL1_FPWMEN, val);
68+
}
69+
70+
static unsigned int tps6287x_get_mode(struct regulator_dev *rdev)
71+
{
72+
unsigned int val;
73+
int ret;
74+
75+
ret = regmap_read(rdev->regmap, TPS6287X_CTRL1, &val);
76+
if (ret < 0)
77+
return 0;
78+
79+
return (val & TPS6287X_CTRL1_FPWMEN) ? REGULATOR_MODE_FAST :
80+
REGULATOR_MODE_NORMAL;
81+
}
82+
83+
static unsigned int tps6287x_of_map_mode(unsigned int mode)
84+
{
85+
switch (mode) {
86+
case REGULATOR_MODE_NORMAL:
87+
case REGULATOR_MODE_FAST:
88+
return mode;
89+
default:
90+
return REGULATOR_MODE_INVALID;
91+
}
92+
}
93+
94+
static const struct regulator_ops tps6287x_regulator_ops = {
95+
.enable = regulator_enable_regmap,
96+
.disable = regulator_disable_regmap,
97+
.set_mode = tps6287x_set_mode,
98+
.get_mode = tps6287x_get_mode,
99+
.is_enabled = regulator_is_enabled_regmap,
100+
.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
101+
.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
102+
.list_voltage = regulator_list_voltage_pickable_linear_range,
103+
.set_ramp_delay = regulator_set_ramp_delay_regmap,
104+
};
105+
106+
static struct regulator_desc tps6287x_reg = {
107+
.name = "tps6287x",
108+
.owner = THIS_MODULE,
109+
.ops = &tps6287x_regulator_ops,
110+
.of_map_mode = tps6287x_of_map_mode,
111+
.type = REGULATOR_VOLTAGE,
112+
.enable_reg = TPS6287X_CTRL1,
113+
.enable_mask = TPS6287X_CTRL1_SWEN,
114+
.vsel_reg = TPS6287X_VSET,
115+
.vsel_mask = 0xFF,
116+
.vsel_range_reg = TPS6287X_CTRL2,
117+
.vsel_range_mask = TPS6287X_CTRL2_VRANGE,
118+
.ramp_reg = TPS6287X_CTRL1,
119+
.ramp_mask = TPS6287X_CTRL1_VRAMP,
120+
.ramp_delay_table = tps6287x_ramp_table,
121+
.n_ramp_values = ARRAY_SIZE(tps6287x_ramp_table),
122+
.linear_ranges = tps6287x_voltage_ranges,
123+
.n_linear_ranges = ARRAY_SIZE(tps6287x_voltage_ranges),
124+
.linear_range_selectors = tps6287x_voltage_range_sel,
125+
};
126+
127+
static int tps6287x_i2c_probe(struct i2c_client *i2c)
128+
{
129+
struct device *dev = &i2c->dev;
130+
struct regulator_config config = {};
131+
struct regulator_dev *rdev;
132+
133+
config.regmap = devm_regmap_init_i2c(i2c, &tps6287x_regmap_config);
134+
if (IS_ERR(config.regmap)) {
135+
dev_err(dev, "Failed to init i2c\n");
136+
return PTR_ERR(config.regmap);
137+
}
138+
139+
config.dev = dev;
140+
config.of_node = dev->of_node;
141+
config.init_data = of_get_regulator_init_data(dev, dev->of_node,
142+
&tps6287x_reg);
143+
144+
rdev = devm_regulator_register(dev, &tps6287x_reg, &config);
145+
if (IS_ERR(rdev)) {
146+
dev_err(dev, "Failed to register regulator\n");
147+
return PTR_ERR(rdev);
148+
}
149+
150+
dev_dbg(dev, "Probed regulator\n");
151+
152+
return 0;
153+
}
154+
155+
static const struct of_device_id tps6287x_dt_ids[] = {
156+
{ .compatible = "ti,tps62870", },
157+
{ .compatible = "ti,tps62871", },
158+
{ .compatible = "ti,tps62872", },
159+
{ .compatible = "ti,tps62873", },
160+
{ }
161+
};
162+
163+
MODULE_DEVICE_TABLE(of, tps6287x_dt_ids);
164+
165+
static const struct i2c_device_id tps6287x_i2c_id[] = {
166+
{ "tps62870", 0 },
167+
{ "tps62871", 0 },
168+
{ "tps62872", 0 },
169+
{ "tps62873", 0 },
170+
{},
171+
};
172+
173+
MODULE_DEVICE_TABLE(i2c, tps6287x_i2c_id);
174+
175+
static struct i2c_driver tps6287x_regulator_driver = {
176+
.driver = {
177+
.name = "tps6287x",
178+
.of_match_table = tps6287x_dt_ids,
179+
},
180+
.probe_new = tps6287x_i2c_probe,
181+
.id_table = tps6287x_i2c_id,
182+
};
183+
184+
module_i2c_driver(tps6287x_regulator_driver);
185+
186+
MODULE_AUTHOR("Mårten Lindahl <marten.lindahl@axis.com>");
187+
MODULE_DESCRIPTION("Regulator driver for TI TPS6287X PMIC");
188+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)