aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGirish S Ghongdemath <girishsg@ti.com>2011-11-23 16:04:14 -0600
committerZiyann <jaraidaniel@gmail.com>2014-10-01 12:59:44 +0200
commit6b7bec685d80f0505e52ba17588234a2582960ef (patch)
treefb7fd697638ce25168e9d37fcaaeabeeaa7e5d42
parent61e6cbba9a161d17787813dc74e2b97369f26346 (diff)
downloadkernel_samsung_tuna-6b7bec685d80f0505e52ba17588234a2582960ef.zip
kernel_samsung_tuna-6b7bec685d80f0505e52ba17588234a2582960ef.tar.gz
kernel_samsung_tuna-6b7bec685d80f0505e52ba17588234a2582960ef.tar.bz2
Regulator: tps6130x: Add support for TI tps6130x regulator
Add initial support for TI tps6130x family. TPS6130x can operate as a standard boost regulator, output voltage range is 3.825-5.700V. Current source support is not added in this initial version. Ported from p-android-omap-2.6.35 Change-Id: I28c9ba1d87652b1269ab23da9e2609fb993b4460 Signed-off-by: Girish S G <girishsg@ti.com> Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com> Signed-off-by: Akash Choudhari <akashc@ti.com> Signed-off-by: Gabriel M. Beddingfield <gabrbedd@ti.com>
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/tps6130x-regulator.c419
-rw-r--r--include/linux/regulator/tps6130x.h33
4 files changed, 460 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d7ed20f..66b88b8 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -232,6 +232,13 @@ config REGULATOR_TPS6105X
It is a single boost converter primarily for white LEDs and
audio amplifiers.
+config REGULATOR_TPS6130X
+ tristate "TI TPS6130X Power regulators"
+ depends on I2C
+ help
+ This driver supports TPS6130X family. TPS6130X can operate as a
+ regulated current source and/or as a standard voltage boost converter.
+
config REGULATOR_TPS65023
tristate "TI TPS65023 Power regulators"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3932d2e..5eb253c 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -34,6 +34,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_AB3100) += ab3100.o
+obj-$(CONFIG_REGULATOR_TPS6130X) += tps6130x-regulator.o
obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o
obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o
diff --git a/drivers/regulator/tps6130x-regulator.c b/drivers/regulator/tps6130x-regulator.c
new file mode 100644
index 0000000..35fe37b
--- /dev/null
+++ b/drivers/regulator/tps6130x-regulator.c
@@ -0,0 +1,419 @@
+/*
+ * tps6130x-regulator.c
+ *
+ * Regulator driver for TPS6130x
+ *
+ * Copyright (C) 2011 Texas Instrument Incorporated - http://www.ti.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 version 2.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/tps6130x.h>
+
+/* Regulator id */
+#define TPS6130X_VOUT 0
+
+/* Register definitions */
+#define TPS6130X_REGISTER1 0x01
+#define TPS6130X_REGISTER2 0x02
+#define TPS6130X_REGISTER3 0x03
+#define TPS6130X_REGISTER4 0x04
+#define TPS6130X_REGISTER5 0x05
+#define TPS6130X_REGISTER6 0x06
+#define TPS6130X_REGISTER7 0x07
+
+/* REGISTER1 bitfields */
+#define TPS6130X_ENVM 0x80
+#define TPS6130X_MODE_CTRL_MASK 0x60
+#define TPS6130X_SHUTDOWN_MODE (0 << 5)
+#define TPS6130X_DC_LIGHT_MODE (1 << 5)
+#define TPS6130X_DC_LIGHT_FLASH_MODE (2 << 5)
+#define TPS6130X_VOUT_MODE (3 << 5)
+
+/* REGISTER6 bitfields */
+#define TPS6130X_OV_MASK 0x0F
+
+/* REGISTER7 bitfields */
+#define TPS6130X_REVID_MASK 0x07
+
+/* Supported voltage values for voltage regulation mode */
+#define TPS6130X_VOUT_MIN_UV 3825000
+#define TPS6130X_VOUT_MAX_UV 5700000
+#define TPS6130X_VOUT_STEP 125000
+#define TPS6130X_VOUT_MAX_SEL 0x0F
+
+/* Regulator specific details */
+struct tps_info {
+ const char *name;
+ int min_uV;
+ int max_uV;
+ int step;
+ int vsel_max;
+ int vsel;
+};
+
+/* PMIC details */
+struct tps_pmic {
+ struct regulator_desc *desc;
+ struct i2c_client *client;
+ struct regulator_dev *rdev;
+ struct tps6130x_platform_data *pdata;
+ struct tps_info *info;
+ struct mutex io_lock;
+ int enabled;
+};
+
+static int tps6130x_reg_read(struct tps_pmic *tps, u8 reg)
+{
+ int data;
+
+ data = i2c_smbus_read_byte_data(tps->client, reg);
+ if (data < 0)
+ dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
+
+ return data;
+}
+
+static int tps6130x_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(tps->client, reg, val);
+ if (ret < 0)
+ dev_err(&tps->client->dev, "Write to reg 0x%x failed\n", reg);
+
+ return ret;
+}
+
+static int tps6130x_update_bits(struct tps_pmic *tps, u8 reg,
+ u8 mask, u8 value)
+{
+ int old_val, new_val, ret = 0;
+
+ mutex_lock(&tps->io_lock);
+
+ old_val = tps6130x_reg_read(tps, reg);
+ if (old_val < 0) {
+ ret = old_val;
+ goto err;
+ }
+
+ new_val = (old_val & ~mask) | value;
+ if (old_val != new_val)
+ ret = tps6130x_reg_write(tps, reg, new_val);
+
+err:
+ mutex_unlock(&tps->io_lock);
+ return ret;
+}
+
+static int tps6130x_chip_enable(struct tps_pmic *tps, int on)
+{
+ struct i2c_client *client = tps->client;
+ int ret = 0;
+
+ /* tps61301/tps61305 supports external NRESET */
+ if (tps->pdata && tps->pdata->chip_enable) {
+ ret = tps->pdata->chip_enable(on);
+ if (ret) {
+ dev_err(&client->dev, "failed to enable %d\n", ret);
+ return ret;
+ }
+ }
+
+ tps->enabled = on;
+
+ return ret;
+}
+
+/* Operations permitted on VOUT */
+
+static int tps6130x_vout_is_enabled(struct regulator_dev *dev)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ int data, vout = 0;
+
+ if (!tps->enabled)
+ return 0;
+
+ data = tps6130x_reg_read(tps, TPS6130X_REGISTER1);
+ if (data < 0)
+ return data;
+
+ /* tps61300/tps61301 have ENVM to force voltage regulation mode */
+ if (data & TPS6130X_ENVM)
+ vout = 1;
+
+ /* device operating in voltage regulation mode */
+ if ((data & TPS6130X_MODE_CTRL_MASK) == TPS6130X_VOUT_MODE)
+ vout = 1;
+
+ return vout;
+}
+
+static int tps6130x_vout_enable(struct regulator_dev *dev)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ struct tps_info *info = tps->info;
+ int ret;
+
+ ret = tps6130x_chip_enable(tps, 1);
+ if (ret)
+ return ret;
+
+ /* set constant voltage source mode */
+ ret = tps6130x_update_bits(tps, TPS6130X_REGISTER1,
+ TPS6130X_MODE_CTRL_MASK,
+ TPS6130X_VOUT_MODE);
+ if (ret)
+ goto err1;
+
+ /* output voltage must be set after voltage mode has been enabled */
+ ret = tps6130x_update_bits(tps, TPS6130X_REGISTER6,
+ TPS6130X_OV_MASK, info->vsel);
+ if (ret)
+ goto err2;
+
+ return 0;
+
+err2:
+ tps6130x_update_bits(tps, TPS6130X_REGISTER1,
+ TPS6130X_MODE_CTRL_MASK,
+ TPS6130X_SHUTDOWN_MODE);
+err1:
+ tps6130x_chip_enable(tps, 0);
+ return ret;
+}
+
+static int tps6130x_vout_disable(struct regulator_dev *dev)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ int ret;
+
+ /* may not disable voltage output if ENVM is forced */
+ ret = tps6130x_update_bits(tps, TPS6130X_REGISTER1,
+ TPS6130X_MODE_CTRL_MASK,
+ TPS6130X_SHUTDOWN_MODE);
+ if (ret)
+ return ret;
+
+ ret = tps6130x_chip_enable(tps, 0);
+
+ return ret;
+}
+
+static int tps6130x_vout_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ struct tps_info *info = tps->info;
+
+ if (selector > info->vsel_max)
+ return -EINVAL;
+
+ return info->min_uV + selector * info->step;
+}
+
+static int tps6130x_vout_get_voltage(struct regulator_dev *dev)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ struct tps_info *info = tps->info;
+
+ /* output voltage cannot be read from REGISTER6 */
+ return info->min_uV + info->vsel * info->step;
+}
+
+static int tps6130x_vout_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV, unsigned *selector)
+{
+ struct tps_pmic *tps = rdev_get_drvdata(dev);
+ struct tps_info *info = tps->info;
+ int vsel, ret;
+
+ if ((min_uV < info->min_uV) || (min_uV > info->max_uV))
+ return -EINVAL;
+
+ if ((max_uV < info->min_uV) || (max_uV > info->max_uV))
+ return -EINVAL;
+
+ vsel = (min_uV - info->min_uV + (info->step - 1)) / info->step;
+
+ ret = tps6130x_vout_list_voltage(dev, vsel);
+ if ((ret < 0) || (ret > max_uV))
+ return -EINVAL;
+
+ /*
+ * new target voltage must be set after
+ * voltage mode operation has been enabled
+ */
+ info->vsel = vsel;
+ *selector = vsel;
+
+ BUG_ON(vsel < 0);
+ BUG_ON(vsel > TPS6130X_VOUT_MAX_SEL);
+
+ return 0;
+}
+
+static struct regulator_ops tps6130x_ops = {
+ .is_enabled = tps6130x_vout_is_enabled,
+ .enable = tps6130x_vout_enable,
+ .disable = tps6130x_vout_disable,
+ .get_voltage = tps6130x_vout_get_voltage,
+ .set_voltage = tps6130x_vout_set_voltage,
+ .list_voltage = tps6130x_vout_list_voltage,
+};
+
+static struct regulator_desc tps6130x_desc = {
+ .name = "VOUT",
+ .id = TPS6130X_VOUT,
+ .ops = &tps6130x_ops,
+ .n_voltages = TPS6130X_VOUT_MAX_SEL + 1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static int tps6130x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct tps_info *info = (void *)id->driver_data;
+ struct regulator_init_data *init_data;
+ struct regulator_dev *rdev;
+ struct tps_pmic *tps;
+ int revid, ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ init_data = client->dev.platform_data;
+ if (!init_data)
+ return -EIO;
+
+ tps = kzalloc(sizeof(*tps), GFP_KERNEL);
+ if (!tps)
+ return -ENOMEM;
+
+ mutex_init(&tps->io_lock);
+ tps->client = client;
+ tps->info = info;
+ tps->desc = &tps6130x_desc;
+
+ if (init_data->driver_data)
+ tps->pdata = init_data->driver_data;
+
+ /* register the regulator */
+ rdev = regulator_register(tps->desc, &client->dev, init_data, tps);
+ if (IS_ERR(rdev)) {
+ dev_err(&client->dev, "failed to register %s\n", id->name);
+ ret = PTR_ERR(rdev);
+ goto reg_err;
+ }
+
+ tps->rdev = rdev;
+ i2c_set_clientdata(client, tps);
+
+ ret = tps6130x_chip_enable(tps, 1);
+ if (ret)
+ goto enable_err;
+
+ revid = tps6130x_reg_read(tps, TPS6130X_REGISTER7);
+ if (revid < 0) {
+ dev_err(&client->dev, "failed to access device\n");
+ ret = revid;
+ goto rev_err;
+ }
+
+ dev_info(&client->dev, "Revision %d\n", revid & TPS6130X_REVID_MASK);
+
+ /* default output voltage: 4.950V */
+ tps->info->vsel = 9;
+
+ ret = tps6130x_chip_enable(tps, 0);
+ if (ret)
+ goto rev_err;
+
+ return 0;
+
+rev_err:
+ tps6130x_chip_enable(tps, 0);
+enable_err:
+ i2c_set_clientdata(client, NULL);
+ regulator_unregister(tps->rdev);
+reg_err:
+ mutex_destroy(&tps->io_lock);
+ tps->client = NULL;
+ kfree(tps);
+ return ret;
+}
+
+static int __devexit tps6130x_remove(struct i2c_client *client)
+{
+ struct tps_pmic *tps = i2c_get_clientdata(client);
+
+ regulator_unregister(tps->rdev);
+ mutex_destroy(&tps->io_lock);
+ tps->client = NULL;
+ i2c_set_clientdata(client, NULL);
+ kfree(tps);
+
+ return 0;
+}
+
+static struct tps_info tps6130x_regs = {
+ .name = "VOUT",
+ .min_uV = TPS6130X_VOUT_MIN_UV,
+ .max_uV = TPS6130X_VOUT_MAX_UV,
+ .step = TPS6130X_VOUT_STEP,
+ .vsel_max = TPS6130X_VOUT_MAX_SEL,
+};
+
+static const struct i2c_device_id tps6130x_id[] = {
+ {
+ .name = "tps6130x",
+ .driver_data = (unsigned long)&tps6130x_regs,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, tps6130x_id);
+
+static struct i2c_driver tps6130x_i2c_driver = {
+ .driver = {
+ .name = "tps6130x",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps6130x_probe,
+ .remove = __devexit_p(tps6130x_remove),
+ .id_table = tps6130x_id,
+};
+
+static int __init tps6130x_init(void)
+{
+ return i2c_add_driver(&tps6130x_i2c_driver);
+}
+subsys_initcall(tps6130x_init);
+
+static void __exit tps6130x_cleanup(void)
+{
+ i2c_del_driver(&tps6130x_i2c_driver);
+}
+module_exit(tps6130x_cleanup);
+
+MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
+MODULE_DESCRIPTION("TPS6130X voltage regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/regulator/tps6130x.h b/include/linux/regulator/tps6130x.h
new file mode 100644
index 0000000..41d5913
--- /dev/null
+++ b/include/linux/regulator/tps6130x.h
@@ -0,0 +1,33 @@
+/*
+ * tps6130x-regulator.h
+ *
+ * Regulator driver for TPS6130x
+ *
+ * Copyright (C) 2011 Texas Instrument Incorporated - http://www.ti.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 version 2.
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_REGULATOR_TPS6130X_H
+#define __LINUX_REGULATOR_TPS6130X_H
+
+/**
+ * tps6130x_platform_data - platform data for tps6130x regulator
+ * @enable: Put tps6130x in normal/reset mode (used for tps61301/tps61305)
+ * If not provided, it's assumed chip is always enabled:
+ * - tps61300/tps61306
+ * - tps61301/tps61305 with NRESET forced to low by hardware
+ */
+
+struct tps6130x_platform_data {
+ int (*chip_enable)(int on);
+};
+
+#endif