regulator: max77812: add max77812 regulator driver
Venkat Reddy Talla [Tue, 21 Feb 2017 15:34:59 +0000 (20:34 +0530)]
Adding regulator driver for MAX77812 device which is
used in t210b01 based platforms for powering cpu,gpu
and dram io.

Bug 200270700

Change-Id: I2406ead7e00d5dc3afa2f480e769b22f0919089b
Signed-off-by: Venkat Reddy Talla <vreddytalla@nvidia.com>
Reviewed-on: http://git-master/r/1308821
Reviewed-by: svccoveritychecker <svccoveritychecker@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

Documentation/devicetree/bindings/regulator/max77812-regulator.txt [new file with mode: 0644]
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/max77812-regulator.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/regulator/max77812-regulator.txt b/Documentation/devicetree/bindings/regulator/max77812-regulator.txt
new file mode 100644 (file)
index 0000000..56c283d
--- /dev/null
@@ -0,0 +1,50 @@
+MAX77812 voltage regulator
+
+Required properties:
+- compatible: "maxim,max77812-regulator"
+- reg: I2C slave address
+
+Regulators subnode:
+
+MAX77812 supports four regulators, regulators should be described under
+    regualtors subnode.
+
+Optional properties:
+-maxim,ramp-up-slew-rate: to configure slew rate during regulator
+        voltage ramp up time
+-maxim,ramp-down-slew-rate: to configre slew rate during regulator
+        voltage ramp down time
+-maxim,soft-start-slew-rate: to configure slew rate during regulator
+       enable time
+-maxim,shutdown-slew-rate: to configure slew rate during regulator
+       disable time or shutdown time
+
+Each regulator is defined using the standard binding for regulators.
+
+Example:
+
+       max77812@1b {
+               compatible = "maxim,max77812-regulator";
+               reg = <0x1b>;
+
+               regulators {
+                       m1vout {
+                               regulator-name = "mvout1";
+                               regulator-min-microvolt = <250000>;
+                               regulator-max-microvolt = <1525000>;
+                               regulator-boot-on;
+                               regulator-always-on;
+                               regulator-init-mode = <REGULATOR_MODE_NORMAL>;
+                       };
+
+                       m2vout {
+                               regulator-name = "mvout2";
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-min-microvolt = <250000>;
+                               regulator-max-microvolt = <1525000>;
+                               regulator-init-mode = <REGULATOR_MODE_NORMAL>;
+                       };
+               };
+       };
+
index b5916f5..c4b9ec9 100644 (file)
@@ -460,6 +460,15 @@ config REGULATOR_MAX77802
          Exynos5420/Exynos5800 SoCs to control various voltages.
          It includes support for control of voltage and ramp speed.
 
+config REGULATOR_MAX77812
+       tristate "Maxim 77812 Quad-Phase Buck regualtor"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         MAXIM MAX77812 is a quad-phase, high-current, buck regulator.
+         This driver supports configuration of this device
+         through regulator interface.
+
 config REGULATOR_MC13XXX_CORE
        tristate
 
index 42d7872..ff478be 100644 (file)
@@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
 obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
 obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
 obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
+obj-$(CONFIG_REGULATOR_MAX77812) += max77812-regulator.o
 obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
 obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
 obj-$(CONFIG_REGULATOR_MC13XXX_CORE) +=  mc13xxx-regulator-core.o
