17b0518fbSMårten Lindahl // SPDX-License-Identifier: GPL-2.0-only
27b0518fbSMårten Lindahl /*
37b0518fbSMårten Lindahl * Copyright (C) 2023 Axis Communications AB
47b0518fbSMårten Lindahl *
57b0518fbSMårten Lindahl * Driver for Texas Instruments TPS6287x PMIC.
67b0518fbSMårten Lindahl * Datasheet: https://www.ti.com/lit/ds/symlink/tps62873.pdf
77b0518fbSMårten Lindahl */
87b0518fbSMårten Lindahl
97b0518fbSMårten Lindahl #include <linux/err.h>
107b0518fbSMårten Lindahl #include <linux/i2c.h>
11045a44d4SRob Herring #include <linux/mod_devicetable.h>
127b0518fbSMårten Lindahl #include <linux/module.h>
137b0518fbSMårten Lindahl #include <linux/regmap.h>
147b0518fbSMårten Lindahl #include <linux/regulator/of_regulator.h>
157b0518fbSMårten Lindahl #include <linux/regulator/machine.h>
167b0518fbSMårten Lindahl #include <linux/regulator/driver.h>
177b0518fbSMårten Lindahl #include <linux/bitfield.h>
187b0518fbSMårten Lindahl #include <linux/linear_range.h>
197b0518fbSMårten Lindahl
207b0518fbSMårten Lindahl #define TPS6287X_VSET 0x00
217b0518fbSMårten Lindahl #define TPS6287X_CTRL1 0x01
227b0518fbSMårten Lindahl #define TPS6287X_CTRL1_VRAMP GENMASK(1, 0)
237b0518fbSMårten Lindahl #define TPS6287X_CTRL1_FPWMEN BIT(4)
247b0518fbSMårten Lindahl #define TPS6287X_CTRL1_SWEN BIT(5)
257b0518fbSMårten Lindahl #define TPS6287X_CTRL2 0x02
267b0518fbSMårten Lindahl #define TPS6287X_CTRL2_VRANGE GENMASK(3, 2)
277b0518fbSMårten Lindahl #define TPS6287X_CTRL3 0x03
287b0518fbSMårten Lindahl #define TPS6287X_STATUS 0x04
297b0518fbSMårten Lindahl
307b0518fbSMårten Lindahl static const struct regmap_config tps6287x_regmap_config = {
317b0518fbSMårten Lindahl .reg_bits = 8,
327b0518fbSMårten Lindahl .val_bits = 8,
337b0518fbSMårten Lindahl .max_register = TPS6287X_STATUS,
347b0518fbSMårten Lindahl };
357b0518fbSMårten Lindahl
367b0518fbSMårten Lindahl static const struct linear_range tps6287x_voltage_ranges[] = {
377b0518fbSMårten Lindahl LINEAR_RANGE(400000, 0, 0xFF, 1250),
387b0518fbSMårten Lindahl LINEAR_RANGE(400000, 0, 0xFF, 2500),
397b0518fbSMårten Lindahl LINEAR_RANGE(400000, 0, 0xFF, 5000),
407b0518fbSMårten Lindahl LINEAR_RANGE(800000, 0, 0xFF, 10000),
417b0518fbSMårten Lindahl };
427b0518fbSMårten Lindahl
437b0518fbSMårten Lindahl static const unsigned int tps6287x_voltage_range_sel[] = {
44269cb04bSChen-Yu Tsai 0x0, 0x1, 0x2, 0x3
457b0518fbSMårten Lindahl };
467b0518fbSMårten Lindahl
477b0518fbSMårten Lindahl static const unsigned int tps6287x_ramp_table[] = {
487b0518fbSMårten Lindahl 10000, 5000, 1250, 500
497b0518fbSMårten Lindahl };
507b0518fbSMårten Lindahl
tps6287x_set_mode(struct regulator_dev * rdev,unsigned int mode)517b0518fbSMårten Lindahl static int tps6287x_set_mode(struct regulator_dev *rdev, unsigned int mode)
527b0518fbSMårten Lindahl {
537b0518fbSMårten Lindahl unsigned int val;
547b0518fbSMårten Lindahl
557b0518fbSMårten Lindahl switch (mode) {
567b0518fbSMårten Lindahl case REGULATOR_MODE_NORMAL:
577b0518fbSMårten Lindahl val = 0;
587b0518fbSMårten Lindahl break;
597b0518fbSMårten Lindahl case REGULATOR_MODE_FAST:
607b0518fbSMårten Lindahl val = TPS6287X_CTRL1_FPWMEN;
617b0518fbSMårten Lindahl break;
627b0518fbSMårten Lindahl default:
637b0518fbSMårten Lindahl return -EINVAL;
647b0518fbSMårten Lindahl }
657b0518fbSMårten Lindahl
667b0518fbSMårten Lindahl return regmap_update_bits(rdev->regmap, TPS6287X_CTRL1,
677b0518fbSMårten Lindahl TPS6287X_CTRL1_FPWMEN, val);
687b0518fbSMårten Lindahl }
697b0518fbSMårten Lindahl
tps6287x_get_mode(struct regulator_dev * rdev)707b0518fbSMårten Lindahl static unsigned int tps6287x_get_mode(struct regulator_dev *rdev)
717b0518fbSMårten Lindahl {
727b0518fbSMårten Lindahl unsigned int val;
737b0518fbSMårten Lindahl int ret;
747b0518fbSMårten Lindahl
757b0518fbSMårten Lindahl ret = regmap_read(rdev->regmap, TPS6287X_CTRL1, &val);
767b0518fbSMårten Lindahl if (ret < 0)
777b0518fbSMårten Lindahl return 0;
787b0518fbSMårten Lindahl
797b0518fbSMårten Lindahl return (val & TPS6287X_CTRL1_FPWMEN) ? REGULATOR_MODE_FAST :
807b0518fbSMårten Lindahl REGULATOR_MODE_NORMAL;
817b0518fbSMårten Lindahl }
827b0518fbSMårten Lindahl
tps6287x_of_map_mode(unsigned int mode)837b0518fbSMårten Lindahl static unsigned int tps6287x_of_map_mode(unsigned int mode)
847b0518fbSMårten Lindahl {
857b0518fbSMårten Lindahl switch (mode) {
867b0518fbSMårten Lindahl case REGULATOR_MODE_NORMAL:
877b0518fbSMårten Lindahl case REGULATOR_MODE_FAST:
887b0518fbSMårten Lindahl return mode;
897b0518fbSMårten Lindahl default:
907b0518fbSMårten Lindahl return REGULATOR_MODE_INVALID;
917b0518fbSMårten Lindahl }
927b0518fbSMårten Lindahl }
937b0518fbSMårten Lindahl
947b0518fbSMårten Lindahl static const struct regulator_ops tps6287x_regulator_ops = {
957b0518fbSMårten Lindahl .enable = regulator_enable_regmap,
967b0518fbSMårten Lindahl .disable = regulator_disable_regmap,
977b0518fbSMårten Lindahl .set_mode = tps6287x_set_mode,
987b0518fbSMårten Lindahl .get_mode = tps6287x_get_mode,
997b0518fbSMårten Lindahl .is_enabled = regulator_is_enabled_regmap,
1007b0518fbSMårten Lindahl .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
1017b0518fbSMårten Lindahl .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
1027b0518fbSMårten Lindahl .list_voltage = regulator_list_voltage_pickable_linear_range,
1037b0518fbSMårten Lindahl .set_ramp_delay = regulator_set_ramp_delay_regmap,
1047b0518fbSMårten Lindahl };
1057b0518fbSMårten Lindahl
1067b0518fbSMårten Lindahl static struct regulator_desc tps6287x_reg = {
1077b0518fbSMårten Lindahl .name = "tps6287x",
1087b0518fbSMårten Lindahl .owner = THIS_MODULE,
1097b0518fbSMårten Lindahl .ops = &tps6287x_regulator_ops,
1107b0518fbSMårten Lindahl .of_map_mode = tps6287x_of_map_mode,
1117b0518fbSMårten Lindahl .type = REGULATOR_VOLTAGE,
1127b0518fbSMårten Lindahl .enable_reg = TPS6287X_CTRL1,
1137b0518fbSMårten Lindahl .enable_mask = TPS6287X_CTRL1_SWEN,
1147b0518fbSMårten Lindahl .vsel_reg = TPS6287X_VSET,
1157b0518fbSMårten Lindahl .vsel_mask = 0xFF,
1167b0518fbSMårten Lindahl .vsel_range_reg = TPS6287X_CTRL2,
1177b0518fbSMårten Lindahl .vsel_range_mask = TPS6287X_CTRL2_VRANGE,
118*35db7c9dSMatti Vaittinen .range_applied_by_vsel = true,
1197b0518fbSMårten Lindahl .ramp_reg = TPS6287X_CTRL1,
1207b0518fbSMårten Lindahl .ramp_mask = TPS6287X_CTRL1_VRAMP,
1217b0518fbSMårten Lindahl .ramp_delay_table = tps6287x_ramp_table,
1227b0518fbSMårten Lindahl .n_ramp_values = ARRAY_SIZE(tps6287x_ramp_table),
123c6929055SVincent Whitchurch .n_voltages = 256 * ARRAY_SIZE(tps6287x_voltage_ranges),
1247b0518fbSMårten Lindahl .linear_ranges = tps6287x_voltage_ranges,
1257b0518fbSMårten Lindahl .n_linear_ranges = ARRAY_SIZE(tps6287x_voltage_ranges),
126269cb04bSChen-Yu Tsai .linear_range_selectors_bitfield = tps6287x_voltage_range_sel,
1277b0518fbSMårten Lindahl };
1287b0518fbSMårten Lindahl
tps6287x_i2c_probe(struct i2c_client * i2c)1297b0518fbSMårten Lindahl static int tps6287x_i2c_probe(struct i2c_client *i2c)
1307b0518fbSMårten Lindahl {
1317b0518fbSMårten Lindahl struct device *dev = &i2c->dev;
1327b0518fbSMårten Lindahl struct regulator_config config = {};
1337b0518fbSMårten Lindahl struct regulator_dev *rdev;
1347b0518fbSMårten Lindahl
1357b0518fbSMårten Lindahl config.regmap = devm_regmap_init_i2c(i2c, &tps6287x_regmap_config);
1367b0518fbSMårten Lindahl if (IS_ERR(config.regmap)) {
1377b0518fbSMårten Lindahl dev_err(dev, "Failed to init i2c\n");
1387b0518fbSMårten Lindahl return PTR_ERR(config.regmap);
1397b0518fbSMårten Lindahl }
1407b0518fbSMårten Lindahl
1417b0518fbSMårten Lindahl config.dev = dev;
1427b0518fbSMårten Lindahl config.of_node = dev->of_node;
1437b0518fbSMårten Lindahl config.init_data = of_get_regulator_init_data(dev, dev->of_node,
1447b0518fbSMårten Lindahl &tps6287x_reg);
1457b0518fbSMårten Lindahl
1467b0518fbSMårten Lindahl rdev = devm_regulator_register(dev, &tps6287x_reg, &config);
1477b0518fbSMårten Lindahl if (IS_ERR(rdev)) {
1487b0518fbSMårten Lindahl dev_err(dev, "Failed to register regulator\n");
1497b0518fbSMårten Lindahl return PTR_ERR(rdev);
1507b0518fbSMårten Lindahl }
1517b0518fbSMårten Lindahl
1527b0518fbSMårten Lindahl dev_dbg(dev, "Probed regulator\n");
1537b0518fbSMårten Lindahl
1547b0518fbSMårten Lindahl return 0;
1557b0518fbSMårten Lindahl }
1567b0518fbSMårten Lindahl
1577b0518fbSMårten Lindahl static const struct of_device_id tps6287x_dt_ids[] = {
1587b0518fbSMårten Lindahl { .compatible = "ti,tps62870", },
1597b0518fbSMårten Lindahl { .compatible = "ti,tps62871", },
1607b0518fbSMårten Lindahl { .compatible = "ti,tps62872", },
1617b0518fbSMårten Lindahl { .compatible = "ti,tps62873", },
1627b0518fbSMårten Lindahl { }
1637b0518fbSMårten Lindahl };
1647b0518fbSMårten Lindahl
1657b0518fbSMårten Lindahl MODULE_DEVICE_TABLE(of, tps6287x_dt_ids);
1667b0518fbSMårten Lindahl
1677b0518fbSMårten Lindahl static const struct i2c_device_id tps6287x_i2c_id[] = {
1687b0518fbSMårten Lindahl { "tps62870", 0 },
1697b0518fbSMårten Lindahl { "tps62871", 0 },
1707b0518fbSMårten Lindahl { "tps62872", 0 },
1717b0518fbSMårten Lindahl { "tps62873", 0 },
1727b0518fbSMårten Lindahl {},
1737b0518fbSMårten Lindahl };
1747b0518fbSMårten Lindahl
1757b0518fbSMårten Lindahl MODULE_DEVICE_TABLE(i2c, tps6287x_i2c_id);
1767b0518fbSMårten Lindahl
1777b0518fbSMårten Lindahl static struct i2c_driver tps6287x_regulator_driver = {
1787b0518fbSMårten Lindahl .driver = {
1797b0518fbSMårten Lindahl .name = "tps6287x",
1807b0518fbSMårten Lindahl .of_match_table = tps6287x_dt_ids,
1817b0518fbSMårten Lindahl },
182d692cc61SUwe Kleine-König .probe = tps6287x_i2c_probe,
1837b0518fbSMårten Lindahl .id_table = tps6287x_i2c_id,
1847b0518fbSMårten Lindahl };
1857b0518fbSMårten Lindahl
1867b0518fbSMårten Lindahl module_i2c_driver(tps6287x_regulator_driver);
1877b0518fbSMårten Lindahl
1887b0518fbSMårten Lindahl MODULE_AUTHOR("Mårten Lindahl <marten.lindahl@axis.com>");
1897b0518fbSMårten Lindahl MODULE_DESCRIPTION("Regulator driver for TI TPS6287X PMIC");
1907b0518fbSMårten Lindahl MODULE_LICENSE("GPL");
191