summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2011-07-10 01:58:14 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:24 -0800
commitf0b86bba4e3c35661d24a1e2594481bc9eefb6b1 (patch)
tree546d763b590155219b2eaf008894e332cd3faa41 /drivers/regulator
parentb06df72c1f361032e02320ae69e93b78e573b599 (diff)
regulator: ricoh583: Add ricoh583 regulator
Adding ricoh583 regulator driver to supprot RICOH 583 PMIC. bug 822562 Original-Change-Id: Ie4b3aab91f2057965e2352f7a9509c651fb2ad0a Reviewed-on: http://git-master/r/40319 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R0d28e8d36a4052250f2d9c20e7f463e1bbda4883
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig7
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/ricoh583-regulator.c381
3 files changed, 389 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 91cd8f1d059b..3d8793a790b2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -353,6 +353,13 @@ config REGULATOR_TPS80031
help
This driver supports TPS80031 voltage regulator chips.
+config REGULATOR_RICOH583
+ tristate "RICOH 583 Power regulators"
+ depends on MFD_RICOH583
+ default n
+ help
+ This driver supports regulator driver for RICOH583 PMIC.
+
config REGULATOR_GPIO_SWITCH
bool "GPIO based enable/disable of power rails."
default n
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 5bf68b93f955..bbfa1d15bea7 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o
obj-$(CONFIG_REGULATOR_TPS6236X) += tps6236x-regulator.o
obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o
+obj-$(CONFIG_REGULATOR_RICOH583) += ricoh583-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
diff --git a/drivers/regulator/ricoh583-regulator.c b/drivers/regulator/ricoh583-regulator.c
new file mode 100644
index 000000000000..e58eb558962f
--- /dev/null
+++ b/drivers/regulator/ricoh583-regulator.c
@@ -0,0 +1,381 @@
+/*
+ * drivers/regulator/ricoh583-regulator.c
+ *
+ * Regulator driver for RICOH583 power management chip.
+ *
+ * Copyright (C) 2011 NVIDIA Corporation
+ *
+ * Copyright (C) 2011 RICOH COMPANY,LTD
+ *
+ * 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 in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*#define DEBUG 1*/
+/*#define VERBOSE_DEBUG 1*/
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/ricoh583.h>
+#include <linux/regulator/ricoh583-regulator.h>
+
+struct ricoh583_regulator {
+ int id;
+ /* Regulator register address.*/
+ u8 reg_en_reg;
+ u8 en_bit;
+ u8 reg_disc_reg;
+ u8 disc_bit;
+ u8 vout_reg;
+ u8 vout_mask;
+ u8 deepsleep_reg;
+
+ /* chip constraints on regulator behavior */
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int nsteps;
+
+ /* regulator specific turn-on delay */
+ u16 delay;
+
+ /* used by regulator core */
+ struct regulator_desc desc;
+
+ /* Device */
+ struct device *dev;
+};
+
+static inline struct device *to_ricoh583_dev(struct regulator_dev *rdev)
+{
+ return rdev_get_dev(rdev)->parent->parent;
+}
+
+static int ricoh583_regulator_enable_time(struct regulator_dev *rdev)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+
+ return ri->delay;
+}
+
+static int ricoh583_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh583_dev(rdev);
+ uint8_t control;
+ int ret;
+
+ ret = ricoh583_read(parent, ri->reg_en_reg, &control);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in reading the control register\n");
+ return ret;
+ }
+ return (((control >> ri->en_bit) & 1) == 1);
+}
+
+static int ricoh583_reg_enable(struct regulator_dev *rdev)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh583_dev(rdev);
+ int ret;
+
+ ret = ricoh583_set_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in updating the STATE register\n");
+ return ret;
+ }
+ udelay(ri->delay);
+ return ret;
+}
+
+static int ricoh583_reg_disable(struct regulator_dev *rdev)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh583_dev(rdev);
+ int ret;
+
+ ret = ricoh583_clr_bits(parent, ri->reg_en_reg, (1 << ri->en_bit));
+ if (ret < 0)
+ dev_err(&rdev->dev, "Error in updating the STATE register\n");
+
+ return ret;
+}
+
+static int ricoh583_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+
+ return ri->min_uV * 1000 + (ri->step_uV * index);
+}
+
+static int __ricoh583_set_ds_voltage(struct device *parent,
+ struct ricoh583_regulator *ri, int min_uV, int max_uV)
+{
+ int vsel;
+ int ret;
+
+ if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+ return -EDOM;
+
+ vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+ if (vsel > ri->nsteps)
+ return -EDOM;
+
+ ret = ricoh583_update(parent, ri->deepsleep_reg, vsel, ri->vout_mask);
+ if (ret < 0)
+ dev_err(ri->dev, "Error in writing the deepsleep register\n");
+ return ret;
+}
+
+static int __ricoh583_set_voltage(struct device *parent,
+ struct ricoh583_regulator *ri, int min_uV, int max_uV)
+{
+ int vsel;
+ int ret;
+
+ if ((min_uV < ri->min_uV) || (max_uV > ri->max_uV))
+ return -EDOM;
+
+ vsel = (min_uV - ri->min_uV + ri->step_uV - 1)/ri->step_uV;
+ if (vsel > ri->nsteps)
+ return -EDOM;
+
+ ret = ricoh583_update(parent, ri->vout_reg, vsel, ri->vout_mask);
+ if (ret < 0)
+ dev_err(ri->dev, "Error in writing the Voltage register\n");
+ return ret;
+}
+
+static int ricoh583_set_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh583_dev(rdev);
+
+ return __ricoh583_set_voltage(parent, ri, min_uV, max_uV);
+}
+
+
+static int ricoh583_get_voltage(struct regulator_dev *rdev)
+{
+ struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
+ struct device *parent = to_ricoh583_dev(rdev);
+ uint8_t vsel;
+ int ret;
+
+ ret = ricoh583_read(parent, ri->vout_reg, &vsel);
+ if (ret < 0) {
+ dev_err(&rdev->dev, "Error in reading the Voltage register\n");
+ return ret;
+ }
+ vsel &= vsel & ri->vout_mask;
+ return ri->min_uV + vsel * ri->step_uV;
+}
+
+
+static struct regulator_ops ricoh583_ops = {
+ .list_voltage = ricoh583_list_voltage,
+ .set_voltage = ricoh583_set_voltage,
+ .get_voltage = ricoh583_get_voltage,
+ .enable = ricoh583_reg_enable,
+ .disable = ricoh583_reg_disable,
+ .is_enabled = ricoh583_reg_is_enabled,
+ .enable_time = ricoh583_regulator_enable_time,
+};
+
+
+#define RICOH583_REG(_id, _en_reg, _en_bit, _disc_reg, _disc_bit, _vout_reg, \
+ _vout_mask, _ds_reg, _min_mv, _max_mv, _step_uV, _nsteps, \
+ _ops, _delay) \
+{ \
+ .reg_en_reg = _en_reg, \
+ .en_bit = _en_bit, \
+ .reg_disc_reg = _disc_reg, \
+ .disc_bit = _disc_bit, \
+ .vout_reg = _vout_reg, \
+ .vout_mask = _vout_mask, \
+ .deepsleep_reg = _ds_reg, \
+ .min_uV = _min_mv * 1000, \
+ .max_uV = _max_mv * 1000, \
+ .step_uV = _step_uV, \
+ .nsteps = _nsteps, \
+ .delay = _delay, \
+ .id = RICOH583_ID_##_id, \
+ .desc = { \
+ .name = ricoh583_rails(_id), \
+ .id = RICOH583_ID_##_id, \
+ .n_voltages = _nsteps, \
+ .ops = &_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
+static struct ricoh583_regulator ricoh583_regulator[] = {
+ RICOH583_REG(DC0, 0x30, 0, 0x30, 1, 0x31, 0x7F, 0x60, 700, 1500,
+ 12500, 0x40, ricoh583_ops, 500),
+ RICOH583_REG(DC1, 0x34, 0, 0x34, 1, 0x35, 0x7F, 0x61, 700, 1500,
+ 12500, 0x40, ricoh583_ops, 500),
+ RICOH583_REG(DC2, 0x38, 0, 0x38, 1, 0x39, 0x7F, 0x62, 900, 2400,
+ 12500, 0x78, ricoh583_ops, 500),
+ RICOH583_REG(DC3, 0x3C, 0, 0x3C, 1, 0x3D, 0x7F, 0x63, 900, 2400,
+ 12500, 0x78, ricoh583_ops, 500),
+ RICOH583_REG(LDO0, 0x51, 0, 0x53, 0, 0x54, 0x7F, 0x64, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO1, 0x51, 1, 0x53, 1, 0x55, 0x7F, 0x65, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO2, 0x51, 2, 0x53, 2, 0x56, 0x7F, 0x66, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO3, 0x51, 3, 0x53, 3, 0x57, 0x7F, 0x67, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO4, 0x51, 4, 0x53, 4, 0x58, 0x3F, 0x68, 750, 1500,
+ 12500, 0x3C, ricoh583_ops, 500),
+ RICOH583_REG(LDO5, 0x51, 5, 0x53, 5, 0x59, 0x7F, 0x69, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO6, 0x51, 6, 0x53, 6, 0x5A, 0x7F, 0x6A, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO7, 0x51, 7, 0x53, 7, 0x5B, 0x7F, 0x6B, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO8, 0x50, 0, 0x52, 0, 0x5C, 0x7F, 0x6C, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+ RICOH583_REG(LDO9, 0x50, 1, 0x50, 1, 0x5D, 0x7F, 0x6D, 900, 3400,
+ 25000, 0x64, ricoh583_ops, 500),
+};
+static inline struct ricoh583_regulator *find_regulator_info(int id)
+{
+ struct ricoh583_regulator *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ricoh583_regulator); i++) {
+ ri = &ricoh583_regulator[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int ricoh583_regulator_preinit(struct device *parent,
+ struct ricoh583_regulator *ri,
+ struct ricoh583_regulator_platform_data *ricoh583_pdata)
+{
+ int ret = 0;
+
+ if (!ricoh583_pdata->init_apply)
+ return 0;
+
+ ret = __ricoh583_set_ds_voltage(parent, ri,
+ ricoh583_pdata->deepsleep_uV, ricoh583_pdata->deepsleep_uV);
+ if (ret < 0) {
+ dev_err(ri->dev, "Not able to initialize ds voltage %d "
+ "for rail %d err %d\n", ricoh583_pdata->deepsleep_uV,
+ ri->desc.id, ret);
+ return ret;
+ }
+
+ ret = __ricoh583_set_voltage(parent, ri, ricoh583_pdata->init_uV,
+ ricoh583_pdata->init_uV);
+ if (ret < 0) {
+ dev_err(ri->dev, "Not able to initialize voltage %d "
+ "for rail %d err %d\n", ricoh583_pdata->init_uV,
+ ri->desc.id, ret);
+ return ret;
+ }
+
+
+ if (ricoh583_pdata->init_enable)
+ ret = ricoh583_set_bits(parent, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ else
+ ret = ricoh583_clr_bits(parent, ri->reg_en_reg,
+ (1 << ri->en_bit));
+ if (ret < 0)
+ dev_err(ri->dev, "Not able to %s rail %d err %d\n",
+ (ricoh583_pdata->init_enable) ? "enable" : "disable",
+ ri->desc.id, ret);
+
+ return ret;
+}
+
+static int __devinit ricoh583_regulator_probe(struct platform_device *pdev)
+{
+ struct ricoh583_regulator *ri = NULL;
+ struct regulator_dev *rdev;
+ struct ricoh583_regulator_platform_data *tps_pdata;
+ int id = pdev->id;
+ int err;
+
+ dev_dbg(&pdev->dev, "Probing reulator %d\n", id);
+
+ ri = find_regulator_info(id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+ tps_pdata = pdev->dev.platform_data;
+ ri->dev = &pdev->dev;
+
+ err = ricoh583_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
+ if (err)
+ return err;
+
+ rdev = regulator_register(&ri->desc, &pdev->dev,
+ &tps_pdata->regulator, ri);
+ if (IS_ERR_OR_NULL(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit ricoh583_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver ricoh583_regulator_driver = {
+ .driver = {
+ .name = "ricoh583-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = ricoh583_regulator_probe,
+ .remove = __devexit_p(ricoh583_regulator_remove),
+};
+
+static int __init ricoh583_regulator_init(void)
+{
+ return platform_driver_register(&ricoh583_regulator_driver);
+}
+subsys_initcall(ricoh583_regulator_init);
+
+static void __exit ricoh583_regulator_exit(void)
+{
+ platform_driver_unregister(&ricoh583_regulator_driver);
+}
+module_exit(ricoh583_regulator_exit);
+
+MODULE_DESCRIPTION("RICOH583 regulator driver");
+MODULE_ALIAS("platform:ricoh583-regulator");
+MODULE_LICENSE("GPL");