diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2011-07-10 01:58:14 +0530 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-08-18 16:40:31 -0700 |
commit | 53ccd798bc1172b7021c8929ca7ebc39244ade09 (patch) | |
tree | 88702b61c8b2e22d8c3a2b0b844d5750a9130bf4 /drivers/regulator | |
parent | ceee35acb43eac80425873f44f18a963747015c4 (diff) |
regulator: ricoh583: Add ricoh583 regulator
Adding ricoh583 regulator driver to supprot RICOH 583 PMIC.
bug 822562
Change-Id: Ie4b3aab91f2057965e2352f7a9509c651fb2ad0a
Reviewed-on: http://git-master/r/40319
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 7 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/ricoh583-regulator.c | 381 |
3 files changed, 389 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b0d889470206..ae25549efeef 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -279,6 +279,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 6b23e8664349..3d0300225bd1 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -39,6 +39,7 @@ obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-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"); |