Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6: regulator: Add MODULE_DEVICE_TABLE to max8997 and max8998 regulator: fix tps6524x section mismatch regulator: Remove more wm831x-specific IRQ operations regulator: add ab8500 enable and raise time delays regulator: provide consumer interface for fall/rise time regulator: add set_voltage_time_sel infrastructure regulator: initialization for ab8500 regulators regulator: add support for USB voltage regulator regulator: switch the ab3100 to use enable_time() Regulator: add suspend-finish API for regulator core. regulator: fix typo in Kconfig regulator: Convert WM831x regulators to genirq regulator: If we fail when setting up a supply say which supply
This commit is contained in:
commit
18bcd0c8cb
|
@ -14,6 +14,8 @@
|
|||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/ab8500.h>
|
||||
|
||||
extern struct ab8500_regulator_reg_init
|
||||
ab8500_regulator_reg_init[AB8500_NUM_REGULATOR_REGISTERS];
|
||||
extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/amba/serial.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mfd/ab8500.h>
|
||||
#include <linux/regulator/ab8500.h>
|
||||
#include <linux/mfd/tc3589x.h>
|
||||
#include <linux/leds-lp5521.h>
|
||||
#include <linux/input.h>
|
||||
|
|
|
@ -126,7 +126,7 @@ config REGULATOR_MAX8998
|
|||
and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages.
|
||||
|
||||
config REGULATOR_TWL4030
|
||||
bool "TI TWL4030/TWL5030/TWL6030/TPS695x0 PMIC"
|
||||
bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC"
|
||||
depends on TWL4030_CORE
|
||||
help
|
||||
This driver supports the voltage regulators provided by
|
||||
|
|
|
@ -206,29 +206,6 @@ static int ab3100_enable_regulator(struct regulator_dev *reg)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* Per-regulator power on delay from spec */
|
||||
switch (abreg->regreg) {
|
||||
case AB3100_LDO_A: /* Fallthrough */
|
||||
case AB3100_LDO_C: /* Fallthrough */
|
||||
case AB3100_LDO_D: /* Fallthrough */
|
||||
case AB3100_LDO_E: /* Fallthrough */
|
||||
case AB3100_LDO_H: /* Fallthrough */
|
||||
case AB3100_LDO_K:
|
||||
udelay(200);
|
||||
break;
|
||||
case AB3100_LDO_F:
|
||||
udelay(600);
|
||||
break;
|
||||
case AB3100_LDO_G:
|
||||
udelay(400);
|
||||
break;
|
||||
case AB3100_BUCK:
|
||||
mdelay(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -450,11 +427,37 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
|
|||
return abreg->plfdata->external_voltage;
|
||||
}
|
||||
|
||||
static int ab3100_enable_time_regulator(struct regulator_dev *reg)
|
||||
{
|
||||
struct ab3100_regulator *abreg = reg->reg_data;
|
||||
|
||||
/* Per-regulator power on delay from spec */
|
||||
switch (abreg->regreg) {
|
||||
case AB3100_LDO_A: /* Fallthrough */
|
||||
case AB3100_LDO_C: /* Fallthrough */
|
||||
case AB3100_LDO_D: /* Fallthrough */
|
||||
case AB3100_LDO_E: /* Fallthrough */
|
||||
case AB3100_LDO_H: /* Fallthrough */
|
||||
case AB3100_LDO_K:
|
||||
return 200;
|
||||
case AB3100_LDO_F:
|
||||
return 600;
|
||||
case AB3100_LDO_G:
|
||||
return 400;
|
||||
case AB3100_BUCK:
|
||||
return 1000;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct regulator_ops regulator_ops_fixed = {
|
||||
.enable = ab3100_enable_regulator,
|
||||
.disable = ab3100_disable_regulator,
|
||||
.is_enabled = ab3100_is_enabled_regulator,
|
||||
.get_voltage = ab3100_get_voltage_regulator,
|
||||
.enable_time = ab3100_enable_time_regulator,
|
||||
};
|
||||
|
||||
static struct regulator_ops regulator_ops_variable = {
|
||||
|
@ -464,6 +467,7 @@ static struct regulator_ops regulator_ops_variable = {
|
|||
.get_voltage = ab3100_get_voltage_regulator,
|
||||
.set_voltage = ab3100_set_voltage_regulator,
|
||||
.list_voltage = ab3100_list_voltage_regulator,
|
||||
.enable_time = ab3100_enable_time_regulator,
|
||||
};
|
||||
|
||||
static struct regulator_ops regulator_ops_variable_sleepable = {
|
||||
|
@ -474,6 +478,7 @@ static struct regulator_ops regulator_ops_variable_sleepable = {
|
|||
.set_voltage = ab3100_set_voltage_regulator,
|
||||
.set_suspend_voltage = ab3100_set_suspend_voltage_regulator,
|
||||
.list_voltage = ab3100_list_voltage_regulator,
|
||||
.enable_time = ab3100_enable_time_regulator,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* AB8500 peripheral regulators
|
||||
*
|
||||
* AB8500 supports the following regulators:
|
||||
* VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA
|
||||
* VAUX1/2/3, VINTCORE, VTVOUT, VUSB, VAUDIO, VAMIC1/2, VDMIC, VANA
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -38,6 +38,7 @@
|
|||
* @voltage_mask: mask to control regulator voltage
|
||||
* @voltages: supported voltage table
|
||||
* @voltages_len: number of supported voltages for the regulator
|
||||
* @delay: startup/set voltage delay in us
|
||||
*/
|
||||
struct ab8500_regulator_info {
|
||||
struct device *dev;
|
||||
|
@ -55,6 +56,7 @@ struct ab8500_regulator_info {
|
|||
u8 voltage_mask;
|
||||
int const *voltages;
|
||||
int voltages_len;
|
||||
unsigned int delay;
|
||||
};
|
||||
|
||||
/* voltage tables for the vauxn/vintcore supplies */
|
||||
|
@ -290,6 +292,29 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int ab8500_regulator_enable_time(struct regulator_dev *rdev)
|
||||
{
|
||||
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
|
||||
return info->delay;
|
||||
}
|
||||
|
||||
static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
|
||||
unsigned int old_sel,
|
||||
unsigned int new_sel)
|
||||
{
|
||||
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
|
||||
int ret;
|
||||
|
||||
/* If the regulator isn't on, it won't take time here */
|
||||
ret = ab8500_regulator_is_enabled(rdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!ret)
|
||||
return 0;
|
||||
return info->delay;
|
||||
}
|
||||
|
||||
static struct regulator_ops ab8500_regulator_ops = {
|
||||
.enable = ab8500_regulator_enable,
|
||||
.disable = ab8500_regulator_disable,
|
||||
|
@ -297,6 +322,8 @@ static struct regulator_ops ab8500_regulator_ops = {
|
|||
.get_voltage = ab8500_regulator_get_voltage,
|
||||
.set_voltage = ab8500_regulator_set_voltage,
|
||||
.list_voltage = ab8500_list_voltage,
|
||||
.enable_time = ab8500_regulator_enable_time,
|
||||
.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
|
||||
};
|
||||
|
||||
static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
|
||||
|
@ -317,6 +344,8 @@ static struct regulator_ops ab8500_regulator_fixed_ops = {
|
|||
.is_enabled = ab8500_regulator_is_enabled,
|
||||
.get_voltage = ab8500_fixed_get_voltage,
|
||||
.list_voltage = ab8500_list_voltage,
|
||||
.enable_time = ab8500_regulator_enable_time,
|
||||
.set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
|
||||
};
|
||||
|
||||
static struct ab8500_regulator_info
|
||||
|
@ -426,12 +455,28 @@ static struct ab8500_regulator_info
|
|||
.owner = THIS_MODULE,
|
||||
.n_voltages = 1,
|
||||
},
|
||||
.delay = 10000,
|
||||
.fixed_uV = 2000000,
|
||||
.update_bank = 0x03,
|
||||
.update_reg = 0x80,
|
||||
.update_mask = 0x82,
|
||||
.update_val_enable = 0x02,
|
||||
},
|
||||
[AB8500_LDO_USB] = {
|
||||
.desc = {
|
||||
.name = "LDO-USB",
|
||||
.ops = &ab8500_regulator_fixed_ops,
|
||||
.type = REGULATOR_VOLTAGE,
|
||||
.id = AB8500_LDO_USB,
|
||||
.owner = THIS_MODULE,
|
||||
.n_voltages = 1,
|
||||
},
|
||||
.fixed_uV = 3300000,
|
||||
.update_bank = 0x03,
|
||||
.update_reg = 0x82,
|
||||
.update_mask = 0x03,
|
||||
.update_val_enable = 0x01,
|
||||
},
|
||||
[AB8500_LDO_AUDIO] = {
|
||||
.desc = {
|
||||
.name = "LDO-AUDIO",
|
||||
|
@ -511,6 +556,186 @@ static struct ab8500_regulator_info
|
|||
|
||||
};
|
||||
|
||||
struct ab8500_reg_init {
|
||||
u8 bank;
|
||||
u8 addr;
|
||||
u8 mask;
|
||||
};
|
||||
|
||||
#define REG_INIT(_id, _bank, _addr, _mask) \
|
||||
[_id] = { \
|
||||
.bank = _bank, \
|
||||
.addr = _addr, \
|
||||
.mask = _mask, \
|
||||
}
|
||||
|
||||
static struct ab8500_reg_init ab8500_reg_init[] = {
|
||||
/*
|
||||
* 0x30, VanaRequestCtrl
|
||||
* 0x0C, VpllRequestCtrl
|
||||
* 0xc0, VextSupply1RequestCtrl
|
||||
*/
|
||||
REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc),
|
||||
/*
|
||||
* 0x03, VextSupply2RequestCtrl
|
||||
* 0x0c, VextSupply3RequestCtrl
|
||||
* 0x30, Vaux1RequestCtrl
|
||||
* 0xc0, Vaux2RequestCtrl
|
||||
*/
|
||||
REG_INIT(AB8500_REGUREQUESTCTRL3, 0x03, 0x05, 0xff),
|
||||
/*
|
||||
* 0x03, Vaux3RequestCtrl
|
||||
* 0x04, SwHPReq
|
||||
*/
|
||||
REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07),
|
||||
/*
|
||||
* 0x08, VanaSysClkReq1HPValid
|
||||
* 0x20, Vaux1SysClkReq1HPValid
|
||||
* 0x40, Vaux2SysClkReq1HPValid
|
||||
* 0x80, Vaux3SysClkReq1HPValid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8),
|
||||
/*
|
||||
* 0x10, VextSupply1SysClkReq1HPValid
|
||||
* 0x20, VextSupply2SysClkReq1HPValid
|
||||
* 0x40, VextSupply3SysClkReq1HPValid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70),
|
||||
/*
|
||||
* 0x08, VanaHwHPReq1Valid
|
||||
* 0x20, Vaux1HwHPReq1Valid
|
||||
* 0x40, Vaux2HwHPReq1Valid
|
||||
* 0x80, Vaux3HwHPReq1Valid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8),
|
||||
/*
|
||||
* 0x01, VextSupply1HwHPReq1Valid
|
||||
* 0x02, VextSupply2HwHPReq1Valid
|
||||
* 0x04, VextSupply3HwHPReq1Valid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07),
|
||||
/*
|
||||
* 0x08, VanaHwHPReq2Valid
|
||||
* 0x20, Vaux1HwHPReq2Valid
|
||||
* 0x40, Vaux2HwHPReq2Valid
|
||||
* 0x80, Vaux3HwHPReq2Valid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8),
|
||||
/*
|
||||
* 0x01, VextSupply1HwHPReq2Valid
|
||||
* 0x02, VextSupply2HwHPReq2Valid
|
||||
* 0x04, VextSupply3HwHPReq2Valid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07),
|
||||
/*
|
||||
* 0x20, VanaSwHPReqValid
|
||||
* 0x80, Vaux1SwHPReqValid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0),
|
||||
/*
|
||||
* 0x01, Vaux2SwHPReqValid
|
||||
* 0x02, Vaux3SwHPReqValid
|
||||
* 0x04, VextSupply1SwHPReqValid
|
||||
* 0x08, VextSupply2SwHPReqValid
|
||||
* 0x10, VextSupply3SwHPReqValid
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f),
|
||||
/*
|
||||
* 0x02, SysClkReq2Valid1
|
||||
* ...
|
||||
* 0x80, SysClkReq8Valid1
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSYSCLKREQVALID1, 0x03, 0x0f, 0xfe),
|
||||
/*
|
||||
* 0x02, SysClkReq2Valid2
|
||||
* ...
|
||||
* 0x80, SysClkReq8Valid2
|
||||
*/
|
||||
REG_INIT(AB8500_REGUSYSCLKREQVALID2, 0x03, 0x10, 0xfe),
|
||||
/*
|
||||
* 0x02, VTVoutEna
|
||||
* 0x04, Vintcore12Ena
|
||||
* 0x38, Vintcore12Sel
|
||||
* 0x40, Vintcore12LP
|
||||
* 0x80, VTVoutLP
|
||||
*/
|
||||
REG_INIT(AB8500_REGUMISC1, 0x03, 0x80, 0xfe),
|
||||
/*
|
||||
* 0x02, VaudioEna
|
||||
* 0x04, VdmicEna
|
||||
* 0x08, Vamic1Ena
|
||||
* 0x10, Vamic2Ena
|
||||
*/
|
||||
REG_INIT(AB8500_VAUDIOSUPPLY, 0x03, 0x83, 0x1e),
|
||||
/*
|
||||
* 0x01, Vamic1_dzout
|
||||
* 0x02, Vamic2_dzout
|
||||
*/
|
||||
REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03),
|
||||
/*
|
||||
* 0x0c, VanaRegu
|
||||
* 0x03, VpllRegu
|
||||
*/
|
||||
REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f),
|
||||
/*
|
||||
* 0x01, VrefDDREna
|
||||
* 0x02, VrefDDRSleepMode
|
||||
*/
|
||||
REG_INIT(AB8500_VREFDDR, 0x04, 0x07, 0x03),
|
||||
/*
|
||||
* 0x03, VextSupply1Regu
|
||||
* 0x0c, VextSupply2Regu
|
||||
* 0x30, VextSupply3Regu
|
||||
* 0x40, ExtSupply2Bypass
|
||||
* 0x80, ExtSupply3Bypass
|
||||
*/
|
||||
REG_INIT(AB8500_EXTSUPPLYREGU, 0x04, 0x08, 0xff),
|
||||
/*
|
||||
* 0x03, Vaux1Regu
|
||||
* 0x0c, Vaux2Regu
|
||||
*/
|
||||
REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f),
|
||||
/*
|
||||
* 0x03, Vaux3Regu
|
||||
*/
|
||||
REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03),
|
||||
/*
|
||||
* 0x3f, Vsmps1Sel1
|
||||
*/
|
||||
REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f),
|
||||
/*
|
||||
* 0x0f, Vaux1Sel
|
||||
*/
|
||||
REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f),
|
||||
/*
|
||||
* 0x0f, Vaux2Sel
|
||||
*/
|
||||
REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f),
|
||||
/*
|
||||
* 0x07, Vaux3Sel
|
||||
*/
|
||||
REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07),
|
||||
/*
|
||||
* 0x01, VextSupply12LP
|
||||
*/
|
||||
REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01),
|
||||
/*
|
||||
* 0x04, Vaux1Disch
|
||||
* 0x08, Vaux2Disch
|
||||
* 0x10, Vaux3Disch
|
||||
* 0x20, Vintcore12Disch
|
||||
* 0x40, VTVoutDisch
|
||||
* 0x80, VaudioDisch
|
||||
*/
|
||||
REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc),
|
||||
/*
|
||||
* 0x02, VanaDisch
|
||||
* 0x04, VdmicPullDownEna
|
||||
* 0x10, VdmicDisch
|
||||
*/
|
||||
REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16),
|
||||
};
|
||||
|
||||
static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
|
||||
|
@ -529,10 +754,51 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev)
|
|||
|
||||
/* make sure the platform data has the correct size */
|
||||
if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) {
|
||||
dev_err(&pdev->dev, "platform configuration error\n");
|
||||
dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* initialize registers */
|
||||
for (i = 0; i < pdata->num_regulator_reg_init; i++) {
|
||||
int id;
|
||||
u8 value;
|
||||
|
||||
id = pdata->regulator_reg_init[i].id;
|
||||
value = pdata->regulator_reg_init[i].value;
|
||||
|
||||
/* check for configuration errors */
|
||||
if (id >= AB8500_NUM_REGULATOR_REGISTERS) {
|
||||
dev_err(&pdev->dev,
|
||||
"Configuration error: id outside range.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (value & ~ab8500_reg_init[id].mask) {
|
||||
dev_err(&pdev->dev,
|
||||
"Configuration error: value outside mask.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* initialize register */
|
||||
err = abx500_mask_and_set_register_interruptible(&pdev->dev,
|
||||
ab8500_reg_init[id].bank,
|
||||
ab8500_reg_init[id].addr,
|
||||
ab8500_reg_init[id].mask,
|
||||
value);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to initialize 0x%02x, 0x%02x.\n",
|
||||
ab8500_reg_init[id].bank,
|
||||
ab8500_reg_init[id].addr);
|
||||
return err;
|
||||
}
|
||||
dev_vdbg(&pdev->dev,
|
||||
" init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
|
||||
ab8500_reg_init[id].bank,
|
||||
ab8500_reg_init[id].addr,
|
||||
ab8500_reg_init[id].mask,
|
||||
value);
|
||||
}
|
||||
|
||||
/* register all regulators */
|
||||
for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
|
||||
struct ab8500_regulator_info *info = NULL;
|
||||
|
|
|
@ -1629,6 +1629,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
int min_uV, int max_uV)
|
||||
{
|
||||
int ret;
|
||||
int delay = 0;
|
||||
unsigned int selector;
|
||||
|
||||
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
|
||||
|
@ -1662,6 +1663,22 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we can't obtain the old selector there is not enough
|
||||
* info to call set_voltage_time_sel().
|
||||
*/
|
||||
if (rdev->desc->ops->set_voltage_time_sel &&
|
||||
rdev->desc->ops->get_voltage_sel) {
|
||||
unsigned int old_selector = 0;
|
||||
|
||||
ret = rdev->desc->ops->get_voltage_sel(rdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
old_selector = ret;
|
||||
delay = rdev->desc->ops->set_voltage_time_sel(rdev,
|
||||
old_selector, selector);
|
||||
}
|
||||
|
||||
if (best_val != INT_MAX) {
|
||||
ret = rdev->desc->ops->set_voltage_sel(rdev, selector);
|
||||
selector = best_val;
|
||||
|
@ -1672,6 +1689,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
|
|||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* Insert any necessary delays */
|
||||
if (delay >= 1000) {
|
||||
mdelay(delay / 1000);
|
||||
udelay(delay % 1000);
|
||||
} else if (delay) {
|
||||
udelay(delay);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
_notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
|
||||
NULL);
|
||||
|
@ -1739,6 +1764,51 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_voltage);
|
||||
|
||||
/**
|
||||
* regulator_set_voltage_time - get raise/fall time
|
||||
* @regulator: regulator source
|
||||
* @old_uV: starting voltage in microvolts
|
||||
* @new_uV: target voltage in microvolts
|
||||
*
|
||||
* Provided with the starting and ending voltage, this function attempts to
|
||||
* calculate the time in microseconds required to rise or fall to this new
|
||||
* voltage.
|
||||
*/
|
||||
int regulator_set_voltage_time(struct regulator *regulator,
|
||||
int old_uV, int new_uV)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
struct regulator_ops *ops = rdev->desc->ops;
|
||||
int old_sel = -1;
|
||||
int new_sel = -1;
|
||||
int voltage;
|
||||
int i;
|
||||
|
||||
/* Currently requires operations to do this */
|
||||
if (!ops->list_voltage || !ops->set_voltage_time_sel
|
||||
|| !rdev->desc->n_voltages)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < rdev->desc->n_voltages; i++) {
|
||||
/* We only look for exact voltage matches here */
|
||||
voltage = regulator_list_voltage(regulator, i);
|
||||
if (voltage < 0)
|
||||
return -EINVAL;
|
||||
if (voltage == 0)
|
||||
continue;
|
||||
if (voltage == old_uV)
|
||||
old_sel = i;
|
||||
if (voltage == new_uV)
|
||||
new_sel = i;
|
||||
}
|
||||
|
||||
if (old_sel < 0 || new_sel < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ops->set_voltage_time_sel(rdev, old_sel, new_sel);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_set_voltage_time);
|
||||
|
||||
/**
|
||||
* regulator_sync_voltage - re-apply last regulator output voltage
|
||||
* @regulator: regulator source
|
||||
|
@ -2565,8 +2635,11 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
|
|||
init_data->consumer_supplies[i].dev,
|
||||
init_data->consumer_supplies[i].dev_name,
|
||||
init_data->consumer_supplies[i].supply);
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set supply %s\n",
|
||||
init_data->consumer_supplies[i].supply);
|
||||
goto unset_supplies;
|
||||
}
|
||||
}
|
||||
|
||||
list_add(&rdev->list, ®ulator_list);
|
||||
|
@ -2652,6 +2725,47 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_suspend_prepare);
|
||||
|
||||
/**
|
||||
* regulator_suspend_finish - resume regulators from system wide suspend
|
||||
*
|
||||
* Turn on regulators that might be turned off by regulator_suspend_prepare
|
||||
* and that should be turned on according to the regulators properties.
|
||||
*/
|
||||
int regulator_suspend_finish(void)
|
||||
{
|
||||
struct regulator_dev *rdev;
|
||||
int ret = 0, error;
|
||||
|
||||
mutex_lock(®ulator_list_mutex);
|
||||
list_for_each_entry(rdev, ®ulator_list, list) {
|
||||
struct regulator_ops *ops = rdev->desc->ops;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
if ((rdev->use_count > 0 || rdev->constraints->always_on) &&
|
||||
ops->enable) {
|
||||
error = ops->enable(rdev);
|
||||
if (error)
|
||||
ret = error;
|
||||
} else {
|
||||
if (!has_full_constraints)
|
||||
goto unlock;
|
||||
if (!ops->disable)
|
||||
goto unlock;
|
||||
if (ops->is_enabled && !ops->is_enabled(rdev))
|
||||
goto unlock;
|
||||
|
||||
error = ops->disable(rdev);
|
||||
if (error)
|
||||
ret = error;
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&rdev->mutex);
|
||||
}
|
||||
mutex_unlock(®ulator_list_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_suspend_finish);
|
||||
|
||||
/**
|
||||
* regulator_has_full_constraints - the system has fully specified constraints
|
||||
*
|
||||
|
|
|
@ -1185,6 +1185,7 @@ static const struct platform_device_id max8997_pmic_id[] = {
|
|||
{ "max8997-pmic", 0},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max8997_pmic_id);
|
||||
|
||||
static struct platform_driver max8997_pmic_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -887,6 +887,7 @@ static const struct platform_device_id max8998_pmic_id[] = {
|
|||
{ "lp3974-pmic", TYPE_LP3974 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, max8998_pmic_id);
|
||||
|
||||
static struct platform_driver max8998_pmic_driver = {
|
||||
.driver = {
|
||||
|
|
|
@ -596,7 +596,7 @@ static struct regulator_ops regulator_ops = {
|
|||
.get_current_limit = get_current_limit,
|
||||
};
|
||||
|
||||
static int __devexit pmic_remove(struct spi_device *spi)
|
||||
static int pmic_remove(struct spi_device *spi)
|
||||
{
|
||||
struct tps6524x *hw = spi_get_drvdata(spi);
|
||||
int i;
|
||||
|
|
|
@ -565,9 +565,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "UV");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name,
|
||||
dcdc);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name, dcdc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -575,9 +574,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "HC");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_oc_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name,
|
||||
dcdc);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_dcdc_oc_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name, dcdc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request HC IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -589,7 +587,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
err_uv:
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
err_regulator:
|
||||
regulator_unregister(dcdc->regulator);
|
||||
err:
|
||||
|
@ -606,8 +604,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "HC"), dcdc);
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
free_irq(platform_get_irq_byname(pdev, "HC"), dcdc);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
regulator_unregister(dcdc->regulator);
|
||||
if (dcdc->dvs_gpio)
|
||||
gpio_free(dcdc->dvs_gpio);
|
||||
|
@ -756,9 +754,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "UV");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name,
|
||||
dcdc);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name, dcdc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -783,7 +780,7 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
regulator_unregister(dcdc->regulator);
|
||||
kfree(dcdc);
|
||||
|
||||
|
@ -885,9 +882,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "UV");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name,
|
||||
dcdc);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_dcdc_uv_irq,
|
||||
IRQF_TRIGGER_RISING, dcdc->name,
|
||||
dcdc);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -908,11 +905,10 @@ err:
|
|||
static __devexit int wm831x_boostp_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
|
||||
struct wm831x *wm831x = dcdc->wm831x;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), dcdc);
|
||||
regulator_unregister(dcdc->regulator);
|
||||
kfree(dcdc);
|
||||
|
||||
|
|
|
@ -198,9 +198,8 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_isink_irq,
|
||||
IRQF_TRIGGER_RISING, isink->name,
|
||||
isink);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_isink_irq,
|
||||
IRQF_TRIGGER_RISING, isink->name, isink);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request ISINK IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -221,11 +220,10 @@ err:
|
|||
static __devexit int wm831x_isink_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_isink *isink = platform_get_drvdata(pdev);
|
||||
struct wm831x *wm831x = isink->wm831x;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink);
|
||||
free_irq(platform_get_irq(pdev, 0), isink);
|
||||
|
||||
regulator_unregister(isink->regulator);
|
||||
kfree(isink);
|
||||
|
|
|
@ -354,9 +354,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "UV");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq,
|
||||
IRQF_TRIGGER_RISING, ldo->name,
|
||||
ldo);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
|
||||
IRQF_TRIGGER_RISING, ldo->name,
|
||||
ldo);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -377,11 +377,10 @@ err:
|
|||
static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
|
||||
struct wm831x *wm831x = ldo->wm831x;
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), ldo);
|
||||
regulator_unregister(ldo->regulator);
|
||||
kfree(ldo);
|
||||
|
||||
|
@ -619,9 +618,8 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
irq = platform_get_irq_byname(pdev, "UV");
|
||||
ret = wm831x_request_irq(wm831x, irq, wm831x_ldo_uv_irq,
|
||||
IRQF_TRIGGER_RISING, ldo->name,
|
||||
ldo);
|
||||
ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
|
||||
IRQF_TRIGGER_RISING, ldo->name, ldo);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
|
||||
irq, ret);
|
||||
|
@ -642,9 +640,8 @@ err:
|
|||
static __devexit int wm831x_aldo_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
|
||||
struct wm831x *wm831x = ldo->wm831x;
|
||||
|
||||
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo);
|
||||
free_irq(platform_get_irq_byname(pdev, "UV"), ldo);
|
||||
regulator_unregister(ldo->regulator);
|
||||
kfree(ldo);
|
||||
|
||||
|
|
|
@ -139,17 +139,23 @@ struct ab8500 {
|
|||
u8 oldmask[AB8500_NUM_IRQ_REGS];
|
||||
};
|
||||
|
||||
struct regulator_reg_init;
|
||||
struct regulator_init_data;
|
||||
|
||||
/**
|
||||
* struct ab8500_platform_data - AB8500 platform data
|
||||
* @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used
|
||||
* @init: board-specific initialization after detection of ab8500
|
||||
* @num_regulator_reg_init: number of regulator init registers
|
||||
* @regulator_reg_init: regulator init registers
|
||||
* @num_regulator: number of regulators
|
||||
* @regulator: machine-specific constraints for regulators
|
||||
*/
|
||||
struct ab8500_platform_data {
|
||||
int irq_base;
|
||||
void (*init) (struct ab8500 *);
|
||||
int num_regulator_reg_init;
|
||||
struct ab8500_regulator_reg_init *regulator_reg_init;
|
||||
int num_regulator;
|
||||
struct regulator_init_data *regulator;
|
||||
};
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
*
|
||||
* License Terms: GNU General Public License v2
|
||||
*
|
||||
* Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
|
||||
*
|
||||
* Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
|
||||
* Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_MFD_AB8500_REGULATOR_H
|
||||
|
@ -17,6 +17,7 @@ enum ab8500_regulator_id {
|
|||
AB8500_LDO_AUX3,
|
||||
AB8500_LDO_INTCORE,
|
||||
AB8500_LDO_TVOUT,
|
||||
AB8500_LDO_USB,
|
||||
AB8500_LDO_AUDIO,
|
||||
AB8500_LDO_ANAMIC1,
|
||||
AB8500_LDO_ANAMIC2,
|
||||
|
@ -24,4 +25,50 @@ enum ab8500_regulator_id {
|
|||
AB8500_LDO_ANA,
|
||||
AB8500_NUM_REGULATORS,
|
||||
};
|
||||
|
||||
/* AB8500 register initialization */
|
||||
struct ab8500_regulator_reg_init {
|
||||
int id;
|
||||
u8 value;
|
||||
};
|
||||
|
||||
#define INIT_REGULATOR_REGISTER(_id, _value) \
|
||||
{ \
|
||||
.id = _id, \
|
||||
.value = _value, \
|
||||
}
|
||||
|
||||
/* AB8500 registers */
|
||||
enum ab8500_regulator_reg {
|
||||
AB8500_REGUREQUESTCTRL2,
|
||||
AB8500_REGUREQUESTCTRL3,
|
||||
AB8500_REGUREQUESTCTRL4,
|
||||
AB8500_REGUSYSCLKREQ1HPVALID1,
|
||||
AB8500_REGUSYSCLKREQ1HPVALID2,
|
||||
AB8500_REGUHWHPREQ1VALID1,
|
||||
AB8500_REGUHWHPREQ1VALID2,
|
||||
AB8500_REGUHWHPREQ2VALID1,
|
||||
AB8500_REGUHWHPREQ2VALID2,
|
||||
AB8500_REGUSWHPREQVALID1,
|
||||
AB8500_REGUSWHPREQVALID2,
|
||||
AB8500_REGUSYSCLKREQVALID1,
|
||||
AB8500_REGUSYSCLKREQVALID2,
|
||||
AB8500_REGUMISC1,
|
||||
AB8500_VAUDIOSUPPLY,
|
||||
AB8500_REGUCTRL1VAMIC,
|
||||
AB8500_VPLLVANAREGU,
|
||||
AB8500_VREFDDR,
|
||||
AB8500_EXTSUPPLYREGU,
|
||||
AB8500_VAUX12REGU,
|
||||
AB8500_VRF1VAUX3REGU,
|
||||
AB8500_VAUX1SEL,
|
||||
AB8500_VAUX2SEL,
|
||||
AB8500_VRF1VAUX3SEL,
|
||||
AB8500_REGUCTRL2SPARE,
|
||||
AB8500_REGUCTRLDISCH,
|
||||
AB8500_REGUCTRLDISCH2,
|
||||
AB8500_VSMPS1SEL1,
|
||||
AB8500_NUM_REGULATOR_REGISTERS,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -153,6 +153,8 @@ int regulator_list_voltage(struct regulator *regulator, unsigned selector);
|
|||
int regulator_is_supported_voltage(struct regulator *regulator,
|
||||
int min_uV, int max_uV);
|
||||
int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV);
|
||||
int regulator_set_voltage_time(struct regulator *regulator,
|
||||
int old_uV, int new_uV);
|
||||
int regulator_get_voltage(struct regulator *regulator);
|
||||
int regulator_sync_voltage(struct regulator *regulator);
|
||||
int regulator_set_current_limit(struct regulator *regulator,
|
||||
|
|
|
@ -63,7 +63,11 @@ enum regulator_status {
|
|||
* when running with the specified parameters.
|
||||
*
|
||||
* @enable_time: Time taken for the regulator voltage output voltage to
|
||||
* stabalise after being enabled, in microseconds.
|
||||
* stabilise after being enabled, in microseconds.
|
||||
* @set_voltage_time_sel: Time taken for the regulator voltage output voltage
|
||||
* to stabilise after being set to a new value, in microseconds.
|
||||
* The function provides the from and to voltage selector, the
|
||||
* function should return the worst case.
|
||||
*
|
||||
* @set_suspend_voltage: Set the voltage for the regulator when the system
|
||||
* is suspended.
|
||||
|
@ -103,8 +107,11 @@ struct regulator_ops {
|
|||
int (*set_mode) (struct regulator_dev *, unsigned int mode);
|
||||
unsigned int (*get_mode) (struct regulator_dev *);
|
||||
|
||||
/* Time taken to enable the regulator */
|
||||
/* Time taken to enable or set voltage on the regulator */
|
||||
int (*enable_time) (struct regulator_dev *);
|
||||
int (*set_voltage_time_sel) (struct regulator_dev *,
|
||||
unsigned int old_selector,
|
||||
unsigned int new_selector);
|
||||
|
||||
/* report regulator status ... most other accessors report
|
||||
* control inputs, this reports results of combining inputs
|
||||
|
|
|
@ -186,6 +186,7 @@ struct regulator_init_data {
|
|||
};
|
||||
|
||||
int regulator_suspend_prepare(suspend_state_t state);
|
||||
int regulator_suspend_finish(void);
|
||||
|
||||
#ifdef CONFIG_REGULATOR
|
||||
void regulator_has_full_constraints(void);
|
||||
|
|
Loading…
Reference in New Issue