[PATCH 1/2] TPS6235x based Power regulator support added

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch provides the changes required for TPS6235x power
regulator support. The driver is put in
drivers/regulator/tps6235x-regulator.c.

The Kconfig and Makefile are modified for build.
This patch should be used alongwith Patch[2/2].

The framework for the build is included. The build will pass
only after the remaining parts of the patches are applied.

Signed-off-by: Manikandan Pillai <mani.pillai@xxxxxx>
---
 drivers/regulator/Kconfig              |   10 +
 drivers/regulator/Makefile             |    1 +
 drivers/regulator/tps6235x-regulator.c |  296 ++++++++++++++++++++++++++++++++
 3 files changed, 307 insertions(+), 0 deletions(-)
 create mode 100644 drivers/regulator/tps6235x-regulator.c

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 0765389..2eee878 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -80,4 +80,14 @@ config REGULATOR_DA903X
 	  Say y here to support the BUCKs and LDOs regulators found on
 	  Dialog Semiconductor DA9030/DA9034 PMIC.
 
+config REGULATOR_TPS6235X
+	bool "TPS6235X Power regulator for OMAP3EVM"
+	depends on I2C=y
+	help
+	  This driver supports the voltage regulators provided by TPS6235x chips.
+	  The TPS62352 and TPS62353 are mounted on PR785 Power module card for
+	  providing voltage regulator functions. The PR785 Power board from
+	  Texas Instruments Inc is a TPS6235X based power card used with OMAP3
+	  EVM boards.
+
 endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 0dacb18..fdc5f5b 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -12,5 +12,6 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
 obj-$(CONFIG_REGULATOR_DA903X)	+= da903x.o
+obj-$(CONFIG_REGULATOR_TPS6235X)+= tps6235x-regulator.o
 
 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/tps6235x-regulator.c b/drivers/regulator/tps6235x-regulator.c
