-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
regulator: mp5416: add mp5416 regulator driver
Adding regulator driver for the device mp5416. The MP5416 PMIC device contains four DC-DC buck converters and five regulators, accessed over I2C. Signed-off-by: Saravanan Sekar <sravanhome@gmail.com> Link: https://lore.kernel.org/r/20200204110419.25933-3-sravanhome@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
- Loading branch information
Saravanan Sekar
authored and
Mark Brown
committed
Feb 11, 2020
1 parent
65c3851
commit a273188
Showing
3 changed files
with
256 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
// SPDX-License-Identifier: GPL-2.0+ | ||
// | ||
// mp5416.c - regulator driver for mps mp5416 | ||
// | ||
// Copyright 2020 Monolithic Power Systems, Inc | ||
// | ||
// Author: Saravanan Sekar <sravanhome@gmail.com> | ||
|
||
#include <linux/kernel.h> | ||
#include <linux/module.h> | ||
#include <linux/init.h> | ||
#include <linux/err.h> | ||
#include <linux/platform_device.h> | ||
#include <linux/regmap.h> | ||
#include <linux/regulator/driver.h> | ||
#include <linux/i2c.h> | ||
|
||
#define MP5416_REG_CTL0 0x00 | ||
#define MP5416_REG_CTL1 0x01 | ||
#define MP5416_REG_CTL2 0x02 | ||
#define MP5416_REG_ILIM 0x03 | ||
#define MP5416_REG_BUCK1 0x04 | ||
#define MP5416_REG_BUCK2 0x05 | ||
#define MP5416_REG_BUCK3 0x06 | ||
#define MP5416_REG_BUCK4 0x07 | ||
#define MP5416_REG_LDO1 0x08 | ||
#define MP5416_REG_LDO2 0x09 | ||
#define MP5416_REG_LDO3 0x0a | ||
#define MP5416_REG_LDO4 0x0b | ||
|
||
#define MP5416_REGULATOR_EN BIT(7) | ||
#define MP5416_MASK_VSET 0x7f | ||
#define MP5416_MASK_BUCK1_ILIM 0xc0 | ||
#define MP5416_MASK_BUCK2_ILIM 0x0c | ||
#define MP5416_MASK_BUCK3_ILIM 0x30 | ||
#define MP5416_MASK_BUCK4_ILIM 0x03 | ||
#define MP5416_MASK_DVS_SLEWRATE 0xc0 | ||
|
||
/* values in uV */ | ||
#define MP5416_VOLT1_MIN 600000 | ||
#define MP5416_VOLT1_MAX 2187500 | ||
#define MP5416_VOLT1_STEP 12500 | ||
#define MP5416_VOLT2_MIN 800000 | ||
#define MP5416_VOLT2_MAX 3975000 | ||
#define MP5416_VOLT2_STEP 25000 | ||
|
||
#define MP5416_VOLT1_RANGE \ | ||
((MP5416_VOLT1_MAX - MP5416_VOLT1_MIN)/MP5416_VOLT1_STEP + 1) | ||
#define MP5416_VOLT2_RANGE \ | ||
((MP5416_VOLT2_MAX - MP5416_VOLT2_MIN)/MP5416_VOLT2_STEP + 1) | ||
|
||
#define MP5416BUCK(_name, _id, _ilim, _dreg, _dval, _vsel) \ | ||
[MP5416_BUCK ## _id] = { \ | ||
.id = MP5416_BUCK ## _id, \ | ||
.name = _name, \ | ||
.of_match = _name, \ | ||
.regulators_node = "regulators", \ | ||
.ops = &mp5416_buck_ops, \ | ||
.min_uV = MP5416_VOLT ##_vsel## _MIN, \ | ||
.uV_step = MP5416_VOLT ##_vsel## _STEP, \ | ||
.n_voltages = MP5416_VOLT ##_vsel## _RANGE, \ | ||
.curr_table = _ilim, \ | ||
.n_current_limits = ARRAY_SIZE(_ilim), \ | ||
.csel_reg = MP5416_REG_ILIM, \ | ||
.csel_mask = MP5416_MASK_BUCK ## _id ##_ILIM, \ | ||
.vsel_reg = MP5416_REG_BUCK ## _id, \ | ||
.vsel_mask = MP5416_MASK_VSET, \ | ||
.enable_reg = MP5416_REG_BUCK ## _id, \ | ||
.enable_mask = MP5416_REGULATOR_EN, \ | ||
.active_discharge_on = _dval, \ | ||
.active_discharge_reg = _dreg, \ | ||
.active_discharge_mask = _dval, \ | ||
.owner = THIS_MODULE, \ | ||
} | ||
|
||
#define MP5416LDO(_name, _id) \ | ||
[MP5416_LDO ## _id] = { \ | ||
.id = MP5416_LDO ## _id, \ | ||
.name = _name, \ | ||
.of_match = _name, \ | ||
.regulators_node = "regulators", \ | ||
.ops = &mp5416_ldo_ops, \ | ||
.min_uV = MP5416_VOLT2_MIN, \ | ||
.uV_step = MP5416_VOLT2_STEP, \ | ||
.n_voltages = MP5416_VOLT2_RANGE, \ | ||
.vsel_reg = MP5416_REG_LDO ##_id, \ | ||
.vsel_mask = MP5416_MASK_VSET, \ | ||
.enable_reg = MP5416_REG_LDO ##_id, \ | ||
.enable_mask = MP5416_REGULATOR_EN, \ | ||
.active_discharge_on = BIT(_id), \ | ||
.active_discharge_reg = MP5416_REG_CTL2, \ | ||
.active_discharge_mask = BIT(_id), \ | ||
.owner = THIS_MODULE, \ | ||
} | ||
|
||
enum mp5416_regulators { | ||
MP5416_BUCK1, | ||
MP5416_BUCK2, | ||
MP5416_BUCK3, | ||
MP5416_BUCK4, | ||
MP5416_LDO1, | ||
MP5416_LDO2, | ||
MP5416_LDO3, | ||
MP5416_LDO4, | ||
MP5416_MAX_REGULATORS, | ||
}; | ||
|
||
static const struct regmap_config mp5416_regmap_config = { | ||
.reg_bits = 8, | ||
.val_bits = 8, | ||
.max_register = 0x0d, | ||
}; | ||
|
||
/* Current limits array (in uA) | ||
* ILIM1 & ILIM3 | ||
*/ | ||
static const unsigned int mp5416_I_limits1[] = { | ||
3800000, 4600000, 5600000, 6800000 | ||
}; | ||
|
||
/* ILIM2 & ILIM4 */ | ||
static const unsigned int mp5416_I_limits2[] = { | ||
2200000, 3200000, 4200000, 5200000 | ||
}; | ||
|
||
static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay); | ||
|
||
static const struct regulator_ops mp5416_ldo_ops = { | ||
.enable = regulator_enable_regmap, | ||
.disable = regulator_disable_regmap, | ||
.is_enabled = regulator_is_enabled_regmap, | ||
.list_voltage = regulator_list_voltage_linear, | ||
.map_voltage = regulator_map_voltage_linear, | ||
.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
.set_active_discharge = regulator_set_active_discharge_regmap, | ||
}; | ||
|
||
static const struct regulator_ops mp5416_buck_ops = { | ||
.enable = regulator_enable_regmap, | ||
.disable = regulator_disable_regmap, | ||
.is_enabled = regulator_is_enabled_regmap, | ||
.list_voltage = regulator_list_voltage_linear, | ||
.map_voltage = regulator_map_voltage_linear, | ||
.get_voltage_sel = regulator_get_voltage_sel_regmap, | ||
.set_voltage_sel = regulator_set_voltage_sel_regmap, | ||
.set_active_discharge = regulator_set_active_discharge_regmap, | ||
.get_current_limit = regulator_get_current_limit_regmap, | ||
.set_current_limit = regulator_set_current_limit_regmap, | ||
.set_ramp_delay = mp5416_set_ramp_delay, | ||
}; | ||
|
||
static struct regulator_desc mp5416_regulators_desc[MP5416_MAX_REGULATORS] = { | ||
MP5416BUCK("buck1", 1, mp5416_I_limits1, MP5416_REG_CTL1, BIT(0), 1), | ||
MP5416BUCK("buck2", 2, mp5416_I_limits2, MP5416_REG_CTL1, BIT(1), 2), | ||
MP5416BUCK("buck3", 3, mp5416_I_limits1, MP5416_REG_CTL1, BIT(2), 1), | ||
MP5416BUCK("buck4", 4, mp5416_I_limits2, MP5416_REG_CTL2, BIT(5), 2), | ||
MP5416LDO("ldo1", 1), | ||
MP5416LDO("ldo2", 2), | ||
MP5416LDO("ldo3", 3), | ||
MP5416LDO("ldo4", 4), | ||
}; | ||
|
||
/* | ||
* DVS ramp rate BUCK1 to BUCK4 | ||
* 00: 32mV/us | ||
* 01: 16mV/us | ||
* 10: 8mV/us | ||
* 11: 4mV/us | ||
*/ | ||
static int mp5416_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) | ||
{ | ||
unsigned int ramp_val; | ||
|
||
if (ramp_delay > 32000 || ramp_delay < 0) | ||
return -EINVAL; | ||
|
||
if (ramp_delay <= 4000) | ||
ramp_val = 3; | ||
else if (ramp_delay <= 8000) | ||
ramp_val = 2; | ||
else if (ramp_delay <= 16000) | ||
ramp_val = 1; | ||
else | ||
ramp_val = 0; | ||
|
||
return regmap_update_bits(rdev->regmap, MP5416_REG_CTL2, | ||
MP5416_MASK_DVS_SLEWRATE, ramp_val << 6); | ||
} | ||
|
||
static int mp5416_i2c_probe(struct i2c_client *client) | ||
{ | ||
struct device *dev = &client->dev; | ||
struct regulator_config config = { NULL, }; | ||
struct regulator_dev *rdev; | ||
struct regmap *regmap; | ||
int i; | ||
|
||
regmap = devm_regmap_init_i2c(client, &mp5416_regmap_config); | ||
if (IS_ERR(regmap)) { | ||
dev_err(dev, "Failed to allocate regmap!\n"); | ||
return PTR_ERR(regmap); | ||
} | ||
|
||
config.dev = dev; | ||
config.regmap = regmap; | ||
|
||
for (i = 0; i < MP5416_MAX_REGULATORS; i++) { | ||
rdev = devm_regulator_register(dev, | ||
&mp5416_regulators_desc[i], | ||
&config); | ||
if (IS_ERR(rdev)) { | ||
dev_err(dev, "Failed to register regulator!\n"); | ||
return PTR_ERR(rdev); | ||
} | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static const struct of_device_id mp5416_of_match[] = { | ||
{ .compatible = "mps,mp5416" }, | ||
{}, | ||
}; | ||
MODULE_DEVICE_TABLE(of, mp5416_of_match); | ||
|
||
static const struct i2c_device_id mp5416_id[] = { | ||
{ "mp5416", }, | ||
{ }, | ||
}; | ||
MODULE_DEVICE_TABLE(i2c, mp5416_id); | ||
|
||
static struct i2c_driver mp5416_regulator_driver = { | ||
.driver = { | ||
.name = "mp5416", | ||
.of_match_table = of_match_ptr(mp5416_of_match), | ||
}, | ||
.probe_new = mp5416_i2c_probe, | ||
.id_table = mp5416_id, | ||
}; | ||
module_i2c_driver(mp5416_regulator_driver); | ||
|
||
MODULE_AUTHOR("Saravanan Sekar <sravanhome@gmail.com>"); | ||
MODULE_DESCRIPTION("MP5416 PMIC regulator driver"); | ||
MODULE_LICENSE("GPL"); |