All of lore.kernel.org
 help / color / mirror / Atom feed
From: Milo Kim <milo.kim@ti.com>
To: <devicetree@vger.kernel.org>, <lee.jones@linaro.org>,
	<linux-kernel@vger.kernel.org>
Cc: Milo Kim <milo.kim@ti.com>, Mark Brown <broonie@kernel.org>
Subject: [PATCH RESEND 16/16] regulator: add LM363X driver
Date: Mon, 2 Nov 2015 14:24:35 +0900	[thread overview]
Message-ID: <1446441875-1256-17-git-send-email-milo.kim@ti.com> (raw)
In-Reply-To: <1446441875-1256-1-git-send-email-milo.kim@ti.com>

LM363X regulator driver supports LM3631 and LM3632.
LM3631 has 5 regulators. LM3632 provides 3 regulators.
One boost output and LDOs are used for the display module.
Boost voltage is configurable but always on.
Supported operations for LDOs are enabled/disabled and voltage change.

Two LDOs of LM3632 can be controlled by external pins.
Those are described in the device tree bindings.

Cc: Mark Brown <broonie@kernel.org>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
 drivers/regulator/Kconfig            |   9 +
 drivers/regulator/Makefile           |   1 +
 drivers/regulator/lm363x-regulator.c | 349 +++++++++++++++++++++++++++++++++++
 3 files changed, 359 insertions(+)
 create mode 100644 drivers/regulator/lm363x-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 64bccff..efac1eb 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -274,6 +274,15 @@ config REGULATOR_ISL6271A
 	help
 	  This driver supports ISL6271A voltage regulator chip.
 
+config REGULATOR_LM363X
+	tristate "TI LM363X voltage regulators"
+	depends on MFD_TI_LMU
+	help
+	  This driver supports LM3631 and LM3632 voltage regulators for
+	  the LCD bias.
+	  One boost output voltage is configurable and always on.
+	  Other LDOs are used for the display module.
+
 config REGULATOR_LP3971
 	tristate "National Semiconductors LP3971 PMIC regulator driver"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0f81749..0ea87cd 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
+obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
 obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