new file mode 100644
index 0000000..96f8251
--- /dev/null
+++ b/drivers/regulator/tps6235x-regulator.c
@@ -0,0 +1,296 @@
+/*
+ * tps6235x-regulator.c -- support regulators in tps6235x family chips
+ *
+ * Author : Manikandan Pillai<mani.pillai@xxxxxx>
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+extern int tps_6235x_read_reg(struct i2c_client *client, u8 reg, u8 *val);
+extern int tps_6235x_write_reg(struct i2c_client *client, u8 reg, u8 val);
+extern struct regulator_consumer_supply tps62352_core_consumers;
+extern struct regulator_consumer_supply tps62352_mpu_consumers;
+
+/* Minimum and Maximum dc-dc voltage supported by the TPS6235x devices
+All voltages given in millivolts */
+#define	TPS62352_MIN_CORE_VOLT	750
+#define	TPS62352_MAX_CORE_VOLT	1537
+#define	TPS62353_MIN_MPU_VOLT	750
+#define	TPS62353_MAX_MPU_VOLT	1537
+
+/* Register bit settings */
+#define	TPS6235X_EN_DCDC	(0x1 << 0x7)
+#define	TPS6235X_VSM_MSK	(0x3F)
+#define	TPS6235X_EN_SYN_MSK	(0x1 << 0x5)
+#define	TPS6235X_SW_VOLT_MSK	(0x1 << 0x4)
+#define	TPS6235X_PWR_OK_MSK	(0x1 << 0x5)
+#define	TPS6235X_OUT_DIS_MSK	(0x1 << 0x6)
+#define	TPS6235X_GO_MSK		(0x1 << 0x7)
+
+#define	MODULE_NAME		"tps_6235x_pwr"
+/*
+ * These chips are often used in OMAP-based systems.
+ *
+ * This driver implements software-based resource control for various
+ * voltage regulators.  This is usually augmented with state machine
+ * based control.
+ */
+
+/* LDO control registers ... offset is from the base of its register bank.
+ * The first three registers of all power resource banks help hardware to
+ * manage the various resource groups.
+ */
+
+#define	TPS6235X_REG_VSEL0	0
+#define	TPS6235X_REG_VSEL1	1
+#define	TPS6235X_REG_CTRL1	2
+#define	TPS6235X_REG_CTRL2	3
+
+/* Device addresses for TPS devices */
+#define	TPS_62352_CORE_ADDR	0x4A
+#define	TPS_62353_MPU_ADDR	0x48
+
+extern int omap_i2c_match_child(struct device *dev, void *data);
+
+static int tps6235x_dcdc_is_enabled(struct regulator_dev *dev)
+{
+	unsigned char vsel1;
+	int ret;
+	struct i2c_client *tps_info	=
+			rdev_get_drvdata(dev);
+	ret = tps_6235x_read_reg(tps_info, TPS6235X_REG_VSEL1, &vsel1);
+	ret &= TPS6235X_EN_DCDC;
+	if (ret)
+		return 1;
+	else
+		return 0;
+}
+
+static int tps6235x_dcdc_enable(struct regulator_dev *dev)
+{
+	unsigned char vsel1;
+	int ret = -1;
+	struct i2c_client *client = rdev_get_drvdata(dev);
+
+	ret = tps_6235x_read_reg(client, TPS6235X_REG_VSEL1, &vsel1);
+	if (ret == 0) {
+		vsel1 |= TPS6235X_EN_DCDC;
+		ret = tps_6235x_write_reg(client, TPS6235X_REG_VSEL1, vsel1);
+	}
+	return ret;
+}
+
+static int tps6235x_dcdc_disable(struct regulator_dev *dev)
+{
+	unsigned char vsel1;
+	int ret = -1;
+	struct	i2c_client *client = rdev_get_drvdata(dev);
+
+	ret = tps_6235x_read_reg(client, TPS6235X_REG_VSEL1, &vsel1);
+	if (ret == 0) {
+		vsel1 &= ~(TPS6235X_EN_DCDC);
+		ret = tps_6235x_write_reg(client, TPS6235X_REG_VSEL1, vsel1);
+	}
+	return ret;
+}
+
+static int tps6235x_dcdc_get_voltage(struct regulator_dev *dev)
+{
+	struct	i2c_client *tps_info = rdev_get_drvdata(dev);
+	unsigned char vsel1;
+	unsigned int volt;
+
+	/* Read the VSEL1 register to get VSM */
+	tps_6235x_read_reg(tps_info, TPS6235X_REG_VSEL1, &vsel1);
+	/* Output voltage set is = min_op_volt + ( VSM * 12.5mv) */
+	/* To cut out floating point operation we will multiply by 25
+	divide by 2 */
+	volt = (((vsel1 & TPS6235X_VSM_MSK) * 25) / 2) + TPS62352_MIN_CORE_VOLT;
+
+	return volt * 1000;
+}
+
+static int tps6235x_dcdc_set_voltage(struct regulator_dev *dev,
+				int min_uV, int max_uV)
+{
+	unsigned char vsel1;
+	unsigned int volt;
+	struct	i2c_client *tps_info = rdev_get_drvdata(dev);
+	unsigned int millivolts = min_uV / 1000;
+
+	/* check if the millivolts is within range */
+	if ((millivolts < TPS62352_MIN_CORE_VOLT) ||
+		(millivolts > TPS62352_MAX_CORE_VOLT))
+		return -1;
+
+	/* Output voltage set is = min_op_volt + ( VSM * 12.5mv) */
+	volt = millivolts - TPS62352_MIN_CORE_VOLT;
+	volt /= 25;
+	volt *= 2;
+	vsel1 = ((TPS6235X_EN_DCDC) | (volt & TPS6235X_VSM_MSK));
+	tps_6235x_write_reg(tps_info, TPS6235X_REG_VSEL1, vsel1);
+	return 0;
+}
+
+static struct regulator_ops tps62352_dcdc_ops = {
+	.is_enabled = tps6235x_dcdc_is_enabled,
+	.get_voltage = tps6235x_dcdc_get_voltage,
+	.set_voltage = tps6235x_dcdc_set_voltage,
+};
+
+static struct regulator_ops tps62353_dcdc_ops = {
+	.is_enabled = tps6235x_dcdc_is_enabled,
+	.enable = tps6235x_dcdc_enable,
+	.disable = tps6235x_dcdc_disable,
+	.get_voltage = tps6235x_dcdc_get_voltage,
+	.set_voltage = tps6235x_dcdc_set_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+	{
+		.name = "tps62352",
+		.id = 2,
+		.ops = &tps62352_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+	{
+		.name = "tps62353",
+		.id = 3,
+		.ops = &tps62353_dcdc_ops,
+		.type = REGULATOR_VOLTAGE,
+		.owner = THIS_MODULE,
+	},
+};
+
+static
+int tps_6235x_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+	struct  regulator_dev           *rdev = NULL;
+	unsigned char reg_val;
+	struct device *dev_child = NULL;
+
+	tps_6235x_read_reg(client, TPS6235X_REG_CTRL2, &reg_val);
+	reg_val |= (TPS6235X_OUT_DIS_MSK | TPS6235X_GO_MSK);
+	tps_6235x_write_reg(client, TPS6235X_REG_CTRL2, reg_val);
+	tps_6235x_read_reg(client, TPS6235X_REG_CTRL2, &reg_val);
+
+	if (reg_val & TPS6235X_PWR_OK_MSK)
+		dev_dbg(&client->dev, "Power is OK  %x\n", reg_val);
+	else {
+		printk(KERN_ERR "Power not within range = %x\n", reg_val);
+		return -2;
+	}
+
+	/* Register the regulators */
+	if (client->addr == TPS_62352_CORE_ADDR) {
+		dev_child = device_find_child(client->adapter->dev.parent,
+				"vdd2", omap_i2c_match_child);
+		/* dev needs to be inited since this is required to for get() */
+		rdev = regulator_register(&regulators[0], dev_child,
+					client);
+	} else if (client->addr == TPS_62353_MPU_ADDR) {
+		/* dev needs to be inited since this is required to for get() */
+		dev_child = device_find_child(client->adapter->dev.parent,
+				"vdd1", omap_i2c_match_child);
+		rdev = regulator_register(&regulators[1], dev_child,
+					client);
+	}
+
+	if (rdev == NULL) {
+		printk(KERN_ERR "ERR in regulator registration\n");
+		return -1;
+	}
+
+	/* Set the regulator platform data for unregistration later on */
+	i2c_set_clientdata(client, rdev);
+
+	return 0;
+}
+
+/**
+ * tps_6235x_remove - TPS6235x driver i2c remove handler
+ * @client: i2c driver client device structure
+ *
+ * Unregister  TPS driver as an i2c client device driver
+ */
+static int __exit tps_6235x_remove(struct i2c_client *client)
+{
+	struct  regulator_dev   *rdev = NULL;
+
+	if (!client->adapter)
+		return -ENODEV; /* our client isn't attached */
+
+	rdev = (struct  regulator_dev *)i2c_get_clientdata(client);
+	regulator_unregister(rdev);
+	/* clear the client data in i2c */
+	i2c_set_clientdata(client, NULL);
+
+	return 0;
+}
+
+static const struct i2c_device_id tps_6235x_id[] = {
+	{ "tps62352", 0},
+	{ "tps62353", 1},
+	{},
+};
+
+MODULE_DEVICE_TABLE(i2c, tps_6235x_id);
+
+static struct i2c_driver tps_6235x_i2c_driver = {
+	.driver = {
+		.name	=	MODULE_NAME,
+		.owner	=	THIS_MODULE,
+	},
+	.probe		= tps_6235x_probe,
+	.remove		= __exit_p(tps_6235x_remove),
+	.id_table	= tps_6235x_id,
+};
+
+/**
+ * tps_6235x_init
+ *
+ * Module init function
+ */
+static int __init tps_6235x_init(void)
+{
+	int err;
+
+	err = i2c_add_driver(&tps_6235x_i2c_driver);
+	if (err) {
+		printk(KERN_ERR "Failed to register " MODULE_NAME ".\n");
+		return err;
+	}
+	return 0;
+}
+
+
+/**
+ * tps_6235x_cleanup
+ *
+ * Module exit function
+ */
+static void __exit tps_6235x_cleanup(void)
+{
+	i2c_del_driver(&tps_6235x_i2c_driver);
+}
+
+late_initcall(tps_6235x_init);
+module_exit(tps_6235x_cleanup);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TPS6235x based linux driver");
+MODULE_LICENSE("GPL");
-- 
1.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux