blob: cd7945dcac7769d79a622b19eea17af55a6b2c39 [file] [log] [blame]
/*
* 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;
int deepsleep_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 vout_reg_cache;
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 + (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,
unsigned *selector)
{
int vsel;
int ret;
uint8_t vout_val;
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;
if (selector)
*selector = vsel;
vout_val = (ri->vout_reg_cache & ~ri->vout_mask) |
(vsel & ri->vout_mask);
ret = ricoh583_write(parent, ri->vout_reg, vout_val);
if (ret < 0)
dev_err(ri->dev, "Error in writing the Voltage register\n");
else
ri->vout_reg_cache = vout_val;
return ret;
}
static int ricoh583_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector)
{
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, selector);
}
static int ricoh583_get_voltage(struct regulator_dev *rdev)
{
struct ricoh583_regulator *ri = rdev_get_drvdata(rdev);
uint8_t vsel;
vsel = ri->vout_reg_cache & 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, \
.deepsleep_id = RICOH583_DS_##_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, 0x41, ricoh583_ops, 500),
RICOH583_REG(DC1, 0x34, 0, 0x34, 1, 0x35, 0x7F, 0x61,
700, 1500, 12500, 0x41, ricoh583_ops, 500),
RICOH583_REG(DC2, 0x38, 0, 0x38, 1, 0x39, 0x7F, 0x62,
900, 2400, 12500, 0x79, ricoh583_ops, 500),
RICOH583_REG(DC3, 0x3C, 0, 0x3C, 1, 0x3D, 0x7F, 0x63,
900, 2400, 12500, 0x79, ricoh583_ops, 500),
RICOH583_REG(LDO0, 0x51, 0, 0x53, 0, 0x54, 0x7F, 0x64,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO1, 0x51, 1, 0x53, 1, 0x55, 0x7F, 0x65,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO2, 0x51, 2, 0x53, 2, 0x56, 0x7F, 0x66,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO3, 0x51, 3, 0x53, 3, 0x57, 0x7F, 0x67,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO4, 0x51, 4, 0x53, 4, 0x58, 0x3F, 0x68,
750, 1500, 12500, 0x3D, ricoh583_ops, 500),
RICOH583_REG(LDO5, 0x51, 5, 0x53, 5, 0x59, 0x7F, 0x69,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO6, 0x51, 6, 0x53, 6, 0x5A, 0x7F, 0x6A,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO7, 0x51, 7, 0x53, 7, 0x5B, 0x7F, 0x6B,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO8, 0x50, 0, 0x52, 0, 0x5C, 0x7F, 0x6C,
900, 3400, 25000, 0x65, ricoh583_ops, 500),
RICOH583_REG(LDO9, 0x50, 1, 0x52, 1, 0x5D, 0x7F, 0x6D,
900, 3400, 25000, 0x65, 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 (ri->deepsleep_id != RICOH583_DS_NONE) {
ret = ricoh583_ext_power_req_config(parent, ri->deepsleep_id,
ricoh583_pdata->ext_pwr_req,
ricoh583_pdata->deepsleep_slots);
if (ret < 0)
return ret;
}
if (!ricoh583_pdata->init_apply)
return 0;
if (ricoh583_pdata->deepsleep_uV) {
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;
}
}
if (ricoh583_pdata->init_uV >= 0) {
ret = __ricoh583_set_voltage(parent, ri,
ricoh583_pdata->init_uV,
ricoh583_pdata->init_uV, 0);
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 inline int ricoh583_cache_regulator_register(struct device *parent,
struct ricoh583_regulator *ri)
{
ri->vout_reg_cache = 0;
return ricoh583_read(parent, ri->vout_reg, &ri->vout_reg_cache);
}
static int ricoh583_regulator_probe(struct platform_device *pdev)
{
struct ricoh583_regulator *ri = NULL;
struct regulator_dev *rdev;
struct ricoh583_regulator_platform_data *tps_pdata;
struct regulator_config config = { };
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_cache_regulator_register(pdev->dev.parent, ri);
if (err) {
dev_err(&pdev->dev, "Fail in caching register\n");
return err;
}
err = ricoh583_regulator_preinit(pdev->dev.parent, ri, tps_pdata);
if (err) {
dev_err(&pdev->dev, "Fail in pre-initialisation\n");
return err;
}
config.dev = &pdev->dev;
config.init_data = &tps_pdata->regulator;
config.driver_data = ri;
rdev = regulator_register(&ri->desc, &config);
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 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 = 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");