new file mode 100644
index 0000000..28408d4
--- /dev/null
+++ b/drivers/regulator/lm363x-regulator.c
@@ -0,0 +1,349 @@
+/*
+ * TI LM363X Regulator Driver
+ *
+ * Copyright 2015 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/* LM3631 */
+#define LM3631_BOOST_VSEL_MAX		0x25
+#define LM3631_LDO_VSEL_MAX		0x28
+#define LM3631_CONT_VSEL_MAX		0x03
+#define LM3631_VBOOST_MIN		4500000
+#define LM3631_VCONT_MIN		1800000
+#define LM3631_VLDO_MIN			4000000
+#define ENABLE_TIME_USEC		1000
+
+/* LM3632 */
+#define LM3632_BOOST_VSEL_MAX		0x26
+#define LM3632_LDO_VSEL_MAX		0x29
+#define LM3632_VBOOST_MIN		4500000
+#define LM3632_VLDO_MIN			4000000
+
+/* Common */
+#define LM363X_STEP_50mV		50000
+#define LM363X_STEP_500mV		500000
+
+struct lm363x_regulator {
+	struct ti_lmu *lmu;
+	struct regulator_dev *regulator;
+};
+
+const int ldo_cont_enable_time[] = {
+	0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
+};
+
+static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
+{
+	struct lm363x_regulator *lm363x_regulator = rdev_get_drvdata(rdev);
+	enum lm363x_regulator_id id = rdev_get_id(rdev);
+	u8 val, addr, mask;
+
+	switch (id) {
+	case LM3631_LDO_CONT:
+		addr = LM3631_REG_ENTIME_VCONT;
+		mask = LM3631_ENTIME_CONT_MASK;
+		break;
+	case LM3631_LDO_OREF:
+		addr = LM3631_REG_ENTIME_VOREF;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	case LM3631_LDO_POS:
+		addr = LM3631_REG_ENTIME_VPOS;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	case LM3631_LDO_NEG:
+		addr = LM3631_REG_ENTIME_VNEG;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	default:
+		return 0;
+	}
+
+	if (ti_lmu_read_byte(lm363x_regulator->lmu, addr, &val))
+		return -EINVAL;
+
+	val = (val & mask) >> LM3631_ENTIME_SHIFT;
+
+	if (id == LM3631_LDO_CONT)
+		return ldo_cont_enable_time[val];
+	else
+		return ENABLE_TIME_USEC * val;
+}
+
+static struct regulator_ops lm363x_boost_voltage_table_ops = {
+	.list_voltage     = regulator_list_voltage_linear,
+	.set_voltage_sel  = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel  = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops lm363x_regulator_voltage_table_ops = {
+	.list_voltage     = regulator_list_voltage_linear,
+	.set_voltage_sel  = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel  = regulator_get_voltage_sel_regmap,
+	.enable           = regulator_enable_regmap,
+	.disable          = regulator_disable_regmap,
+	.is_enabled       = regulator_is_enabled_regmap,
+	.enable_time      = lm363x_regulator_enable_time,
+};
+
+static const struct regulator_desc lm363x_regulator_desc[] = {
+	/* LM3631 */
+	{
+		.name           = "vboost",
+		.id             = LM3631_BOOST,
+		.ops            = &lm363x_boost_voltage_table_ops,
+		.n_voltages     = LM3631_BOOST_VSEL_MAX + 1,
+		.min_uV         = LM3631_VBOOST_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_BOOST,
+		.vsel_mask      = LM3631_VOUT_MASK,
+	},
+	{
+		.name           = "ldo_cont",
+		.id             = LM3631_LDO_CONT,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_CONT_VSEL_MAX + 1,
+		.min_uV         = LM3631_VCONT_MIN,
+		.uV_step        = LM363X_STEP_500mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_CONT,
+		.vsel_mask      = LM3631_VOUT_CONT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL2,
+		.enable_mask    = LM3631_EN_CONT_MASK,
+	},
+	{
+		.name           = "ldo_oref",
+		.id             = LM3631_LDO_OREF,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_OREF,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_OREF_MASK,
+	},
+	{
+		.name           = "ldo_vpos",
+		.id             = LM3631_LDO_POS,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_POS,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_VPOS_MASK,
+	},
+	{
+		.name           = "ldo_vneg",
+		.id             = LM3631_LDO_NEG,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_NEG,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_VNEG_MASK,
+	},
+	/* LM3632 */
+	{
+		.name           = "vboost",
+		.id             = LM3632_BOOST,
+		.ops            = &lm363x_boost_voltage_table_ops,
+		.n_voltages     = LM3632_BOOST_VSEL_MAX + 1,
+		.min_uV         = LM3632_VBOOST_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_BOOST,
+		.vsel_mask      = LM3632_VOUT_MASK,
+	},
+	{
+		.name           = "ldo_vpos",
+		.id             = LM3632_LDO_POS,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3632_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_POS,
+		.vsel_mask      = LM3632_VOUT_MASK,
+		.enable_reg     = LM3632_REG_BIAS_CONFIG,
+		.enable_mask    = LM3632_EN_VPOS_MASK,
+	},
+	{
+		.name           = "ldo_vneg",
+		.id             = LM3632_LDO_NEG,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3632_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_NEG,
+		.vsel_mask      = LM3632_VOUT_MASK,
+		.enable_reg     = LM3632_REG_BIAS_CONFIG,
+		.enable_mask    = LM3632_EN_VNEG_MASK,
+	},
+};
+
+static struct of_regulator_match lm363x_regulator_matches[] = {
+	[LM3631_BOOST]		= { .name = "vboost" },
+	[LM3631_LDO_CONT]	= { .name = "vcont" },
+	[LM3631_LDO_OREF]	= { .name = "voref" },
+	[LM3631_LDO_POS]	= { .name = "vpos" },
+	[LM3631_LDO_NEG]	= { .name = "vneg" },
+	[LM3632_BOOST]		= { .name = "vboost" },
+	[LM3632_LDO_POS]	= { .name = "vpos" },
+	[LM3632_LDO_NEG]	= { .name = "vneg" },
+};
+
+static struct regulator_init_data *
+lm363x_regulator_of_get_init_data(struct device *dev,
+			struct lm363x_regulator *lm363x_regulator, int id)
+{
+	struct device_node *np = dev->of_node;
+	int count;
+
+	count = of_regulator_match(dev, np, &lm363x_regulator_matches[id], 1);
+	if (count <= 0)
+		return ERR_PTR(-ENODEV);
+
+	return lm363x_regulator_matches[id].init_data;
+}
+
+static int lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)
+{
+	struct device_node *np = dev->of_node;
+	int gpio = -1;
+
+	/*
+	 * Check LCM_EN1/2_GPIO is configured.
+	 * Those pins are used for enabling VPOS/VNEG LDOs.
+	 */
+	if (id == LM3632_LDO_POS)
+		gpio = of_get_named_gpio(np, "ti,lcm-en1-gpio", 0);
+	else if (id == LM3632_LDO_NEG)
+		gpio = of_get_named_gpio(np, "ti,lcm-en2-gpio", 0);
+
+	return gpio;
+}
+
+static int lm363x_regulator_probe(struct platform_device *pdev)
+{
+	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+	struct lm363x_regulator *lm363x_regulator;
+	struct regulator_init_data *init_data;
+	struct regulator_config cfg = { };
+	struct regulator_dev *rdev;
+	struct device *dev = &pdev->dev;
+	int id = pdev->id;
+	int ret, ena_gpio;
+
+	lm363x_regulator = devm_kzalloc(dev, sizeof(*lm363x_regulator),
+					GFP_KERNEL);
+	if (!lm363x_regulator)
+		return -ENOMEM;
+
+	lm363x_regulator->lmu = lmu;
+
+	init_data = lm363x_regulator_of_get_init_data(dev, lm363x_regulator,
+						      id);
+	if (IS_ERR(init_data))
+		return PTR_ERR(init_data);
+
+	cfg.dev = dev->parent;
+	cfg.init_data = init_data;
+	cfg.driver_data = lm363x_regulator;
+	cfg.regmap = lmu->regmap;
+
+	/*
+	 * LM3632 LDOs can be controlled by external pin.
+	 * Register update is required if the pin is used.
+	 */
+	ena_gpio = lm363x_regulator_of_get_enable_gpio(dev, id);
+	if (gpio_is_valid(ena_gpio)) {
+		cfg.ena_gpio = ena_gpio;
+		cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW;
+
+		ret = ti_lmu_update_bits(lmu, LM3632_REG_BIAS_CONFIG,
+					 LM3632_EXT_EN_MASK,
+					 LM3632_EXT_EN_MASK);
+		if (ret) {
+			dev_err(dev, "External pin err: %d\n", ret);
+			return ret;
+		}
+	}
+
+	rdev = regulator_register(&lm363x_regulator_desc[id], &cfg);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(dev, "[%d] regulator register err: %d\n", id, ret);
+		return ret;
+	}
+
+	lm363x_regulator->regulator = rdev;
+	platform_set_drvdata(pdev, lm363x_regulator);
+
+	return 0;
+}
+
+static int lm363x_regulator_remove(struct platform_device *pdev)
+{
+	struct lm363x_regulator *lm363x_regulator = platform_get_drvdata(pdev);
+
+	regulator_unregister(lm363x_regulator->regulator);
+	return 0;
+}
+
+static const struct of_device_id lm363x_regulator_of_match[] = {
+	{ .compatible = "ti,lm363x-regulator" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lm363x_regulator_of_match);
+
+static struct platform_driver lm363x_regulator_driver = {
+	.probe = lm363x_regulator_probe,
+	.remove = lm363x_regulator_remove,
+	.driver = {
+		.name = "lm363x-regulator",
+		.of_match_table = lm363x_regulator_of_match,
+	},
+};
+
+module_platform_driver(lm363x_regulator_driver);
+
+MODULE_DESCRIPTION("TI LM363X Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lm363x-regulator");
-- 
1.9.1


WARNING: multiple messages have this Message-ID (diff)
From: Milo Kim <milo.kim@ti.com>
To: devicetree@vger.kernel.org, lee.jones@linaro.org,
	linux-kernel@vger.kernel.org
Cc: Milo Kim <milo.kim@ti.com>, Mark Brown <broonie@kernel.org>
Subject: [PATCH RESEND 16/16] regulator: add LM363X driver
Date: Mon, 2 Nov 2015 14:24:35 +0900	[thread overview]
Message-ID: <1446441875-1256-17-git-send-email-milo.kim@ti.com> (raw)
In-Reply-To: <1446441875-1256-1-git-send-email-milo.kim@ti.com>

LM363X regulator driver supports LM3631 and LM3632.
LM3631 has 5 regulators. LM3632 provides 3 regulators.
One boost output and LDOs are used for the display module.
Boost voltage is configurable but always on.
Supported operations for LDOs are enabled/disabled and voltage change.

Two LDOs of LM3632 can be controlled by external pins.
Those are described in the device tree bindings.

Cc: Mark Brown <broonie@kernel.org>
Cc: Lee Jones <lee.jones@linaro.org>
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Milo Kim <milo.kim@ti.com>
---
 drivers/regulator/Kconfig            |   9 +
 drivers/regulator/Makefile           |   1 +
 drivers/regulator/lm363x-regulator.c | 349 +++++++++++++++++++++++++++++++++++
 3 files changed, 359 insertions(+)
 create mode 100644 drivers/regulator/lm363x-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 64bccff..efac1eb 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -274,6 +274,15 @@ config REGULATOR_ISL6271A
 	help
 	  This driver supports ISL6271A voltage regulator chip.
 
+config REGULATOR_LM363X
+	tristate "TI LM363X voltage regulators"
+	depends on MFD_TI_LMU
+	help
+	  This driver supports LM3631 and LM3632 voltage regulators for
+	  the LCD bias.
+	  One boost output voltage is configurable and always on.
+	  Other LDOs are used for the display module.
+
 config REGULATOR_LP3971
 	tristate "National Semiconductors LP3971 PMIC regulator driver"
 	depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0f81749..0ea87cd 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
 obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o
 obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
 obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o
+obj-$(CONFIG_REGULATOR_LM363X) += lm363x-regulator.o
 obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
 obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
 obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o
diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c
new file mode 100644
index 0000000..28408d4
--- /dev/null
+++ b/drivers/regulator/lm363x-regulator.c
@@ -0,0 +1,349 @@
+/*
+ * TI LM363X Regulator Driver
+ *
+ * Copyright 2015 Texas Instruments
+ *
+ * Author: Milo Kim <milo.kim@ti.com>
+ *
+ * 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.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/mfd/ti-lmu.h>
+#include <linux/mfd/ti-lmu-register.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/slab.h>
+
+/* LM3631 */
+#define LM3631_BOOST_VSEL_MAX		0x25
+#define LM3631_LDO_VSEL_MAX		0x28
+#define LM3631_CONT_VSEL_MAX		0x03
+#define LM3631_VBOOST_MIN		4500000
+#define LM3631_VCONT_MIN		1800000
+#define LM3631_VLDO_MIN			4000000
+#define ENABLE_TIME_USEC		1000
+
+/* LM3632 */
+#define LM3632_BOOST_VSEL_MAX		0x26
+#define LM3632_LDO_VSEL_MAX		0x29
+#define LM3632_VBOOST_MIN		4500000
+#define LM3632_VLDO_MIN			4000000
+
+/* Common */
+#define LM363X_STEP_50mV		50000
+#define LM363X_STEP_500mV		500000
+
+struct lm363x_regulator {
+	struct ti_lmu *lmu;
+	struct regulator_dev *regulator;
+};
+
+const int ldo_cont_enable_time[] = {
+	0, 2000, 5000, 10000, 20000, 50000, 100000, 200000,
+};
+
+static int lm363x_regulator_enable_time(struct regulator_dev *rdev)
+{
+	struct lm363x_regulator *lm363x_regulator = rdev_get_drvdata(rdev);
+	enum lm363x_regulator_id id = rdev_get_id(rdev);
+	u8 val, addr, mask;
+
+	switch (id) {
+	case LM3631_LDO_CONT:
+		addr = LM3631_REG_ENTIME_VCONT;
+		mask = LM3631_ENTIME_CONT_MASK;
+		break;
+	case LM3631_LDO_OREF:
+		addr = LM3631_REG_ENTIME_VOREF;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	case LM3631_LDO_POS:
+		addr = LM3631_REG_ENTIME_VPOS;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	case LM3631_LDO_NEG:
+		addr = LM3631_REG_ENTIME_VNEG;
+		mask = LM3631_ENTIME_MASK;
+		break;
+	default:
+		return 0;
+	}
+
+	if (ti_lmu_read_byte(lm363x_regulator->lmu, addr, &val))
+		return -EINVAL;
+
+	val = (val & mask) >> LM3631_ENTIME_SHIFT;
+
+	if (id == LM3631_LDO_CONT)
+		return ldo_cont_enable_time[val];
+	else
+		return ENABLE_TIME_USEC * val;
+}
+
+static struct regulator_ops lm363x_boost_voltage_table_ops = {
+	.list_voltage     = regulator_list_voltage_linear,
+	.set_voltage_sel  = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel  = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops lm363x_regulator_voltage_table_ops = {
+	.list_voltage     = regulator_list_voltage_linear,
+	.set_voltage_sel  = regulator_set_voltage_sel_regmap,
+	.get_voltage_sel  = regulator_get_voltage_sel_regmap,
+	.enable           = regulator_enable_regmap,
+	.disable          = regulator_disable_regmap,
+	.is_enabled       = regulator_is_enabled_regmap,
+	.enable_time      = lm363x_regulator_enable_time,
+};
+
+static const struct regulator_desc lm363x_regulator_desc[] = {
+	/* LM3631 */
+	{
+		.name           = "vboost",
+		.id             = LM3631_BOOST,
+		.ops            = &lm363x_boost_voltage_table_ops,
+		.n_voltages     = LM3631_BOOST_VSEL_MAX + 1,
+		.min_uV         = LM3631_VBOOST_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_BOOST,
+		.vsel_mask      = LM3631_VOUT_MASK,
+	},
+	{
+		.name           = "ldo_cont",
+		.id             = LM3631_LDO_CONT,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_CONT_VSEL_MAX + 1,
+		.min_uV         = LM3631_VCONT_MIN,
+		.uV_step        = LM363X_STEP_500mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_CONT,
+		.vsel_mask      = LM3631_VOUT_CONT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL2,
+		.enable_mask    = LM3631_EN_CONT_MASK,
+	},
+	{
+		.name           = "ldo_oref",
+		.id             = LM3631_LDO_OREF,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_OREF,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_OREF_MASK,
+	},
+	{
+		.name           = "ldo_vpos",
+		.id             = LM3631_LDO_POS,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_POS,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_VPOS_MASK,
+	},
+	{
+		.name           = "ldo_vneg",
+		.id             = LM3631_LDO_NEG,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3631_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3631_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3631_REG_VOUT_NEG,
+		.vsel_mask      = LM3631_VOUT_MASK,
+		.enable_reg     = LM3631_REG_LDO_CTRL1,
+		.enable_mask    = LM3631_EN_VNEG_MASK,
+	},
+	/* LM3632 */
+	{
+		.name           = "vboost",
+		.id             = LM3632_BOOST,
+		.ops            = &lm363x_boost_voltage_table_ops,
+		.n_voltages     = LM3632_BOOST_VSEL_MAX + 1,
+		.min_uV         = LM3632_VBOOST_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_BOOST,
+		.vsel_mask      = LM3632_VOUT_MASK,
+	},
+	{
+		.name           = "ldo_vpos",
+		.id             = LM3632_LDO_POS,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3632_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_POS,
+		.vsel_mask      = LM3632_VOUT_MASK,
+		.enable_reg     = LM3632_REG_BIAS_CONFIG,
+		.enable_mask    = LM3632_EN_VPOS_MASK,
+	},
+	{
+		.name           = "ldo_vneg",
+		.id             = LM3632_LDO_NEG,
+		.ops            = &lm363x_regulator_voltage_table_ops,
+		.n_voltages     = LM3632_LDO_VSEL_MAX + 1,
+		.min_uV         = LM3632_VLDO_MIN,
+		.uV_step        = LM363X_STEP_50mV,
+		.type           = REGULATOR_VOLTAGE,
+		.owner          = THIS_MODULE,
+		.vsel_reg       = LM3632_REG_VOUT_NEG,
+		.vsel_mask      = LM3632_VOUT_MASK,
+		.enable_reg     = LM3632_REG_BIAS_CONFIG,
+		.enable_mask    = LM3632_EN_VNEG_MASK,
+	},
+};
+
+static struct of_regulator_match lm363x_regulator_matches[] = {
+	[LM3631_BOOST]		= { .name = "vboost" },
+	[LM3631_LDO_CONT]	= { .name = "vcont" },
+	[LM3631_LDO_OREF]	= { .name = "voref" },
+	[LM3631_LDO_POS]	= { .name = "vpos" },
+	[LM3631_LDO_NEG]	= { .name = "vneg" },
+	[LM3632_BOOST]		= { .name = "vboost" },
+	[LM3632_LDO_POS]	= { .name = "vpos" },
+	[LM3632_LDO_NEG]	= { .name = "vneg" },
+};
+
+static struct regulator_init_data *
+lm363x_regulator_of_get_init_data(struct device *dev,
+			struct lm363x_regulator *lm363x_regulator, int id)
+{
+	struct device_node *np = dev->of_node;
+	int count;
+
+	count = of_regulator_match(dev, np, &lm363x_regulator_matches[id], 1);
+	if (count <= 0)
+		return ERR_PTR(-ENODEV);
+
+	return lm363x_regulator_matches[id].init_data;
+}
+
+static int lm363x_regulator_of_get_enable_gpio(struct device *dev, int id)
+{
+	struct device_node *np = dev->of_node;
+	int gpio = -1;
+
+	/*
+	 * Check LCM_EN1/2_GPIO is configured.
+	 * Those pins are used for enabling VPOS/VNEG LDOs.
+	 */
+	if (id == LM3632_LDO_POS)
+		gpio = of_get_named_gpio(np, "ti,lcm-en1-gpio", 0);
+	else if (id == LM3632_LDO_NEG)
+		gpio = of_get_named_gpio(np, "ti,lcm-en2-gpio", 0);
+
+	return gpio;
+}
+
+static int lm363x_regulator_probe(struct platform_device *pdev)
+{
+	struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent);
+	struct lm363x_regulator *lm363x_regulator;
+	struct regulator_init_data *init_data;
+	struct regulator_config cfg = { };
+	struct regulator_dev *rdev;
+	struct device *dev = &pdev->dev;
+	int id = pdev->id;
+	int ret, ena_gpio;
+
+	lm363x_regulator = devm_kzalloc(dev, sizeof(*lm363x_regulator),
+					GFP_KERNEL);
+	if (!lm363x_regulator)
+		return -ENOMEM;
+
+	lm363x_regulator->lmu = lmu;
+
+	init_data = lm363x_regulator_of_get_init_data(dev, lm363x_regulator,
+						      id);
+	if (IS_ERR(init_data))
+		return PTR_ERR(init_data);
+
+	cfg.dev = dev->parent;
+	cfg.init_data = init_data;
+	cfg.driver_data = lm363x_regulator;
+	cfg.regmap = lmu->regmap;
+
+	/*
+	 * LM3632 LDOs can be controlled by external pin.
+	 * Register update is required if the pin is used.
+	 */
+	ena_gpio = lm363x_regulator_of_get_enable_gpio(dev, id);
+	if (gpio_is_valid(ena_gpio)) {
+		cfg.ena_gpio = ena_gpio;
+		cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW;
+
+		ret = ti_lmu_update_bits(lmu, LM3632_REG_BIAS_CONFIG,
+					 LM3632_EXT_EN_MASK,
+					 LM3632_EXT_EN_MASK);
+		if (ret) {
+			dev_err(dev, "External pin err: %d\n", ret);
+			return ret;
+		}
+	}
+
+	rdev = regulator_register(&lm363x_regulator_desc[id], &cfg);
+	if (IS_ERR(rdev)) {
+		ret = PTR_ERR(rdev);
+		dev_err(dev, "[%d] regulator register err: %d\n", id, ret);
+		return ret;
+	}
+
+	lm363x_regulator->regulator = rdev;
+	platform_set_drvdata(pdev, lm363x_regulator);
+
+	return 0;
+}
+
+static int lm363x_regulator_remove(struct platform_device *pdev)
+{
+	struct lm363x_regulator *lm363x_regulator = platform_get_drvdata(pdev);
+
+	regulator_unregister(lm363x_regulator->regulator);
+	return 0;
+}
+
+static const struct of_device_id lm363x_regulator_of_match[] = {
+	{ .compatible = "ti,lm363x-regulator" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, lm363x_regulator_of_match);
+
+static struct platform_driver lm363x_regulator_driver = {
+	.probe = lm363x_regulator_probe,
+	.remove = lm363x_regulator_remove,
+	.driver = {
+		.name = "lm363x-regulator",
+		.of_match_table = lm363x_regulator_of_match,
+	},
+};
+
+module_platform_driver(lm363x_regulator_driver);
+
+MODULE_DESCRIPTION("TI LM363X Regulator Driver");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lm363x-regulator");
-- 
1.9.1

  parent reply	other threads:[~2015-11-02  5:26 UTC|newest]

Thread overview: 99+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-11-02  5:24 [PATCH RESEND 00/16] Support TI LMU devices Milo Kim
2015-11-02  5:24 ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 01/16] Documentation: dt-bindings: mfd: add TI LMU device binding information Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-06  2:00   ` Rob Herring
2015-11-11  9:49   ` Lee Jones
2015-11-12  0:05     ` Kim, Milo
2015-11-12  0:05       ` Kim, Milo
2015-11-02  5:24 ` [PATCH RESEND 02/16] Documentation: dt-bindings: backlight: add TI LMU backlight " Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02 15:02   ` Rob Herring
2015-11-03  7:13     ` Kim, Milo
2015-11-03 15:32       ` Rob Herring
2015-11-02  5:24 ` [PATCH RESEND 03/16] Documentation: dt-bindings: hwmon: add TI LMU HWMON " Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-06  1:57   ` Rob Herring
2015-11-06  1:57     ` Rob Herring
2015-11-06  3:48     ` Kim, Milo
2015-11-06  3:48       ` Kim, Milo
     [not found] ` <1446441875-1256-1-git-send-email-milo.kim-l0cyMroinI0@public.gmane.org>
2015-11-02  5:24   ` [PATCH RESEND 04/16] Documentation: dt-bindings: leds: add LM3633 LED " Milo Kim
2015-11-02  5:24     ` Milo Kim
     [not found]     ` <1446441875-1256-5-git-send-email-milo.kim-l0cyMroinI0@public.gmane.org>
2015-11-03 16:15       ` Jacek Anaszewski
2015-11-03 16:15         ` Jacek Anaszewski
2015-11-10  7:01         ` Kim, Milo
2015-11-10  7:01           ` Kim, Milo
2015-11-02  5:24 ` [PATCH RESEND 05/16] Documentation: dt-bindings: regulator: add LM363x regulator " Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 06/16] mfd: add TI LMU driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-23 10:30   ` Lee Jones
2015-11-24  2:35     ` Kim, Milo
2015-11-24  2:35       ` Kim, Milo
2015-11-24  6:39       ` Kim, Milo
2015-11-24  6:39         ` Kim, Milo
2015-11-24  8:18         ` Lee Jones
2015-11-25  8:10           ` Kim, Milo
2015-11-25  8:10             ` Kim, Milo
     [not found]             ` <56556D01.9070804-l0cyMroinI0@public.gmane.org>
2015-11-25  8:15               ` Lee Jones
2015-11-25  8:15                 ` Lee Jones
2015-11-02  5:24 ` [PATCH RESEND 07/16] backlight: add TI LMU backlight common driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 08/16] backlight: ti-lmu-backlight: add LM3532 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:37   ` kbuild test robot
2015-11-02  5:37     ` kbuild test robot
2015-11-02  7:33     ` Kim, Milo
2015-11-02  7:33       ` Kim, Milo
2015-11-02  5:24 ` [PATCH RESEND 09/16] backlight: ti-lmu-backlight: add LM3631 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 10/16] backlight: ti-lmu-backlight: add LM3632 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 11/16] backlight: ti-lmu-backlight: add LM3633 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 12/16] backlight: ti-lmu-backlight: add LM3695 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 13/16] backlight: ti-lmu-backlight: add LM3697 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02  5:24 ` [PATCH RESEND 14/16] hwmon: add TI LMU hardware fault monitoring driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-02 14:27   ` Guenter Roeck
2015-11-02 14:27     ` Guenter Roeck
2015-11-03  7:01     ` Kim, Milo
2015-11-03  7:01       ` Kim, Milo
2015-11-02  5:24 ` [PATCH RESEND 15/16] leds: add LM3633 driver Milo Kim
2015-11-02  5:24   ` Milo Kim
2015-11-03 16:15   ` Jacek Anaszewski
     [not found]     ` <5638DD99.9070502-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-11-10  7:38       ` Kim, Milo
