File Index
Files and directories
Sign in
FILE

tps6287x-regulator.c

File preview with syntax highlighting.

linux-6.19.14/drivers/regulator/tps6287x-regulator.c C
  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/mod_devicetable.h>
 12#include <linux/module.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
 30static bool tps6287x_volatile_reg(struct device *dev, unsigned int reg)
 31{
 32	return reg == TPS6287X_STATUS;
 33}
 34
 35static const struct regmap_config tps6287x_regmap_config = {
 36	.reg_bits = 8,
 37	.val_bits = 8,
 38	.max_register = TPS6287X_STATUS,
 39	.cache_type = REGCACHE_MAPLE,
 40	.volatile_reg = tps6287x_volatile_reg,
 41};
 42
 43static const struct linear_range tps6287x_voltage_ranges[] = {
 44	LINEAR_RANGE(400000, 0, 0xFF, 1250),
 45	LINEAR_RANGE(400000, 0, 0xFF, 2500),
 46	LINEAR_RANGE(400000, 0, 0xFF, 5000),
 47	LINEAR_RANGE(800000, 0, 0xFF, 10000),
 48};
 49
 50static const unsigned int tps6287x_voltage_range_sel[] = {
 51	0x0, 0x1, 0x2, 0x3
 52};
 53
 54static const unsigned int tps6287x_voltage_range_prefix[] = {
 55	0x000, 0x100, 0x200, 0x300
 56};
 57
 58static const unsigned int tps6287x_ramp_table[] = {
 59	10000, 5000, 1250, 500
 60};
 61
 62struct tps6287x_reg_data {
 63	int range;
 64};
 65
 66static int tps6287x_best_range(struct regulator_config *config, const struct regulator_desc *desc)
 67{
 68	const struct linear_range *r;
 69	int i;
 70
 71	if (!config->init_data->constraints.apply_uV)
 72		return -1;
 73
 74	for (i = 0; i < desc->n_linear_ranges; i++) {
 75		r = &desc->linear_ranges[i];
 76		if (r->min <= config->init_data->constraints.min_uV &&
 77		    config->init_data->constraints.max_uV <= linear_range_get_max_value(r))
 78			return i;
 79	}
 80	return -1;
 81}
 82
 83static int tps6287x_set_mode(struct regulator_dev *rdev, unsigned int mode)
 84{
 85	unsigned int val;
 86
 87	switch (mode) {
 88	case REGULATOR_MODE_NORMAL:
 89		val = 0;
 90		break;
 91	case REGULATOR_MODE_FAST:
 92		val = TPS6287X_CTRL1_FPWMEN;
 93		break;
 94	default:
 95		return -EINVAL;
 96	}
 97
 98	return regmap_update_bits(rdev->regmap, TPS6287X_CTRL1,
 99				  TPS6287X_CTRL1_FPWMEN, val);
100}
101
102static unsigned int tps6287x_get_mode(struct regulator_dev *rdev)
103{
104	unsigned int val;
105	int ret;
106
107	ret = regmap_read(rdev->regmap, TPS6287X_CTRL1, &val);
108	if (ret < 0)
109		return 0;
110
111	return (val & TPS6287X_CTRL1_FPWMEN) ? REGULATOR_MODE_FAST :
112	    REGULATOR_MODE_NORMAL;
113}
114
115static unsigned int tps6287x_of_map_mode(unsigned int mode)
116{
117	switch (mode) {
118	case REGULATOR_MODE_NORMAL:
119	case REGULATOR_MODE_FAST:
120		return mode;
121	default:
122		return REGULATOR_MODE_INVALID;
123	}
124}
125
126static int tps6287x_map_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
127{
128	struct tps6287x_reg_data *data = (struct tps6287x_reg_data *)rdev->reg_data;
129	struct linear_range selected_range;
130	int selector, voltage;
131
132	if (!data || data->range == -1)
133		return regulator_map_voltage_pickable_linear_range(rdev, min_uV, max_uV);
134
135	selected_range = rdev->desc->linear_ranges[data->range];
136	selector = DIV_ROUND_UP(min_uV - selected_range.min, selected_range.step);
137	if (selector < selected_range.min_sel || selector > selected_range.max_sel)
138		return -EINVAL;
139
140	selector |= tps6287x_voltage_range_prefix[data->range];
141	voltage = rdev->desc->ops->list_voltage(rdev, selector);
142	if (voltage < min_uV || voltage > max_uV)
143		return -EINVAL;
144
145	return selector;
146}
147
148static const struct regulator_ops tps6287x_regulator_ops = {
149	.enable = regulator_enable_regmap,
150	.disable = regulator_disable_regmap,
151	.set_mode = tps6287x_set_mode,
152	.get_mode = tps6287x_get_mode,
153	.is_enabled = regulator_is_enabled_regmap,
154	.get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
155	.set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
156	.list_voltage = regulator_list_voltage_pickable_linear_range,
157	.map_voltage = tps6287x_map_voltage,
158	.set_ramp_delay = regulator_set_ramp_delay_regmap,
159};
160
161static const struct regulator_desc tps6287x_reg = {
162	.name = "tps6287x",
163	.owner = THIS_MODULE,
164	.ops = &tps6287x_regulator_ops,
165	.of_map_mode = tps6287x_of_map_mode,
166	.type = REGULATOR_VOLTAGE,
167	.enable_reg = TPS6287X_CTRL1,
168	.enable_mask = TPS6287X_CTRL1_SWEN,
169	.vsel_reg = TPS6287X_VSET,
170	.vsel_mask = 0xFF,
171	.vsel_range_reg = TPS6287X_CTRL2,
172	.vsel_range_mask = TPS6287X_CTRL2_VRANGE,
173	.range_applied_by_vsel = true,
174	.ramp_reg = TPS6287X_CTRL1,
175	.ramp_mask = TPS6287X_CTRL1_VRAMP,
176	.ramp_delay_table = tps6287x_ramp_table,
177	.n_ramp_values = ARRAY_SIZE(tps6287x_ramp_table),
178	.n_voltages = 256 * ARRAY_SIZE(tps6287x_voltage_ranges),
179	.linear_ranges = tps6287x_voltage_ranges,
180	.n_linear_ranges = ARRAY_SIZE(tps6287x_voltage_ranges),
181	.linear_range_selectors_bitfield = tps6287x_voltage_range_sel,
182};
183
184static int tps6287x_i2c_probe(struct i2c_client *i2c)
185{
186	struct device *dev = &i2c->dev;
187	struct regulator_config config = {};
188	struct tps6287x_reg_data *reg_data;
189	struct regulator_dev *rdev;
190
191	reg_data = devm_kzalloc(dev, sizeof(struct tps6287x_reg_data), GFP_KERNEL);
192
193	if (!reg_data)
194		return -ENOMEM;
195
196	config.regmap = devm_regmap_init_i2c(i2c, &tps6287x_regmap_config);
197	if (IS_ERR(config.regmap)) {
198		dev_err(dev, "Failed to init i2c\n");
199		return PTR_ERR(config.regmap);
200	}
201
202	config.dev = dev;
203	config.of_node = dev->of_node;
204	config.init_data = of_get_regulator_init_data(dev, dev->of_node,
205						      &tps6287x_reg);
206
207	reg_data->range = tps6287x_best_range(&config, &tps6287x_reg);
208
209	rdev = devm_regulator_register(dev, &tps6287x_reg, &config);
210	if (IS_ERR(rdev)) {
211		dev_err(dev, "Failed to register regulator\n");
212		return PTR_ERR(rdev);
213	}
214
215	rdev->reg_data = (void *)reg_data;
216	dev_dbg(dev, "Probed regulator\n");
217
218	return 0;
219}
220
221static const struct of_device_id tps6287x_dt_ids[] = {
222	{ .compatible = "ti,tps62870", },
223	{ .compatible = "ti,tps62871", },
224	{ .compatible = "ti,tps62872", },
225	{ .compatible = "ti,tps62873", },
226	{ }
227};
228
229MODULE_DEVICE_TABLE(of, tps6287x_dt_ids);
230
231static const struct i2c_device_id tps6287x_i2c_id[] = {
232	{ "tps62870" },
233	{ "tps62871" },
234	{ "tps62872" },
235	{ "tps62873" },
236	{}
237};
238
239MODULE_DEVICE_TABLE(i2c, tps6287x_i2c_id);
240
241static struct i2c_driver tps6287x_regulator_driver = {
242	.driver = {
243		.name = "tps6287x",
244		.of_match_table = tps6287x_dt_ids,
245	},
246	.probe = tps6287x_i2c_probe,
247	.id_table = tps6287x_i2c_id,
248};
249
250module_i2c_driver(tps6287x_regulator_driver);
251
252MODULE_AUTHOR("MÃ¥rten Lindahl <marten.lindahl@axis.com>");
253MODULE_DESCRIPTION("Regulator driver for TI TPS6287X PMIC");
254MODULE_LICENSE("GPL");
~/ Read-only file preview.