diff --git a/drivers/regulator/max77812-regulator.c b/drivers/regulator/max77812-regulator.c
new file mode 100644 (file)
index 0000000..2611e22
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * MAXIM max77812 Regulator driver
+ *
+ * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
+ *
+ * Author: Venkat Reddy Talla <vreddytalla@nvidia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
+ * whether express or implied; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define max77812_rails(_name)  "max77812-"#_name
+
+#define MAX77812_REG_RSET              0x00
+#define MAX77812_REG_INT_SRC           0x01
+#define MAX77812_REG_INT_SRC_M         0x02
+#define MAX77812_REG_TOPSYS_INT                0x03
+#define MAX77812_REG_TOPSYS_INT_M      0x04
+#define MAX77812_REG_TOPSYS_STAT       0x05
+#define MAX77812_REG_EN_CTRL           0x06
+#define MAX77812_REG_STUP_DLY1         0x07
+#define MAX77812_REG_STUP_DLY2         0x08
+#define MAX77812_REG_STUP_DLY3         0x09
+#define MAX77812_REG_SHDN_DLY1         0x0A
+#define MAX77812_REG_SHDN_DLY2         0x0B
+#define MAX77812_REG_SHDN_DLY3         0x0C
+#define MAX77812_REG_SHDN_DLY4         0x0D
+#define MAX77812_REG_WDTRSTB_DEB       0x0E
+#define MAX77812_REG_GPI_FUNC          0x0F
+#define MAX77812_REG_GPI_DEB1          0x10
+#define MAX77812_REG_GPI_DEB2          0x11
+#define MAX77812_REG_GPI_PD_CTRL       0x12
+#define MAX77812_REG_PROT_CFG          0x13
+#define MAX77812_REG_I2C_CFG           0x15
+#define MAX77812_REG_BUCK_INT          0x20
+#define MAX77812_REG_BUCK_INT_M                0x21
+#define MAX77812_REG_BUCK_STAT         0x22
+#define MAX77812_REG_M1_VOUT           0x23
+#define MAX77812_REG_M2_VOUT           0x24
+#define MAX77812_REG_M3_VOUT           0x25
+#define MAX77812_REG_M4_VOUT           0x26
+#define MAX77812_REG_M1_VOUT_D         0x27
+#define MAX77812_REG_M2_VOUT_D         0x28
+#define MAX77812_REG_M3_VOUT_D         0x29
+#define MAX77812_REG_M4_VOUT_D         0x2A
+#define MAX77812_REG_M1_VOUT_S         0x2B
+#define MAX77812_REG_M2_VOUT_S         0x2C
+#define MAX77812_REG_M3_VOUT_S         0x2D
+#define MAX77812_REG_M4_VOUT_S         0x2E
+#define MAX77812_REG_M1_CGF            0x2F
+#define MAX77812_REG_M2_CGF            0x30
+#define MAX77812_REG_M3_CGF            0x31
+#define MAX77812_REG_M4_CGF            0x32
+#define MAX77812_REG_GLB_CFG1          0x33
+#define MAX77812_REG_GLB_CFG2          0x34
+#define MAX77812_REG_MAX               0x35
+
+#define MAX77812_REG_EN_CTRL_MASK(n)           BIT(n)
+#define MAX77812_START_SLEW_RATE_MASK          0x07
+#define MAX77812_SHDN_SLEW_RATE_MASK           0x70
+#define MAX77812_RAMPDOWN_SLEW_RATE_MASK       0x07
+#define MAX77812_RAMPUP_SLEW_RATE_MASK         0x70
+
+#define MAX77812_VOUT_MASK             0xFF
+#define MAX77812_VOUT_N_VOLTAGE                0xFF
+#define MAX77812_VOUT_VMIN             250000
+#define MAX77812_VOUT_VMAX             1525000
+#define MAX77812_VOUT_STEP             5000
+
+#define MAX77812_REGULATOR_ID_M1       0
+#define MAX77812_REGULATOR_ID_M2       1
+#define MAX77812_REGULATOR_ID_M3       2
+#define MAX77812_REGULATOR_ID_M4       3
+#define MAX77812_MAX_REGULATORS                4
+
+static unsigned int slew_rate_table[] = {
+       1250, 2500, 5000, 10000, 20000, 40000, 60000,
+};
+
+struct max77812_reg_pdata {
+       struct regulator_init_data *ridata;
+};
+
+struct max77812_regulator {
+       struct device *dev;
+       struct regmap *rmap;
+       struct regulator_desc *rdesc[MAX77812_MAX_REGULATORS];
+       struct max77812_reg_pdata reg_pdata[MAX77812_MAX_REGULATORS];
+       struct regulator_dev *rdev[MAX77812_MAX_REGULATORS];
+       u32 ramp_up_slew_rate;
+       u32 ramp_down_slew_rate;
+       u32 shutdown_slew_rate;
+       u32 softstart_slew_rate;
+};
+
+static int max77812_regulator_enable(struct regulator_dev *rdev)
+{
+       struct max77812_regulator *max77812 = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = regmap_update_bits(max77812->rmap, rdev->desc->enable_reg,
+                       rdev->desc->enable_mask,
+                       rdev->desc->enable_mask);
+       if (ret < 0) {
+               dev_err(max77812->dev, "Regulator enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static int max77812_regulator_disable(struct regulator_dev *rdev)
+{
+       struct max77812_regulator *max77812 = rdev_get_drvdata(rdev);
+       int ret;
+
+       ret = regmap_update_bits(max77812->rmap, rdev->desc->enable_reg,
+                               rdev->desc->enable_mask, 0);
+       if (ret < 0) {
+               dev_err(max77812->dev, "Regulator disable failed: %d\n", ret);
+               return ret;
+       }
+
+       return ret;
+}
+
+static u8 max77802_slew_rate_to_reg(const unsigned int sr_limits[],
+                       u8 cnt, unsigned int slew_rate)
+{
+       int i;
+
+       for (i = 0; i < cnt; i++) {
+               if (slew_rate <= sr_limits[i])
+                       return i;
+       }
+
+       return cnt - 1;
+}
+
+static int max77812_reg_init(struct max77812_regulator *max77812)
+{
+       u8 slew_rate = 0;
+       u8 rampdelay = 0;
+       u8 mask = 0;
+       int ret;
+
+       if (max77812->softstart_slew_rate) {
+               slew_rate = max77802_slew_rate_to_reg(slew_rate_table,
+                               ARRAY_SIZE(slew_rate_table),
+                               max77812->softstart_slew_rate);
+               mask = MAX77812_START_SLEW_RATE_MASK;
+       }
+
+       if (max77812->shutdown_slew_rate) {
+               rampdelay = max77802_slew_rate_to_reg(slew_rate_table,
+                               ARRAY_SIZE(slew_rate_table),
+                               max77812->shutdown_slew_rate);
+               slew_rate |= rampdelay;
+               mask |= MAX77812_SHDN_SLEW_RATE_MASK;
+       }
+
+       if (slew_rate && mask) {
+               ret = regmap_update_bits(max77812->rmap,
+                                       MAX77812_REG_GLB_CFG1,
+                                       mask, slew_rate);
+               if (ret < 0) {
+                       dev_err(max77812->dev, "slew rate cfg1 update failed %d\n",
+                                               ret);
+                       return ret;
+               }
+       }
+
+       slew_rate = 0;
+       mask = 0;
+
+       if (max77812->ramp_up_slew_rate) {
+               slew_rate = max77802_slew_rate_to_reg(slew_rate_table,
+                               ARRAY_SIZE(slew_rate_table),
+                               max77812->ramp_up_slew_rate);
+               mask = MAX77812_RAMPUP_SLEW_RATE_MASK;
+       }
+
+       if (max77812->ramp_down_slew_rate) {
+               rampdelay = max77802_slew_rate_to_reg(slew_rate_table,
+                               ARRAY_SIZE(slew_rate_table),
+                               max77812->ramp_down_slew_rate);
+               slew_rate |= rampdelay;
+               mask |= MAX77812_RAMPDOWN_SLEW_RATE_MASK;
+       }
+
+       if (slew_rate && mask) {
+               ret = regmap_update_bits(max77812->rmap,
+                                       MAX77812_REG_GLB_CFG2,
+                                       mask, slew_rate);
+               if (ret < 0) {
+                       dev_err(max77812->dev, "slew rate cfg2 update failed %d\n",
+                                               ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static struct regulator_ops max77812_regulator_ops = {
+       .enable = max77812_regulator_enable,
+       .disable = max77812_regulator_disable,
+       .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,
+};
+
+#define MAX77812_REGULATOR_DESC(_id, _name, _en_bit)           \
+       [MAX77812_REGULATOR_ID_##_id] = {               \
+               .name = max77812_rails(_name),          \
+               .of_match = of_match_ptr(#_name),               \
+               .regulators_node = of_match_ptr("regulators"),  \
+               .supply_name = "vin",                   \
+               .id = MAX77812_REGULATOR_ID_##_id,      \
+               .ops = &max77812_regulator_ops,         \
+               .n_voltages = MAX77812_VOUT_N_VOLTAGE,  \
+               .min_uV = MAX77812_VOUT_VMIN,           \
+               .uV_step = MAX77812_VOUT_STEP,          \
+               .enable_time = 500,                     \
+               .vsel_mask = MAX77812_VOUT_MASK,        \
+               .vsel_reg = MAX77812_REG_##_id##_VOUT,  \
+               .enable_reg     = MAX77812_REG_EN_CTRL,         \
+               .enable_mask = BIT(_en_bit),                    \
+               .type = REGULATOR_VOLTAGE,              \
+               .owner = THIS_MODULE,                   \
+       }
+
+static struct regulator_desc max77812_regs_desc[MAX77812_MAX_REGULATORS] = {
+       MAX77812_REGULATOR_DESC(M1, m1vout, 0),
+       MAX77812_REGULATOR_DESC(M2, m2vout, 2),
+       MAX77812_REGULATOR_DESC(M3, m3vout, 4),
+       MAX77812_REGULATOR_DESC(M4, m4vout, 6),
+};
+
+static int max77812_reg_parse_dt(struct device *dev,
+               struct max77812_regulator *max77812_regs)
+{
+       struct device_node *np = dev->of_node;
+       u32 pval;
+       int ret;
+
+       ret = of_property_read_u32(np, "maxim,ramp-up-slew-rate", &pval);
+       if (!ret)
+               max77812_regs->ramp_up_slew_rate = pval;
+
+       ret = of_property_read_u32(np, "maxim,ramp-down-slew-rate", &pval);
+       if (!ret)
+               max77812_regs->ramp_down_slew_rate = pval;
+
+       ret = of_property_read_u32(np, "maxim,shutdown-slew-rate", &pval);
+       if (!ret)
+               max77812_regs->shutdown_slew_rate = pval;
+
+       ret = of_property_read_u32(np, "maxim,soft-start-slew-rate", &pval);
+       if (!ret)
+               max77812_regs->softstart_slew_rate = pval;
+
+       return 0;
+}
+
+static const struct regmap_config max77812_regmap_config = {
+       .reg_bits               = 8,
+       .val_bits               = 8,
+       .max_register   = MAX77812_REG_MAX - 1,
+       .cache_type             = REGCACHE_NONE,
+};
+
+static int max77812_probe(struct i2c_client *client,
+                       const struct i2c_device_id *client_id)
+{
+       struct device *dev = &client->dev;
+       struct max77812_reg_pdata *rpdata;
+       struct regulator_config config = { };
+       struct regulator_desc *rdesc;
+       struct max77812_regulator *max77812;
+       int id;
+       int ret;
+
+       max77812 = devm_kzalloc(dev, sizeof(*max77812), GFP_KERNEL);
+       if (!max77812)
+               return -ENOMEM;
+
+       ret = max77812_reg_parse_dt(dev, max77812);
+       if (ret < 0) {
+               dev_err(dev, "Reading data from DT failed: %d\n", ret);
+               return ret;
+       }
+
+       max77812->rmap = devm_regmap_init_i2c(client, &max77812_regmap_config);
+       if (IS_ERR(max77812->rmap)) {
+               ret = PTR_ERR(max77812->rmap);
+               dev_err(dev, "regmap init failed: %d\n", ret);
+               return ret;
+       }
+
+       i2c_set_clientdata(client, max77812);
+       max77812->dev = dev;
+
+       ret = max77812_reg_init(max77812);
+       if (ret < 0) {
+               dev_err(dev, "max77812 Init failed: %d\n", ret);
+               return ret;
+       }
+
+       for (id = 0; id < MAX77812_MAX_REGULATORS; ++id) {
+               rdesc = &max77812_regs_desc[id];
+               max77812->rdesc[id] = rdesc;
+               rpdata = &max77812->reg_pdata[id];
+
+               config.regmap = max77812->rmap;
+               config.dev = dev;
+               config.init_data = rpdata->ridata;
+               config.driver_data = max77812;
+
+               max77812->rdev[id] = devm_regulator_register(dev,
+                                       rdesc, &config);
+               if (IS_ERR(max77812->rdev[id])) {
+                       ret = PTR_ERR(max77812->rdev[id]);
+                       dev_err(dev, "regulator %s register failed: %d\n",
+                                               rdesc->name, ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static const struct of_device_id max77812_of_match[] = {
+       { .compatible = "maxim,max77812-regulator", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, max77812_of_match);
+
+static const struct i2c_device_id max77812_id[] = {
+       {.name = "max77812",},
+       {},
+};
+
+static struct i2c_driver max77812_i2c_driver = {
+       .driver = {
+               .name = "max77812",
+               .owner = THIS_MODULE,
+               .of_match_table = max77812_of_match,
+       },
+       .probe = max77812_probe,
+       .id_table = max77812_id,
+};
+module_i2c_driver(max77812_i2c_driver);
+
+MODULE_AUTHOR("Venkat Reddy Talla <vreddytalla@nvidia.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("max77812 regulator driver");