2015-11-10  7:38         ` Kim, Milo
2015-11-10 13:44         ` Jacek Anaszewski
     [not found]           ` <5641F4D3.7000800-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2015-11-11  2:16             ` Kim, Milo
2015-11-11  2:16               ` Kim, Milo
2015-11-12  9:04               ` Jacek Anaszewski
2015-11-20  9:22         ` Jacek Anaszewski
2015-11-22 23:40           ` Kim, Milo
2015-11-22 23:40             ` Kim, Milo
     [not found]             ` <56525262.60308-l0cyMroinI0@public.gmane.org>
2015-11-23 11:17               ` Jacek Anaszewski
2015-11-23 11:17                 ` Jacek Anaszewski
2015-11-02  5:24 ` Milo Kim [this message]
2015-11-02  5:24   ` [PATCH RESEND 16/16] regulator: add LM363X driver Milo Kim
2015-11-02 12:26   ` Mark Brown
2015-11-03  6:59     ` Kim, Milo
2015-11-03  6:59       ` Kim, Milo
2015-11-04 13:59   ` Mark Brown
2015-11-10  7:54     ` Kim, Milo
2015-11-10  7:54       ` Kim, Milo
2015-11-02  8:59 ` [PATCH RESEND 00/16] Support TI LMU devices Lee Jones
2015-11-02  8:59   ` Lee Jones
2015-11-03  6:52   ` Kim, Milo
2015-11-03  6:52     ` Kim, Milo
2015-11-03  8:33     ` Lee Jones
2015-11-03  9:08       ` Kim, Milo
2015-11-03  9:08         ` Kim, Milo
2015-11-25  8:51       ` Kim, Milo
2015-11-25  8:51         ` Kim, Milo
2015-11-25  9:05         ` Lee Jones
2015-11-02  9:00 ` Lee Jones
2015-11-03  6:56   ` Kim, Milo
2015-11-03  6:56     ` Kim, Milo
2015-11-03  8:35     ` Lee Jones

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1446441875-1256-17-git-send-email-milo.kim@ti.com \
    --to=milo.kim@ti.com \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=lee.jones@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.