mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
![Thomas Gleixner](/assets/img/avatar_default.png)
Based on the normalized pattern: this program is free software you can redistribute it and/or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed as is without any warranty of any kind whether expressed or implied without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license version 2 for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference. Reviewed-by: Allison Randal <allison@lohutok.net> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
199 lines
5.9 KiB
C
199 lines
5.9 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Regulator driver for LP873X PMIC
|
|
*
|
|
* Copyright (C) 2016 Texas Instruments Incorporated - https://www.ti.com/
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/regmap.h>
|
|
|
|
#include <linux/mfd/lp873x.h>
|
|
|
|
#define LP873X_REGULATOR(_name, _id, _of, _ops, _n, _vr, _vm, _er, _em, \
|
|
_delay, _lr, _cr) \
|
|
[_id] = { \
|
|
.desc = { \
|
|
.name = _name, \
|
|
.supply_name = _of "-in", \
|
|
.id = _id, \
|
|
.of_match = of_match_ptr(_of), \
|
|
.regulators_node = of_match_ptr("regulators"),\
|
|
.ops = &_ops, \
|
|
.n_voltages = _n, \
|
|
.type = REGULATOR_VOLTAGE, \
|
|
.owner = THIS_MODULE, \
|
|
.vsel_reg = _vr, \
|
|
.vsel_mask = _vm, \
|
|
.enable_reg = _er, \
|
|
.enable_mask = _em, \
|
|
.ramp_delay = _delay, \
|
|
.linear_ranges = _lr, \
|
|
.n_linear_ranges = ARRAY_SIZE(_lr), \
|
|
.curr_table = lp873x_buck_uA, \
|
|
.n_current_limits = ARRAY_SIZE(lp873x_buck_uA), \
|
|
.csel_reg = (_cr), \
|
|
.csel_mask = LP873X_BUCK0_CTRL_2_BUCK0_ILIM,\
|
|
}, \
|
|
.ctrl2_reg = _cr, \
|
|
}
|
|
|
|
struct lp873x_regulator {
|
|
struct regulator_desc desc;
|
|
unsigned int ctrl2_reg;
|
|
};
|
|
|
|
static const struct lp873x_regulator regulators[];
|
|
|
|
static const struct linear_range buck0_buck1_ranges[] = {
|
|
REGULATOR_LINEAR_RANGE(0, 0x0, 0x13, 0),
|
|
REGULATOR_LINEAR_RANGE(700000, 0x14, 0x17, 10000),
|
|
REGULATOR_LINEAR_RANGE(735000, 0x18, 0x9d, 5000),
|
|
REGULATOR_LINEAR_RANGE(1420000, 0x9e, 0xff, 20000),
|
|
};
|
|
|
|
static const struct linear_range ldo0_ldo1_ranges[] = {
|
|
REGULATOR_LINEAR_RANGE(800000, 0x0, 0x19, 100000),
|
|
};
|
|
|
|
static const unsigned int lp873x_buck_ramp_delay[] = {
|
|
30000, 15000, 10000, 7500, 3800, 1900, 940, 470
|
|
};
|
|
|
|
/* LP873X BUCK current limit */
|
|
static const unsigned int lp873x_buck_uA[] = {
|
|
1500000, 2000000, 2500000, 3000000, 3500000, 4000000,
|
|
};
|
|
|
|
static int lp873x_buck_set_ramp_delay(struct regulator_dev *rdev,
|
|
int ramp_delay)
|
|
{
|
|
int id = rdev_get_id(rdev);
|
|
struct lp873x *lp873 = rdev_get_drvdata(rdev);
|
|
unsigned int reg;
|
|
int ret;
|
|
|
|
if (ramp_delay <= 470)
|
|
reg = 7;
|
|
else if (ramp_delay <= 940)
|
|
reg = 6;
|
|
else if (ramp_delay <= 1900)
|
|
reg = 5;
|
|
else if (ramp_delay <= 3800)
|
|
reg = 4;
|
|
else if (ramp_delay <= 7500)
|
|
reg = 3;
|
|
else if (ramp_delay <= 10000)
|
|
reg = 2;
|
|
else if (ramp_delay <= 15000)
|
|
reg = 1;
|
|
else
|
|
reg = 0;
|
|
|
|
ret = regmap_update_bits(lp873->regmap, regulators[id].ctrl2_reg,
|
|
LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE,
|
|
reg << __ffs(LP873X_BUCK0_CTRL_2_BUCK0_SLEW_RATE));
|
|
if (ret) {
|
|
dev_err(lp873->dev, "SLEW RATE write failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
rdev->constraints->ramp_delay = lp873x_buck_ramp_delay[reg];
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Operations permitted on BUCK0, BUCK1 */
|
|
static const struct regulator_ops lp873x_buck01_ops = {
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
.enable = regulator_enable_regmap,
|
|
.disable = regulator_disable_regmap,
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
.set_voltage_time_sel = regulator_set_voltage_time_sel,
|
|
.set_ramp_delay = lp873x_buck_set_ramp_delay,
|
|
.set_current_limit = regulator_set_current_limit_regmap,
|
|
.get_current_limit = regulator_get_current_limit_regmap,
|
|
};
|
|
|
|
/* Operations permitted on LDO0 and LDO1 */
|
|
static const struct regulator_ops lp873x_ldo01_ops = {
|
|
.is_enabled = regulator_is_enabled_regmap,
|
|
.enable = regulator_enable_regmap,
|
|
.disable = regulator_disable_regmap,
|
|
.get_voltage_sel = regulator_get_voltage_sel_regmap,
|
|
.set_voltage_sel = regulator_set_voltage_sel_regmap,
|
|
.list_voltage = regulator_list_voltage_linear_range,
|
|
.map_voltage = regulator_map_voltage_linear_range,
|
|
};
|
|
|
|
static const struct lp873x_regulator regulators[] = {
|
|
LP873X_REGULATOR("BUCK0", LP873X_BUCK_0, "buck0", lp873x_buck01_ops,
|
|
256, LP873X_REG_BUCK0_VOUT,
|
|
LP873X_BUCK0_VOUT_BUCK0_VSET, LP873X_REG_BUCK0_CTRL_1,
|
|
LP873X_BUCK0_CTRL_1_BUCK0_EN, 10000,
|
|
buck0_buck1_ranges, LP873X_REG_BUCK0_CTRL_2),
|
|
LP873X_REGULATOR("BUCK1", LP873X_BUCK_1, "buck1", lp873x_buck01_ops,
|
|
256, LP873X_REG_BUCK1_VOUT,
|
|
LP873X_BUCK1_VOUT_BUCK1_VSET, LP873X_REG_BUCK1_CTRL_1,
|
|
LP873X_BUCK1_CTRL_1_BUCK1_EN, 10000,
|
|
buck0_buck1_ranges, LP873X_REG_BUCK1_CTRL_2),
|
|
LP873X_REGULATOR("LDO0", LP873X_LDO_0, "ldo0", lp873x_ldo01_ops, 26,
|
|
LP873X_REG_LDO0_VOUT, LP873X_LDO0_VOUT_LDO0_VSET,
|
|
LP873X_REG_LDO0_CTRL,
|
|
LP873X_LDO0_CTRL_LDO0_EN, 0, ldo0_ldo1_ranges, 0xFF),
|
|
LP873X_REGULATOR("LDO1", LP873X_LDO_1, "ldo1", lp873x_ldo01_ops, 26,
|
|
LP873X_REG_LDO1_VOUT, LP873X_LDO1_VOUT_LDO1_VSET,
|
|
LP873X_REG_LDO1_CTRL,
|
|
LP873X_LDO1_CTRL_LDO1_EN, 0, ldo0_ldo1_ranges, 0xFF),
|
|
};
|
|
|
|
static int lp873x_regulator_probe(struct platform_device *pdev)
|
|
{
|
|
struct lp873x *lp873 = dev_get_drvdata(pdev->dev.parent);
|
|
struct regulator_config config = { };
|
|
struct regulator_dev *rdev;
|
|
int i;
|
|
|
|
platform_set_drvdata(pdev, lp873);
|
|
|
|
config.dev = &pdev->dev;
|
|
config.dev->of_node = lp873->dev->of_node;
|
|
config.driver_data = lp873;
|
|
config.regmap = lp873->regmap;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
|
|
rdev = devm_regulator_register(&pdev->dev, ®ulators[i].desc,
|
|
&config);
|
|
if (IS_ERR(rdev)) {
|
|
dev_err(lp873->dev, "failed to register %s regulator\n",
|
|
pdev->name);
|
|
return PTR_ERR(rdev);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct platform_device_id lp873x_regulator_id_table[] = {
|
|
{ "lp873x-regulator", },
|
|
{ /* sentinel */ }
|
|
};
|
|
MODULE_DEVICE_TABLE(platform, lp873x_regulator_id_table);
|
|
|
|
static struct platform_driver lp873x_regulator_driver = {
|
|
.driver = {
|
|
.name = "lp873x-pmic",
|
|
},
|
|
.probe = lp873x_regulator_probe,
|
|
.id_table = lp873x_regulator_id_table,
|
|
};
|
|
module_platform_driver(lp873x_regulator_driver);
|
|
|
|
MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
|
|
MODULE_DESCRIPTION("LP873X voltage regulator driver");
|
|
MODULE_ALIAS("platform:lp873x-pmic");
|
|
MODULE_LICENSE("GPL v2");
|