regulator: mp5416: add mp5416 regulator driver
authorSaravanan Sekar <sravanhome@gmail.com>
Tue, 4 Feb 2020 11:04:18 +0000 (12:04 +0100)
committerMark Brown <broonie@kernel.org>
Tue, 11 Feb 2020 11:34:34 +0000 (11:34 +0000)
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>
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/mp5416.c [new file with mode: 0644]

index 074a2ef..b8ae513 100644 (file)
@@ -613,6 +613,16 @@ config REGULATOR_MCP16502
          through the regulator interface. In addition it enables
          suspend-to-ram/standby transition.
 
+config REGULATOR_MP5416
+       tristate "Monolithic MP5416 PMIC"
+       depends on I2C && OF
+       select REGMAP_I2C
+       help
+         Say y here to support the MP5416 PMIC. This will enable supports
+         the software controllable 4 buck and 4 LDO regulators.
+         Say M here if you want to include support for the regulator as a
+         module.
+
 config REGULATOR_MP8859
        tristate "MPS MP8859 regulator driver"
        depends on I2C
index c0d6b96..bc69d64 100644 (file)
@@ -78,6 +78,7 @@ obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
 obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o
+obj-$(CONFIG_REGULATOR_MP5416) += mp5416.o
 obj-$(CONFIG_REGULATOR_MP8859) += mp8859.o
 obj-$(CONFIG_REGULATOR_MPQ7920) += mpq7920.o
 obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o
diff --git a/drivers/regulator/mp5416.c b/drivers/regulator/mp5416.c
new file mode 100644 (file)
index 0000000..7954ad1
--- /dev/null
@@ -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");