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: (27 commits)
  Regulators: wm8400 - cleanup platform driver data handling
  Regulators: wm8994 - clean up driver data after removal
  Regulators: wm831x-xxx - clean up driver data after removal
  Regulators: pcap-regulator - clean up driver data after removal
  Regulators: max8660 - annotate probe and remove methods
  Regulators: max1586 - annotate probe and remove methods
  Regulators: lp3971 - fail if platform data was not supplied
  Regulators: tps6507x-regulator - mark probe method as __devinit
  Regulators: tps65023-regulator - mark probe method as __devinit
  Regulators: twl-regulator - mark probe function as __devinit
  Regulators: fixed - annotate probe and remove methods
  Regulators: ab3100 - fix probe and remove annotations
  Regulators: virtual - use sysfs attribute groups
  twl6030: regulator: Configure STATE register instead of REMAP
  regulator: Provide optional dummy regulator for consumers
  regulator: Assume regulators are enabled if they don't report anything
  regulator: Convert fixed voltage regulator to use enable_time()
  regulator: Add WM8994 regulator support
  regulator: enable max8649 regulator driver
  regulator: trivial: fix typos in user-visible Kconfig text
  ...
This commit is contained in:
Linus Torvalds 2010-03-04 07:52:06 -08:00
commit c8bf9fec47
28 changed files with 1622 additions and 184 deletions

View File

@ -27,6 +27,17 @@ config REGULATOR_DEBUG
help help
Say yes here to enable debugging support. Say yes here to enable debugging support.
config REGULATOR_DUMMY
bool "Provide a dummy regulator if regulator lookups fail"
help
If this option is enabled then when a regulator lookup fails
and the board has not specified that it has provided full
constraints then the regulator core will provide an always
enabled dummy regulator will be provided, allowing consumer
drivers to continue.
A warning will be generated when this substitution is done.
config REGULATOR_FIXED_VOLTAGE config REGULATOR_FIXED_VOLTAGE
tristate "Fixed voltage regulator support" tristate "Fixed voltage regulator support"
help help
@ -69,6 +80,13 @@ config REGULATOR_MAX1586
regulator via I2C bus. The provided regulator is suitable regulator via I2C bus. The provided regulator is suitable
for PXA27x chips to control VCC_CORE and VCC_USIM voltages. for PXA27x chips to control VCC_CORE and VCC_USIM voltages.
config REGULATOR_MAX8649
tristate "Maxim 8649 voltage regulator"
depends on I2C
help
This driver controls a Maxim 8649 voltage output regulator via
I2C bus.
config REGULATOR_MAX8660 config REGULATOR_MAX8660
tristate "Maxim 8660/8661 voltage regulator" tristate "Maxim 8660/8661 voltage regulator"
depends on I2C depends on I2C
@ -91,19 +109,26 @@ config REGULATOR_WM831X
of PMIC devices. of PMIC devices.
config REGULATOR_WM8350 config REGULATOR_WM8350
tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC" tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC"
depends on MFD_WM8350 depends on MFD_WM8350
help help
This driver provides support for the voltage and current regulators This driver provides support for the voltage and current regulators
of the WM8350 AudioPlus PMIC. of the WM8350 AudioPlus PMIC.
config REGULATOR_WM8400 config REGULATOR_WM8400
tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC" tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"
depends on MFD_WM8400 depends on MFD_WM8400
help help
This driver provides support for the voltage regulators of the This driver provides support for the voltage regulators of the
WM8400 AudioPlus PMIC. WM8400 AudioPlus PMIC.
config REGULATOR_WM8994
tristate "Wolfson Microelectronics WM8994 CODEC"
depends on MFD_WM8994
help
This driver provides support for the voltage regulators on the
WM8994 CODEC.
config REGULATOR_DA903X config REGULATOR_DA903X
tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC" tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
depends on PMIC_DA903X depends on PMIC_DA903X

View File

@ -9,15 +9,18 @@ obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o
obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-ldo.o
obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o
obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o

View File

@ -561,7 +561,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
* for all the different regulators. * for all the different regulators.
*/ */
static int __init ab3100_regulators_probe(struct platform_device *pdev) static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
{ {
struct ab3100_platform_data *plfdata = pdev->dev.platform_data; struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
struct ab3100 *ab3100 = platform_get_drvdata(pdev); struct ab3100 *ab3100 = platform_get_drvdata(pdev);
@ -641,7 +641,7 @@ static int __init ab3100_regulators_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int __exit ab3100_regulators_remove(struct platform_device *pdev) static int __devexit ab3100_regulators_remove(struct platform_device *pdev)
{ {
int i; int i;
@ -659,7 +659,7 @@ static struct platform_driver ab3100_regulators_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = ab3100_regulators_probe, .probe = ab3100_regulators_probe,
.remove = __exit_p(ab3100_regulators_remove), .remove = __devexit_p(ab3100_regulators_remove),
}; };
static __init int ab3100_regulators_init(void) static __init int ab3100_regulators_init(void)

View File

@ -19,10 +19,13 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/delay.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include "dummy.h"
#define REGULATOR_VERSION "0.5" #define REGULATOR_VERSION "0.5"
static DEFINE_MUTEX(regulator_list_mutex); static DEFINE_MUTEX(regulator_list_mutex);
@ -1084,6 +1087,13 @@ overflow_err:
return NULL; return NULL;
} }
static int _regulator_get_enable_time(struct regulator_dev *rdev)
{
if (!rdev->desc->ops->enable_time)
return 0;
return rdev->desc->ops->enable_time(rdev);
}
/* Internal regulator request function */ /* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id, static struct regulator *_regulator_get(struct device *dev, const char *id,
int exclusive) int exclusive)
@ -1115,6 +1125,22 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,
goto found; goto found;
} }
} }
#ifdef CONFIG_REGULATOR_DUMMY
if (!devname)
devname = "deviceless";
/* If the board didn't flag that it was fully constrained then
* substitute in a dummy regulator so consumers can continue.
*/
if (!has_full_constraints) {
pr_warning("%s supply %s not found, using dummy regulator\n",
devname, id);
rdev = dummy_regulator_rdev;
goto found;
}
#endif
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
return regulator; return regulator;
@ -1251,7 +1277,7 @@ static int _regulator_can_change_status(struct regulator_dev *rdev)
/* locks held by regulator_enable() */ /* locks held by regulator_enable() */
static int _regulator_enable(struct regulator_dev *rdev) static int _regulator_enable(struct regulator_dev *rdev)
{ {
int ret; int ret, delay;
/* do we need to enable the supply regulator first */ /* do we need to enable the supply regulator first */
if (rdev->supply) { if (rdev->supply) {
@ -1275,13 +1301,34 @@ static int _regulator_enable(struct regulator_dev *rdev)
if (!_regulator_can_change_status(rdev)) if (!_regulator_can_change_status(rdev))
return -EPERM; return -EPERM;
if (rdev->desc->ops->enable) { if (!rdev->desc->ops->enable)
ret = rdev->desc->ops->enable(rdev);
if (ret < 0)
return ret;
} else {
return -EINVAL; return -EINVAL;
/* Query before enabling in case configuration
* dependant. */
ret = _regulator_get_enable_time(rdev);
if (ret >= 0) {
delay = ret;
} else {
printk(KERN_WARNING
"%s: enable_time() failed for %s: %d\n",
__func__, rdev_get_name(rdev),
ret);
delay = 0;
} }
/* Allow the regulator to ramp; it would be useful
* to extend this for bulk operations so that the
* regulators can ramp together. */
ret = rdev->desc->ops->enable(rdev);
if (ret < 0)
return ret;
if (delay >= 1000)
mdelay(delay / 1000);
else if (delay)
udelay(delay);
} else if (ret < 0) { } else if (ret < 0) {
printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n",
__func__, rdev_get_name(rdev), ret); __func__, rdev_get_name(rdev), ret);
@ -1341,6 +1388,9 @@ static int _regulator_disable(struct regulator_dev *rdev)
__func__, rdev_get_name(rdev)); __func__, rdev_get_name(rdev));
return ret; return ret;
} }
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
NULL);
} }
/* decrease our supplies ref count and disable if required */ /* decrease our supplies ref count and disable if required */
@ -1399,8 +1449,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
return ret; return ret;
} }
/* notify other consumers that power has been forced off */ /* notify other consumers that power has been forced off */
_notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE, _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
NULL); REGULATOR_EVENT_DISABLE, NULL);
} }
/* decrease our supplies ref count and disable if required */ /* decrease our supplies ref count and disable if required */
@ -1434,9 +1484,9 @@ EXPORT_SYMBOL_GPL(regulator_force_disable);
static int _regulator_is_enabled(struct regulator_dev *rdev) static int _regulator_is_enabled(struct regulator_dev *rdev)
{ {
/* sanity check */ /* If we don't know then assume that the regulator is always on */
if (!rdev->desc->ops->is_enabled) if (!rdev->desc->ops->is_enabled)
return -EINVAL; return 1;
return rdev->desc->ops->is_enabled(rdev); return rdev->desc->ops->is_enabled(rdev);
} }
@ -2451,8 +2501,15 @@ EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
static int __init regulator_init(void) static int __init regulator_init(void)
{ {
int ret;
printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
return class_register(&regulator_class);
ret = class_register(&regulator_class);
regulator_dummy_init();
return ret;
} }
/* init early to allow our consumers to complete system booting */ /* init early to allow our consumers to complete system booting */

66
drivers/regulator/dummy.c Normal file
View File

@ -0,0 +1,66 @@
/*
* dummy.c
*
* Copyright 2010 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.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; either version 2 of the
* License, or (at your option) any later version.
*
* This is useful for systems with mixed controllable and
* non-controllable regulators, as well as for allowing testing on
* systems with no controllable regulators.
*/
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include "dummy.h"
struct regulator_dev *dummy_regulator_rdev;
static struct regulator_init_data dummy_initdata;
static struct regulator_ops dummy_ops;
static struct regulator_desc dummy_desc = {
.name = "dummy",
.id = -1,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
.ops = &dummy_ops,
};
static struct platform_device *dummy_pdev;
void __init regulator_dummy_init(void)
{
int ret;
dummy_pdev = platform_device_alloc("reg-dummy", -1);
if (!dummy_pdev) {
pr_err("Failed to allocate dummy regulator device\n");
return;
}
ret = platform_device_add(dummy_pdev);
if (ret != 0) {
pr_err("Failed to register dummy regulator device: %d\n", ret);
platform_device_put(dummy_pdev);
return;
}
dummy_regulator_rdev = regulator_register(&dummy_desc, NULL,
&dummy_initdata, NULL);
if (IS_ERR(dummy_regulator_rdev)) {
ret = PTR_ERR(dummy_regulator_rdev);
pr_err("Failed to register regulator: %d\n", ret);
platform_device_unregister(dummy_pdev);
return;
}
}

31
drivers/regulator/dummy.h Normal file
View File

@ -0,0 +1,31 @@
/*
* dummy.h
*
* Copyright 2010 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.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; either version 2 of the
* License, or (at your option) any later version.
*
* This is useful for systems with mixed controllable and
* non-controllable regulators, as well as for allowing testing on
* systems with no controllable regulators.
*/
#ifndef _DUMMY_H
#define _DUMMY_H
struct regulator_dev;
extern struct regulator_dev *dummy_regulator_rdev;
#ifdef CONFIG_REGULATOR_DUMMY
void __init regulator_dummy_init(void);
#else
static inline void regulator_dummy_init(void) { }
#endif
#endif

View File

@ -24,14 +24,16 @@
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h> #include <linux/regulator/fixed.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/delay.h>
struct fixed_voltage_data { struct fixed_voltage_data {
struct regulator_desc desc; struct regulator_desc desc;
struct regulator_dev *dev; struct regulator_dev *dev;
int microvolts; int microvolts;
int gpio; int gpio;
unsigned enable_high:1; unsigned startup_delay;
unsigned is_enabled:1; bool enable_high;
bool is_enabled;
}; };
static int fixed_voltage_is_enabled(struct regulator_dev *dev) static int fixed_voltage_is_enabled(struct regulator_dev *dev)
@ -47,7 +49,7 @@ static int fixed_voltage_enable(struct regulator_dev *dev)
if (gpio_is_valid(data->gpio)) { if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, data->enable_high); gpio_set_value_cansleep(data->gpio, data->enable_high);
data->is_enabled = 1; data->is_enabled = true;
} }
return 0; return 0;
@ -59,12 +61,19 @@ static int fixed_voltage_disable(struct regulator_dev *dev)
if (gpio_is_valid(data->gpio)) { if (gpio_is_valid(data->gpio)) {
gpio_set_value_cansleep(data->gpio, !data->enable_high); gpio_set_value_cansleep(data->gpio, !data->enable_high);
data->is_enabled = 0; data->is_enabled = false;
} }
return 0; return 0;
} }
static int fixed_voltage_enable_time(struct regulator_dev *dev)
{
struct fixed_voltage_data *data = rdev_get_drvdata(dev);
return data->startup_delay;
}
static int fixed_voltage_get_voltage(struct regulator_dev *dev) static int fixed_voltage_get_voltage(struct regulator_dev *dev)
{ {
struct fixed_voltage_data *data = rdev_get_drvdata(dev); struct fixed_voltage_data *data = rdev_get_drvdata(dev);
@ -87,11 +96,12 @@ static struct regulator_ops fixed_voltage_ops = {
.is_enabled = fixed_voltage_is_enabled, .is_enabled = fixed_voltage_is_enabled,
.enable = fixed_voltage_enable, .enable = fixed_voltage_enable,
.disable = fixed_voltage_disable, .disable = fixed_voltage_disable,
.enable_time = fixed_voltage_enable_time,
.get_voltage = fixed_voltage_get_voltage, .get_voltage = fixed_voltage_get_voltage,
.list_voltage = fixed_voltage_list_voltage, .list_voltage = fixed_voltage_list_voltage,
}; };
static int regulator_fixed_voltage_probe(struct platform_device *pdev) static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev)
{ {
struct fixed_voltage_config *config = pdev->dev.platform_data; struct fixed_voltage_config *config = pdev->dev.platform_data;
struct fixed_voltage_data *drvdata; struct fixed_voltage_data *drvdata;
@ -117,6 +127,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
drvdata->microvolts = config->microvolts; drvdata->microvolts = config->microvolts;
drvdata->gpio = config->gpio; drvdata->gpio = config->gpio;
drvdata->startup_delay = config->startup_delay;
if (gpio_is_valid(config->gpio)) { if (gpio_is_valid(config->gpio)) {
drvdata->enable_high = config->enable_high; drvdata->enable_high = config->enable_high;
@ -163,7 +174,7 @@ static int regulator_fixed_voltage_probe(struct platform_device *pdev)
/* Regulator without GPIO control is considered /* Regulator without GPIO control is considered
* always enabled * always enabled
*/ */
drvdata->is_enabled = 1; drvdata->is_enabled = true;
} }
drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
@ -191,7 +202,7 @@ err:
return ret; return ret;
} }
static int regulator_fixed_voltage_remove(struct platform_device *pdev) static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev)
{ {
struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev); struct fixed_voltage_data *drvdata = platform_get_drvdata(pdev);
@ -205,10 +216,11 @@ static int regulator_fixed_voltage_remove(struct platform_device *pdev)
} }
static struct platform_driver regulator_fixed_voltage_driver = { static struct platform_driver regulator_fixed_voltage_driver = {
.probe = regulator_fixed_voltage_probe, .probe = reg_fixed_voltage_probe,
.remove = regulator_fixed_voltage_remove, .remove = __devexit_p(reg_fixed_voltage_remove),
.driver = { .driver = {
.name = "reg-fixed-voltage", .name = "reg-fixed-voltage",
.owner = THIS_MODULE,
}, },
}; };

View File

@ -54,7 +54,7 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val);
#define LP3971_BUCK2_BASE 0x29 #define LP3971_BUCK2_BASE 0x29
#define LP3971_BUCK3_BASE 0x32 #define LP3971_BUCK3_BASE 0x32
const static int buck_base_addr[] = { static const int buck_base_addr[] = {
LP3971_BUCK1_BASE, LP3971_BUCK1_BASE,
LP3971_BUCK2_BASE, LP3971_BUCK2_BASE,
LP3971_BUCK3_BASE, LP3971_BUCK3_BASE,
@ -63,7 +63,7 @@ const static int buck_base_addr[] = {
#define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x]) #define LP3971_BUCK_TARGET_VOL1_REG(x) (buck_base_addr[x])
#define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1) #define LP3971_BUCK_TARGET_VOL2_REG(x) (buck_base_addr[x]+1)
const static int buck_voltage_map[] = { static const int buck_voltage_map[] = {
0, 800, 850, 900, 950, 1000, 1050, 1100, 0, 800, 850, 900, 950, 1000, 1050, 1100,
1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800,
@ -96,17 +96,17 @@ const static int buck_voltage_map[] = {
#define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2) #define LDO_VOL_CONTR_SHIFT(x) ((x & 1) << 2)
#define LDO_VOL_CONTR_MASK 0x0f #define LDO_VOL_CONTR_MASK 0x0f
const static int ldo45_voltage_map[] = { static const int ldo45_voltage_map[] = {
1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350,
1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300,
}; };
const static int ldo123_voltage_map[] = { static const int ldo123_voltage_map[] = {
1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500,
2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300,
}; };
const static int *ldo_voltage_map[] = { static const int *ldo_voltage_map[] = {
ldo123_voltage_map, /* LDO1 */ ldo123_voltage_map, /* LDO1 */
ldo123_voltage_map, /* LDO2 */ ldo123_voltage_map, /* LDO2 */
ldo123_voltage_map, /* LDO3 */ ldo123_voltage_map, /* LDO3 */
@ -431,20 +431,20 @@ static int lp3971_set_bits(struct lp3971 *lp3971, u8 reg, u16 mask, u16 val)
return ret; return ret;
} }
static int setup_regulators(struct lp3971 *lp3971, static int __devinit setup_regulators(struct lp3971 *lp3971,
struct lp3971_platform_data *pdata) struct lp3971_platform_data *pdata)
{ {
int i, err; int i, err;
int num_regulators = pdata->num_regulators;
lp3971->num_regulators = num_regulators; lp3971->num_regulators = pdata->num_regulators;
lp3971->rdev = kzalloc(sizeof(struct regulator_dev *) * num_regulators, lp3971->rdev = kcalloc(pdata->num_regulators,
GFP_KERNEL); sizeof(struct regulator_dev *), GFP_KERNEL);
/* Instantiate the regulators */ /* Instantiate the regulators */
for (i = 0; i < num_regulators; i++) { for (i = 0; i < pdata->num_regulators; i++) {
int id = pdata->regulators[i].id; struct lp3971_regulator_subdev *reg = &pdata->regulators[i];
lp3971->rdev[i] = regulator_register(&regulators[id], lp3971->rdev[i] = regulator_register(&regulators[reg->id],
lp3971->dev, pdata->regulators[i].initdata, lp3971); lp3971->dev, reg->initdata, lp3971);
if (IS_ERR(lp3971->rdev[i])) { if (IS_ERR(lp3971->rdev[i])) {
err = PTR_ERR(lp3971->rdev[i]); err = PTR_ERR(lp3971->rdev[i]);
@ -455,10 +455,10 @@ static int setup_regulators(struct lp3971 *lp3971,
} }
return 0; return 0;
error: error:
for (i = 0; i < num_regulators; i++) while (--i >= 0)
if (lp3971->rdev[i]) regulator_unregister(lp3971->rdev[i]);
regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev); kfree(lp3971->rdev);
lp3971->rdev = NULL; lp3971->rdev = NULL;
return err; return err;
@ -472,15 +472,17 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
int ret; int ret;
u16 val; u16 val;
lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL); if (!pdata) {
if (lp3971 == NULL) { dev_dbg(&i2c->dev, "No platform init data supplied\n");
ret = -ENOMEM; return -ENODEV;
goto err;
} }
lp3971 = kzalloc(sizeof(struct lp3971), GFP_KERNEL);
if (lp3971 == NULL)
return -ENOMEM;
lp3971->i2c = i2c; lp3971->i2c = i2c;
lp3971->dev = &i2c->dev; lp3971->dev = &i2c->dev;
i2c_set_clientdata(i2c, lp3971);
mutex_init(&lp3971->io_lock); mutex_init(&lp3971->io_lock);
@ -493,19 +495,15 @@ static int __devinit lp3971_i2c_probe(struct i2c_client *i2c,
goto err_detect; goto err_detect;
} }
if (pdata) { ret = setup_regulators(lp3971, pdata);
ret = setup_regulators(lp3971, pdata); if (ret < 0)
if (ret < 0) goto err_detect;
goto err_detect;
} else
dev_warn(lp3971->dev, "No platform init data supplied\n");
i2c_set_clientdata(i2c, lp3971);
return 0; return 0;
err_detect: err_detect:
i2c_set_clientdata(i2c, NULL);
kfree(lp3971); kfree(lp3971);
err:
return ret; return ret;
} }
@ -513,11 +511,13 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
{ {
struct lp3971 *lp3971 = i2c_get_clientdata(i2c); struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
int i; int i;
for (i = 0; i < lp3971->num_regulators; i++)
if (lp3971->rdev[i])
regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev);
i2c_set_clientdata(i2c, NULL); i2c_set_clientdata(i2c, NULL);
for (i = 0; i < lp3971->num_regulators; i++)
regulator_unregister(lp3971->rdev[i]);
kfree(lp3971->rdev);
kfree(lp3971); kfree(lp3971);
return 0; return 0;

View File

@ -179,8 +179,8 @@ static struct regulator_desc max1586_reg[] = {
}, },
}; };
static int max1586_pmic_probe(struct i2c_client *client, static int __devinit max1586_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id) const struct i2c_device_id *i2c_id)
{ {
struct regulator_dev **rdev; struct regulator_dev **rdev;
struct max1586_platform_data *pdata = client->dev.platform_data; struct max1586_platform_data *pdata = client->dev.platform_data;
@ -235,7 +235,7 @@ out:
return ret; return ret;
} }
static int max1586_pmic_remove(struct i2c_client *client) static int __devexit max1586_pmic_remove(struct i2c_client *client)
{ {
struct regulator_dev **rdev = i2c_get_clientdata(client); struct regulator_dev **rdev = i2c_get_clientdata(client);
int i; int i;
@ -257,9 +257,10 @@ MODULE_DEVICE_TABLE(i2c, max1586_id);
static struct i2c_driver max1586_pmic_driver = { static struct i2c_driver max1586_pmic_driver = {
.probe = max1586_pmic_probe, .probe = max1586_pmic_probe,
.remove = max1586_pmic_remove, .remove = __devexit_p(max1586_pmic_remove),
.driver = { .driver = {
.name = "max1586", .name = "max1586",
.owner = THIS_MODULE,
}, },
.id_table = max1586_id, .id_table = max1586_id,
}; };

408
drivers/regulator/max8649.c Normal file
View File

@ -0,0 +1,408 @@
/*
* Regulators driver for Maxim max8649
*
* Copyright (C) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/max8649.h>
#define MAX8649_DCDC_VMIN 750000 /* uV */
#define MAX8649_DCDC_VMAX 1380000 /* uV */
#define MAX8649_DCDC_STEP 10000 /* uV */
#define MAX8649_VOL_MASK 0x3f
/* Registers */
#define MAX8649_MODE0 0x00
#define MAX8649_MODE1 0x01
#define MAX8649_MODE2 0x02
#define MAX8649_MODE3 0x03
#define MAX8649_CONTROL 0x04
#define MAX8649_SYNC 0x05
#define MAX8649_RAMP 0x06
#define MAX8649_CHIP_ID1 0x08
#define MAX8649_CHIP_ID2 0x09
/* Bits */
#define MAX8649_EN_PD (1 << 7)
#define MAX8649_VID0_PD (1 << 6)
#define MAX8649_VID1_PD (1 << 5)
#define MAX8649_VID_MASK (3 << 5)
#define MAX8649_FORCE_PWM (1 << 7)
#define MAX8649_SYNC_EXTCLK (1 << 6)
#define MAX8649_EXT_MASK (3 << 6)
#define MAX8649_RAMP_MASK (7 << 5)
#define MAX8649_RAMP_DOWN (1 << 1)
struct max8649_regulator_info {
struct regulator_dev *regulator;
struct i2c_client *i2c;
struct device *dev;
struct mutex io_lock;
int vol_reg;
unsigned mode:2; /* bit[1:0] = VID1, VID0 */
unsigned extclk_freq:2;
unsigned extclk:1;
unsigned ramp_timing:3;
unsigned ramp_down:1;
};
/* I2C operations */
static inline int max8649_read_device(struct i2c_client *i2c,
int reg, int bytes, void *dest)
{
unsigned char data;
int ret;
data = (unsigned char)reg;
ret = i2c_master_send(i2c, &data, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(i2c, dest, bytes);
if (ret < 0)
return ret;
return 0;
}
static inline int max8649_write_device(struct i2c_client *i2c,
int reg, int bytes, void *src)
{
unsigned char buf[bytes + 1];
int ret;
buf[0] = (unsigned char)reg;
memcpy(&buf[1], src, bytes);
ret = i2c_master_send(i2c, buf, bytes + 1);
if (ret < 0)
return ret;
return 0;
}
static int max8649_reg_read(struct i2c_client *i2c, int reg)
{
struct max8649_regulator_info *info = i2c_get_clientdata(i2c);
unsigned char data;
int ret;
mutex_lock(&info->io_lock);
ret = max8649_read_device(i2c, reg, 1, &data);
mutex_unlock(&info->io_lock);
if (ret < 0)
return ret;
return (int)data;
}
static int max8649_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
struct max8649_regulator_info *info = i2c_get_clientdata(i2c);
unsigned char value;
int ret;
mutex_lock(&info->io_lock);
ret = max8649_read_device(i2c, reg, 1, &value);
if (ret < 0)
goto out;
value &= ~mask;
value |= data;
ret = max8649_write_device(i2c, reg, 1, &value);
out:
mutex_unlock(&info->io_lock);
return ret;
}
static inline int check_range(int min_uV, int max_uV)
{
if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX)
|| (min_uV > max_uV))
return -EINVAL;
return 0;
}
static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index)
{
return (MAX8649_DCDC_VMIN + index * MAX8649_DCDC_STEP);
}
static int max8649_get_voltage(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data;
int ret;
ret = max8649_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
data = (unsigned char)ret & MAX8649_VOL_MASK;
return max8649_list_voltage(rdev, data);
}
static int max8649_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
unsigned char data, mask;
if (check_range(min_uV, max_uV)) {
dev_err(info->dev, "invalid voltage range (%d, %d) uV\n",
min_uV, max_uV);
return -EINVAL;
}
data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1)
/ MAX8649_DCDC_STEP;
mask = MAX8649_VOL_MASK;
return max8649_set_bits(info->i2c, info->vol_reg, mask, data);
}
/* EN_PD means pulldown on EN input */
static int max8649_enable(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, 0);
}
/*
* Applied internal pulldown resistor on EN input pin.
* If pulldown EN pin outside, it would be better.
*/
static int max8649_disable(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD,
MAX8649_EN_PD);
}
static int max8649_is_enabled(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
ret = max8649_reg_read(info->i2c, MAX8649_CONTROL);
if (ret < 0)
return ret;
return !((unsigned char)ret & MAX8649_EN_PD);
}
static int max8649_enable_time(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
int voltage, rate, ret;
/* get voltage */
ret = max8649_reg_read(info->i2c, info->vol_reg);
if (ret < 0)
return ret;
ret &= MAX8649_VOL_MASK;
voltage = max8649_list_voltage(rdev, (unsigned char)ret); /* uV */
/* get rate */
ret = max8649_reg_read(info->i2c, MAX8649_RAMP);
if (ret < 0)
return ret;
ret = (ret & MAX8649_RAMP_MASK) >> 5;
rate = (32 * 1000) >> ret; /* uV/uS */
return (voltage / rate);
}
static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
switch (mode) {
case REGULATOR_MODE_FAST:
max8649_set_bits(info->i2c, info->vol_reg, MAX8649_FORCE_PWM,
MAX8649_FORCE_PWM);
break;
case REGULATOR_MODE_NORMAL:
max8649_set_bits(info->i2c, info->vol_reg,
MAX8649_FORCE_PWM, 0);
break;
default:
return -EINVAL;
}
return 0;
}
static unsigned int max8649_get_mode(struct regulator_dev *rdev)
{
struct max8649_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
ret = max8649_reg_read(info->i2c, info->vol_reg);
if (ret & MAX8649_FORCE_PWM)
return REGULATOR_MODE_FAST;
return REGULATOR_MODE_NORMAL;
}
static struct regulator_ops max8649_dcdc_ops = {
.set_voltage = max8649_set_voltage,
.get_voltage = max8649_get_voltage,
.list_voltage = max8649_list_voltage,
.enable = max8649_enable,
.disable = max8649_disable,
.is_enabled = max8649_is_enabled,
.enable_time = max8649_enable_time,
.set_mode = max8649_set_mode,
.get_mode = max8649_get_mode,
};
static struct regulator_desc dcdc_desc = {
.name = "max8649",
.ops = &max8649_dcdc_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = 1 << 6,
.owner = THIS_MODULE,
};
static int __devinit max8649_regulator_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max8649_platform_data *pdata = client->dev.platform_data;
struct max8649_regulator_info *info = NULL;
unsigned char data;
int ret;
info = kzalloc(sizeof(struct max8649_regulator_info), GFP_KERNEL);
if (!info) {
dev_err(&client->dev, "No enough memory\n");
return -ENOMEM;
}
info->i2c = client;
info->dev = &client->dev;
mutex_init(&info->io_lock);
i2c_set_clientdata(client, info);
info->mode = pdata->mode;
switch (info->mode) {
case 0:
info->vol_reg = MAX8649_MODE0;
break;
case 1:
info->vol_reg = MAX8649_MODE1;
break;
case 2:
info->vol_reg = MAX8649_MODE2;
break;
case 3:
info->vol_reg = MAX8649_MODE3;
break;
default:
break;
}
ret = max8649_reg_read(info->i2c, MAX8649_CHIP_ID1);
if (ret < 0) {
dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n",
ret);
goto out;
}
dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret);
/* enable VID0 & VID1 */
max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_VID_MASK, 0);
/* enable/disable external clock synchronization */
info->extclk = pdata->extclk;
data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0;
max8649_set_bits(info->i2c, info->vol_reg, MAX8649_SYNC_EXTCLK, data);
if (info->extclk) {
/* set external clock frequency */
info->extclk_freq = pdata->extclk_freq;
max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK,
info->extclk_freq);
}
if (pdata->ramp_timing) {
info->ramp_timing = pdata->ramp_timing;
max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_MASK,
info->ramp_timing << 5);
}
info->ramp_down = pdata->ramp_down;
if (info->ramp_down) {
max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_DOWN,
MAX8649_RAMP_DOWN);
}
info->regulator = regulator_register(&dcdc_desc, &client->dev,
pdata->regulator, info);
if (IS_ERR(info->regulator)) {
dev_err(info->dev, "failed to register regulator %s\n",
dcdc_desc.name);
ret = PTR_ERR(info->regulator);
goto out;
}
dev_info(info->dev, "Max8649 regulator device is detected.\n");
return 0;
out:
kfree(info);
return ret;
}
static int __devexit max8649_regulator_remove(struct i2c_client *client)
{
struct max8649_regulator_info *info = i2c_get_clientdata(client);
if (info) {
if (info->regulator)
regulator_unregister(info->regulator);
kfree(info);
}
i2c_set_clientdata(client, NULL);
return 0;
}
static const struct i2c_device_id max8649_id[] = {
{ "max8649", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max8649_id);
static struct i2c_driver max8649_driver = {
.probe = max8649_regulator_probe,
.remove = __devexit_p(max8649_regulator_remove),
.driver = {
.name = "max8649",
},
.id_table = max8649_id,
};
static int __init max8649_init(void)
{
return i2c_add_driver(&max8649_driver);
}
subsys_initcall(max8649_init);
static void __exit max8649_exit(void)
{
i2c_del_driver(&max8649_driver);
}
module_exit(max8649_exit);
/* Module information */
MODULE_DESCRIPTION("MAXIM 8649 voltage regulator driver");
MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
MODULE_LICENSE("GPL");

View File

@ -345,8 +345,8 @@ static struct regulator_desc max8660_reg[] = {
}, },
}; };
static int max8660_probe(struct i2c_client *client, static int __devinit max8660_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id) const struct i2c_device_id *i2c_id)
{ {
struct regulator_dev **rdev; struct regulator_dev **rdev;
struct max8660_platform_data *pdata = client->dev.platform_data; struct max8660_platform_data *pdata = client->dev.platform_data;
@ -354,7 +354,7 @@ static int max8660_probe(struct i2c_client *client,
int boot_on, i, id, ret = -EINVAL; int boot_on, i, id, ret = -EINVAL;
if (pdata->num_subdevs > MAX8660_V_END) { if (pdata->num_subdevs > MAX8660_V_END) {
dev_err(&client->dev, "Too much regulators found!\n"); dev_err(&client->dev, "Too many regulators found!\n");
goto out; goto out;
} }
@ -462,7 +462,7 @@ out:
return ret; return ret;
} }
static int max8660_remove(struct i2c_client *client) static int __devexit max8660_remove(struct i2c_client *client)
{ {
struct regulator_dev **rdev = i2c_get_clientdata(client); struct regulator_dev **rdev = i2c_get_clientdata(client);
int i; int i;
@ -485,9 +485,10 @@ MODULE_DEVICE_TABLE(i2c, max8660_id);
static struct i2c_driver max8660_driver = { static struct i2c_driver max8660_driver = {
.probe = max8660_probe, .probe = max8660_probe,
.remove = max8660_remove, .remove = __devexit_p(max8660_remove),
.driver = { .driver = {
.name = "max8660", .name = "max8660",
.owner = THIS_MODULE,
}, },
.id_table = max8660_id, .id_table = max8660_id,
}; };

View File

@ -2,6 +2,7 @@
* Regulator Driver for Freescale MC13783 PMIC * Regulator Driver for Freescale MC13783 PMIC
* *
* Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> * Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -16,11 +17,44 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/err.h> #include <linux/err.h>
#define MC13783_REG_SWITCHERS4 28
#define MC13783_REG_SWITCHERS4_PLLEN (1 << 18)
#define MC13783_REG_SWITCHERS5 29 #define MC13783_REG_SWITCHERS5 29
#define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20)
#define MC13783_REG_SWITCHERS5_SW3VSEL 18
#define MC13783_REG_SWITCHERS5_SW3VSEL_M (3 << 18)
#define MC13783_REG_REGULATORSETTING0 30
#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL 2
#define MC13783_REG_REGULATORSETTING0_VDIGVSEL 4
#define MC13783_REG_REGULATORSETTING0_VGENVSEL 6
#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL 9
#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL 11
#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL 13
#define MC13783_REG_REGULATORSETTING0_VSIMVSEL 14
#define MC13783_REG_REGULATORSETTING0_VESIMVSEL 15
#define MC13783_REG_REGULATORSETTING0_VCAMVSEL 16
#define MC13783_REG_REGULATORSETTING0_VIOLOVSEL_M (3 << 2)
#define MC13783_REG_REGULATORSETTING0_VDIGVSEL_M (3 << 4)
#define MC13783_REG_REGULATORSETTING0_VGENVSEL_M (7 << 6)
#define MC13783_REG_REGULATORSETTING0_VRFDIGVSEL_M (3 << 9)
#define MC13783_REG_REGULATORSETTING0_VRFREFVSEL_M (3 << 11)
#define MC13783_REG_REGULATORSETTING0_VRFCPVSEL_M (1 << 13)
#define MC13783_REG_REGULATORSETTING0_VSIMVSEL_M (1 << 14)
#define MC13783_REG_REGULATORSETTING0_VESIMVSEL_M (1 << 15)
#define MC13783_REG_REGULATORSETTING0_VCAMVSEL_M (7 << 16)
#define MC13783_REG_REGULATORSETTING1 31
#define MC13783_REG_REGULATORSETTING1_VVIBVSEL 0
#define MC13783_REG_REGULATORSETTING1_VRF1VSEL 2
#define MC13783_REG_REGULATORSETTING1_VRF2VSEL 4
#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL 6
#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL 9
#define MC13783_REG_REGULATORSETTING1_VVIBVSEL_M (3 << 0)
#define MC13783_REG_REGULATORSETTING1_VRF1VSEL_M (3 << 2)
#define MC13783_REG_REGULATORSETTING1_VRF2VSEL_M (3 << 4)
#define MC13783_REG_REGULATORSETTING1_VMMC1VSEL_M (7 << 6)
#define MC13783_REG_REGULATORSETTING1_VMMC2VSEL_M (7 << 9)
#define MC13783_REG_REGULATORMODE0 32 #define MC13783_REG_REGULATORMODE0 32
#define MC13783_REG_REGULATORMODE0_VAUDIOEN (1 << 0) #define MC13783_REG_REGULATORMODE0_VAUDIOEN (1 << 0)
@ -48,19 +82,107 @@
#define MC13783_REG_POWERMISC_GPO2EN (1 << 8) #define MC13783_REG_POWERMISC_GPO2EN (1 << 8)
#define MC13783_REG_POWERMISC_GPO3EN (1 << 10) #define MC13783_REG_POWERMISC_GPO3EN (1 << 10)
#define MC13783_REG_POWERMISC_GPO4EN (1 << 12) #define MC13783_REG_POWERMISC_GPO4EN (1 << 12)
#define MC13783_REG_POWERMISC_PWGT1SPIEN (1 << 15)
#define MC13783_REG_POWERMISC_PWGT2SPIEN (1 << 16)
#define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15)
struct mc13783_regulator { struct mc13783_regulator {
struct regulator_desc desc; struct regulator_desc desc;
int reg; int reg;
int enable_bit; int enable_bit;
int vsel_reg;
int vsel_shift;
int vsel_mask;
int const *voltages;
};
/* Voltage Values */
static const int const mc13783_sw3_val[] = {
5000000, 5000000, 5000000, 5500000,
};
static const int const mc13783_vaudio_val[] = {
2775000,
};
static const int const mc13783_viohi_val[] = {
2775000,
};
static const int const mc13783_violo_val[] = {
1200000, 1300000, 1500000, 1800000,
};
static const int const mc13783_vdig_val[] = {
1200000, 1300000, 1500000, 1800000,
};
static const int const mc13783_vgen_val[] = {
1200000, 1300000, 1500000, 1800000,
1100000, 2000000, 2775000, 2400000,
};
static const int const mc13783_vrfdig_val[] = {
1200000, 1500000, 1800000, 1875000,
};
static const int const mc13783_vrfref_val[] = {
2475000, 2600000, 2700000, 2775000,
};
static const int const mc13783_vrfcp_val[] = {
2700000, 2775000,
};
static const int const mc13783_vsim_val[] = {
1800000, 2900000, 3000000,
};
static const int const mc13783_vesim_val[] = {
1800000, 2900000,
};
static const int const mc13783_vcam_val[] = {
1500000, 1800000, 2500000, 2550000,
2600000, 2750000, 2800000, 3000000,
};
static const int const mc13783_vrfbg_val[] = {
1250000,
};
static const int const mc13783_vvib_val[] = {
1300000, 1800000, 2000000, 3000000,
};
static const int const mc13783_vmmc_val[] = {
1600000, 1800000, 2000000, 2600000,
2700000, 2800000, 2900000, 3000000,
};
static const int const mc13783_vrf_val[] = {
1500000, 1875000, 2700000, 2775000,
};
static const int const mc13783_gpo_val[] = {
3100000,
};
static const int const mc13783_pwgtdrv_val[] = {
5500000,
}; };
static struct regulator_ops mc13783_regulator_ops; static struct regulator_ops mc13783_regulator_ops;
static struct regulator_ops mc13783_fixed_regulator_ops;
static struct regulator_ops mc13783_gpo_regulator_ops;
#define MC13783_DEFINE(prefix, _name, _reg) \ #define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \
[MC13783_ ## prefix ## _ ## _name] = { \ [MC13783_ ## prefix ## _ ## _name] = { \
.desc = { \ .desc = { \
.name = #prefix "_" #_name, \ .name = #prefix "_" #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
.ops = &mc13783_regulator_ops, \ .ops = &mc13783_regulator_ops, \
.type = REGULATOR_VOLTAGE, \ .type = REGULATOR_VOLTAGE, \
.id = MC13783_ ## prefix ## _ ## _name, \ .id = MC13783_ ## prefix ## _ ## _name, \
@ -68,40 +190,92 @@ static struct regulator_ops mc13783_regulator_ops;
}, \ }, \
.reg = MC13783_REG_ ## _reg, \ .reg = MC13783_REG_ ## _reg, \
.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
.vsel_reg = MC13783_REG_ ## _vsel_reg, \
.vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\
.vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\
.voltages = _voltages, \
} }
#define MC13783_DEFINE_SW(_name, _reg) MC13783_DEFINE(SW, _name, _reg) #define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \
#define MC13783_DEFINE_REGU(_name, _reg) MC13783_DEFINE(REGU, _name, _reg) [MC13783_ ## prefix ## _ ## _name] = { \
.desc = { \
.name = #prefix "_" #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
.ops = &mc13783_fixed_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = MC13783_ ## prefix ## _ ## _name, \
.owner = THIS_MODULE, \
}, \
.reg = MC13783_REG_ ## _reg, \
.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
.voltages = _voltages, \
}
#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \
[MC13783_ ## prefix ## _ ## _name] = { \
.desc = { \
.name = #prefix "_" #_name, \
.n_voltages = ARRAY_SIZE(_voltages), \
.ops = &mc13783_gpo_regulator_ops, \
.type = REGULATOR_VOLTAGE, \
.id = MC13783_ ## prefix ## _ ## _name, \
.owner = THIS_MODULE, \
}, \
.reg = MC13783_REG_ ## _reg, \
.enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \
.voltages = _voltages, \
}
#define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \
MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages)
#define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \
MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages)
static struct mc13783_regulator mc13783_regulators[] = { static struct mc13783_regulator mc13783_regulators[] = {
MC13783_DEFINE_SW(SW3, SWITCHERS5), MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val),
MC13783_DEFINE_SW(PLL, SWITCHERS4),
MC13783_DEFINE_REGU(VAUDIO, REGULATORMODE0), MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val),
MC13783_DEFINE_REGU(VIOHI, REGULATORMODE0), MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val),
MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0), MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VDIG, REGULATORMODE0), mc13783_violo_val),
MC13783_DEFINE_REGU(VGEN, REGULATORMODE0), MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0), mc13783_vdig_val),
MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0), MC13783_DEFINE_REGU(VGEN, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0), mc13783_vgen_val),
MC13783_DEFINE_REGU(VSIM, REGULATORMODE1), MC13783_DEFINE_REGU(VRFDIG, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VESIM, REGULATORMODE1), mc13783_vrfdig_val),
MC13783_DEFINE_REGU(VCAM, REGULATORMODE1), MC13783_DEFINE_REGU(VRFREF, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VRFBG, REGULATORMODE1), mc13783_vrfref_val),
MC13783_DEFINE_REGU(VVIB, REGULATORMODE1), MC13783_DEFINE_REGU(VRFCP, REGULATORMODE0, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VRF1, REGULATORMODE1), mc13783_vrfcp_val),
MC13783_DEFINE_REGU(VRF2, REGULATORMODE1), MC13783_DEFINE_REGU(VSIM, REGULATORMODE1, REGULATORSETTING0, \
MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1), mc13783_vsim_val),
MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1), MC13783_DEFINE_REGU(VESIM, REGULATORMODE1, REGULATORSETTING0, \
MC13783_DEFINE_REGU(GPO1, POWERMISC), mc13783_vesim_val),
MC13783_DEFINE_REGU(GPO2, POWERMISC), MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \
MC13783_DEFINE_REGU(GPO3, POWERMISC), mc13783_vcam_val),
MC13783_DEFINE_REGU(GPO4, POWERMISC), MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val),
MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vvib_val),
MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vrf_val),
MC13783_DEFINE_REGU(VRF2, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vrf_val),
MC13783_DEFINE_REGU(VMMC1, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vmmc_val),
MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \
mc13783_vmmc_val),
MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val),
MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val),
MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val),
MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val),
MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val),
MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val),
}; };
struct mc13783_regulator_priv { struct mc13783_regulator_priv {
struct mc13783 *mc13783; struct mc13783 *mc13783;
u32 powermisc_pwgt_state;
struct regulator_dev *regulators[]; struct regulator_dev *regulators[];
}; };
@ -154,10 +328,241 @@ static int mc13783_regulator_is_enabled(struct regulator_dev *rdev)
return (val & mc13783_regulators[id].enable_bit) != 0; return (val & mc13783_regulators[id].enable_bit) != 0;
} }
static int mc13783_regulator_list_voltage(struct regulator_dev *rdev,
unsigned selector)
{
int id = rdev_get_id(rdev);
if (selector >= mc13783_regulators[id].desc.n_voltages)
return -EINVAL;
return mc13783_regulators[id].voltages[selector];
}
static int mc13783_get_best_voltage_index(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
int reg_id = rdev_get_id(rdev);
int i;
int bestmatch;
int bestindex;
/*
* Locate the minimum voltage fitting the criteria on
* this regulator. The switchable voltages are not
* in strict falling order so we need to check them
* all for the best match.
*/
bestmatch = INT_MAX;
bestindex = -1;
for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) {
if (mc13783_regulators[reg_id].voltages[i] >= min_uV &&
mc13783_regulators[reg_id].voltages[i] < bestmatch) {
bestmatch = mc13783_regulators[reg_id].voltages[i];
bestindex = i;
}
}
if (bestindex < 0 || bestmatch > max_uV) {
dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n",
min_uV, max_uV);
return -EINVAL;
}
return bestindex;
}
static int mc13783_regulator_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
int value, id = rdev_get_id(rdev);
int ret;
dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
__func__, id, min_uV, max_uV);
/* Find the best index */
value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV);
dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value);
if (value < 0)
return value;
mc13783_lock(priv->mc13783);
ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg,
mc13783_regulators[id].vsel_mask,
value << mc13783_regulators[id].vsel_shift);
mc13783_unlock(priv->mc13783);
return ret;
}
static int mc13783_regulator_get_voltage(struct regulator_dev *rdev)
{
struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
int ret, id = rdev_get_id(rdev);
unsigned int val;
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
mc13783_lock(priv->mc13783);
ret = mc13783_reg_read(priv->mc13783,
mc13783_regulators[id].vsel_reg, &val);
mc13783_unlock(priv->mc13783);
if (ret)
return ret;
val = (val & mc13783_regulators[id].vsel_mask)
>> mc13783_regulators[id].vsel_shift;
dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages);
return mc13783_regulators[id].voltages[val];
}
static struct regulator_ops mc13783_regulator_ops = { static struct regulator_ops mc13783_regulator_ops = {
.enable = mc13783_regulator_enable, .enable = mc13783_regulator_enable,
.disable = mc13783_regulator_disable, .disable = mc13783_regulator_disable,
.is_enabled = mc13783_regulator_is_enabled, .is_enabled = mc13783_regulator_is_enabled,
.list_voltage = mc13783_regulator_list_voltage,
.set_voltage = mc13783_regulator_set_voltage,
.get_voltage = mc13783_regulator_get_voltage,
};
static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
int id = rdev_get_id(rdev);
dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
__func__, id, min_uV, max_uV);
if (min_uV > mc13783_regulators[id].voltages[0] &&
max_uV < mc13783_regulators[id].voltages[0])
return 0;
else
return -EINVAL;
}
static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev)
{
int id = rdev_get_id(rdev);
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
return mc13783_regulators[id].voltages[0];
}
static struct regulator_ops mc13783_fixed_regulator_ops = {
.enable = mc13783_regulator_enable,
.disable = mc13783_regulator_disable,
.is_enabled = mc13783_regulator_is_enabled,
.list_voltage = mc13783_regulator_list_voltage,
.set_voltage = mc13783_fixed_regulator_set_voltage,
.get_voltage = mc13783_fixed_regulator_get_voltage,
};
int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask,
u32 val)
{
struct mc13783 *mc13783 = priv->mc13783;
int ret;
u32 valread;
BUG_ON(val & ~mask);
ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
if (ret)
return ret;
/* Update the stored state for Power Gates. */
priv->powermisc_pwgt_state =
(priv->powermisc_pwgt_state & ~mask) | val;
priv->powermisc_pwgt_state &= MC13783_REG_POWERMISC_PWGTSPI_M;
/* Construct the new register value */
valread = (valread & ~mask) | val;
/* Overwrite the PWGTxEN with the stored version */
valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
priv->powermisc_pwgt_state;
return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
}
static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
{
struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
int ret;
u32 en_val = mc13783_regulators[id].enable_bit;
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
/* Power Gate enable value is 0 */
if (id == MC13783_REGU_PWGT1SPI ||
id == MC13783_REGU_PWGT2SPI)
en_val = 0;
mc13783_lock(priv->mc13783);
ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
en_val);
mc13783_unlock(priv->mc13783);
return ret;
}
static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
{
struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
int ret;
u32 dis_val = 0;
dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
/* Power Gate disable value is 1 */
if (id == MC13783_REGU_PWGT1SPI ||
id == MC13783_REGU_PWGT2SPI)
dis_val = mc13783_regulators[id].enable_bit;
mc13783_lock(priv->mc13783);
ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit,
dis_val);
mc13783_unlock(priv->mc13783);
return ret;
}
static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
{
struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev);
int ret, id = rdev_get_id(rdev);
unsigned int val;
mc13783_lock(priv->mc13783);
ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val);
mc13783_unlock(priv->mc13783);
if (ret)
return ret;
/* Power Gates state is stored in powermisc_pwgt_state
* where the meaning of bits is negated */
val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
(priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M);
return (val & mc13783_regulators[id].enable_bit) != 0;
}
static struct regulator_ops mc13783_gpo_regulator_ops = {
.enable = mc13783_gpo_regulator_enable,
.disable = mc13783_gpo_regulator_disable,
.is_enabled = mc13783_gpo_regulator_is_enabled,
.list_voltage = mc13783_regulator_list_voltage,
.set_voltage = mc13783_fixed_regulator_set_voltage,
.get_voltage = mc13783_fixed_regulator_get_voltage,
}; };
static int __devinit mc13783_regulator_probe(struct platform_device *pdev) static int __devinit mc13783_regulator_probe(struct platform_device *pdev)

View File

@ -288,16 +288,18 @@ static int __devexit pcap_regulator_remove(struct platform_device *pdev)
struct regulator_dev *rdev = platform_get_drvdata(pdev); struct regulator_dev *rdev = platform_get_drvdata(pdev);
regulator_unregister(rdev); regulator_unregister(rdev);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
static struct platform_driver pcap_regulator_driver = { static struct platform_driver pcap_regulator_driver = {
.driver = { .driver = {
.name = "pcap-regulator", .name = "pcap-regulator",
.owner = THIS_MODULE,
}, },
.probe = pcap_regulator_probe, .probe = pcap_regulator_probe,
.remove = __devexit_p(pcap_regulator_remove), .remove = __devexit_p(pcap_regulator_remove),
}; };
static int __init pcap_regulator_init(void) static int __init pcap_regulator_init(void)

View File

@ -457,8 +457,8 @@ static struct regulator_ops tps65023_ldo_ops = {
.list_voltage = tps65023_ldo_list_voltage, .list_voltage = tps65023_ldo_list_voltage,
}; };
static static int __devinit tps_65023_probe(struct i2c_client *client,
int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
static int desc_id; static int desc_id;
const struct tps_info *info = (void *)id->driver_data; const struct tps_info *info = (void *)id->driver_data;
@ -466,6 +466,7 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct tps_pmic *tps; struct tps_pmic *tps;
int i; int i;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO; return -EIO;
@ -475,7 +476,6 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
* coming from the board-evm file. * coming from the board-evm file.
*/ */
init_data = client->dev.platform_data; init_data = client->dev.platform_data;
if (!init_data) if (!init_data)
return -EIO; return -EIO;
@ -502,21 +502,12 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Register the regulators */ /* Register the regulators */
rdev = regulator_register(&tps->desc[i], &client->dev, rdev = regulator_register(&tps->desc[i], &client->dev,
init_data, tps); init_data, tps);
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n", dev_err(&client->dev, "failed to register %s\n",
id->name); id->name);
error = PTR_ERR(rdev);
/* Unregister */ goto fail;
while (i)
regulator_unregister(tps->rdev[--i]);
tps->client = NULL;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
kfree(tps);
return PTR_ERR(rdev);
} }
/* Save regulator for cleanup */ /* Save regulator for cleanup */
@ -526,6 +517,13 @@ int tps_65023_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, tps); i2c_set_clientdata(client, tps);
return 0; return 0;
fail:
while (--i >= 0)
regulator_unregister(tps->rdev[i]);
kfree(tps);
return error;
} }
/** /**
@ -539,13 +537,12 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
struct tps_pmic *tps = i2c_get_clientdata(client); struct tps_pmic *tps = i2c_get_clientdata(client);
int i; int i;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
for (i = 0; i < TPS65023_NUM_REGULATOR; i++) for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]); regulator_unregister(tps->rdev[i]);
tps->client = NULL;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
kfree(tps); kfree(tps);
return 0; return 0;

View File

@ -538,8 +538,8 @@ static struct regulator_ops tps6507x_ldo_ops = {
.list_voltage = tps6507x_ldo_list_voltage, .list_voltage = tps6507x_ldo_list_voltage,
}; };
static static int __devinit tps_6507x_probe(struct i2c_client *client,
int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
static int desc_id; static int desc_id;
const struct tps_info *info = (void *)id->driver_data; const struct tps_info *info = (void *)id->driver_data;
@ -547,6 +547,7 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct tps_pmic *tps; struct tps_pmic *tps;
int i; int i;
int error;
if (!i2c_check_functionality(client->adapter, if (!i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA)) I2C_FUNC_SMBUS_BYTE_DATA))
@ -557,7 +558,6 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
* coming from the board-evm file. * coming from the board-evm file.
*/ */
init_data = client->dev.platform_data; init_data = client->dev.platform_data;
if (!init_data) if (!init_data)
return -EIO; return -EIO;
@ -586,18 +586,8 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (IS_ERR(rdev)) { if (IS_ERR(rdev)) {
dev_err(&client->dev, "failed to register %s\n", dev_err(&client->dev, "failed to register %s\n",
id->name); id->name);
error = PTR_ERR(rdev);
/* Unregister */ goto fail;
while (i)
regulator_unregister(tps->rdev[--i]);
tps->client = NULL;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
kfree(tps);
return PTR_ERR(rdev);
} }
/* Save regulator for cleanup */ /* Save regulator for cleanup */
@ -607,6 +597,13 @@ int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
i2c_set_clientdata(client, tps); i2c_set_clientdata(client, tps);
return 0; return 0;
fail:
while (--i >= 0)
regulator_unregister(tps->rdev[i]);
kfree(tps);
return error;
} }
/** /**
@ -620,13 +617,12 @@ static int __devexit tps_6507x_remove(struct i2c_client *client)
struct tps_pmic *tps = i2c_get_clientdata(client); struct tps_pmic *tps = i2c_get_clientdata(client);
int i; int i;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
for (i = 0; i < TPS6507X_NUM_REGULATOR; i++) for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]); regulator_unregister(tps->rdev[i]);
tps->client = NULL;
/* clear the client data in i2c */
i2c_set_clientdata(client, NULL);
kfree(tps); kfree(tps);
return 0; return 0;

View File

@ -519,19 +519,19 @@ static struct twlreg_info twl_regs[] = {
/* 6030 REG with base as PMC Slave Misc : 0x0030 */ /* 6030 REG with base as PMC Slave Misc : 0x0030 */
/* Turnon-delay and remap configuration values for 6030 are not /* Turnon-delay and remap configuration values for 6030 are not
verified since the specification is not public */ verified since the specification is not public */
TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x21),
TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x21),
TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x21),
TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x21),
TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x21),
TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08), TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x21),
TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08), TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08), TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08), TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08) TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21)
}; };
static int twlreg_probe(struct platform_device *pdev) static int __devinit twlreg_probe(struct platform_device *pdev)
{ {
int i; int i;
struct twlreg_info *info; struct twlreg_info *info;

View File

@ -19,7 +19,7 @@
struct virtual_consumer_data { struct virtual_consumer_data {
struct mutex lock; struct mutex lock;
struct regulator *regulator; struct regulator *regulator;
int enabled; bool enabled;
int min_uV; int min_uV;
int max_uV; int max_uV;
int min_uA; int min_uA;
@ -49,7 +49,7 @@ static void update_voltage_constraints(struct device *dev,
dev_dbg(dev, "Enabling regulator\n"); dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator); ret = regulator_enable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 1; data->enabled = true;
else else
dev_err(dev, "regulator_enable() failed: %d\n", dev_err(dev, "regulator_enable() failed: %d\n",
ret); ret);
@ -59,7 +59,7 @@ static void update_voltage_constraints(struct device *dev,
dev_dbg(dev, "Disabling regulator\n"); dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator); ret = regulator_disable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 0; data->enabled = false;
else else
dev_err(dev, "regulator_disable() failed: %d\n", dev_err(dev, "regulator_disable() failed: %d\n",
ret); ret);
@ -89,7 +89,7 @@ static void update_current_limit_constraints(struct device *dev,
dev_dbg(dev, "Enabling regulator\n"); dev_dbg(dev, "Enabling regulator\n");
ret = regulator_enable(data->regulator); ret = regulator_enable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 1; data->enabled = true;
else else
dev_err(dev, "regulator_enable() failed: %d\n", dev_err(dev, "regulator_enable() failed: %d\n",
ret); ret);
@ -99,7 +99,7 @@ static void update_current_limit_constraints(struct device *dev,
dev_dbg(dev, "Disabling regulator\n"); dev_dbg(dev, "Disabling regulator\n");
ret = regulator_disable(data->regulator); ret = regulator_disable(data->regulator);
if (ret == 0) if (ret == 0)
data->enabled = 0; data->enabled = false;
else else
dev_err(dev, "regulator_disable() failed: %d\n", dev_err(dev, "regulator_disable() failed: %d\n",
ret); ret);
@ -270,24 +270,28 @@ static DEVICE_ATTR(min_microamps, 0666, show_min_uA, set_min_uA);
static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA); static DEVICE_ATTR(max_microamps, 0666, show_max_uA, set_max_uA);
static DEVICE_ATTR(mode, 0666, show_mode, set_mode); static DEVICE_ATTR(mode, 0666, show_mode, set_mode);
static struct device_attribute *attributes[] = { static struct attribute *regulator_virtual_attributes[] = {
&dev_attr_min_microvolts, &dev_attr_min_microvolts.attr,
&dev_attr_max_microvolts, &dev_attr_max_microvolts.attr,
&dev_attr_min_microamps, &dev_attr_min_microamps.attr,
&dev_attr_max_microamps, &dev_attr_max_microamps.attr,
&dev_attr_mode, &dev_attr_mode.attr,
NULL
}; };
static int regulator_virtual_consumer_probe(struct platform_device *pdev) static const struct attribute_group regulator_virtual_attr_group = {
.attrs = regulator_virtual_attributes,
};
static int __devinit regulator_virtual_probe(struct platform_device *pdev)
{ {
char *reg_id = pdev->dev.platform_data; char *reg_id = pdev->dev.platform_data;
struct virtual_consumer_data *drvdata; struct virtual_consumer_data *drvdata;
int ret, i; int ret;
drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL); drvdata = kzalloc(sizeof(struct virtual_consumer_data), GFP_KERNEL);
if (drvdata == NULL) { if (drvdata == NULL)
return -ENOMEM; return -ENOMEM;
}
mutex_init(&drvdata->lock); mutex_init(&drvdata->lock);
@ -299,13 +303,12 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
goto err; goto err;
} }
for (i = 0; i < ARRAY_SIZE(attributes); i++) { ret = sysfs_create_group(&pdev->dev.kobj,
ret = device_create_file(&pdev->dev, attributes[i]); &regulator_virtual_attr_group);
if (ret != 0) { if (ret != 0) {
dev_err(&pdev->dev, "Failed to create attr %d: %d\n", dev_err(&pdev->dev,
i, ret); "Failed to create attribute group: %d\n", ret);
goto err_regulator; goto err_regulator;
}
} }
drvdata->mode = regulator_get_mode(drvdata->regulator); drvdata->mode = regulator_get_mode(drvdata->regulator);
@ -317,37 +320,36 @@ static int regulator_virtual_consumer_probe(struct platform_device *pdev)
err_regulator: err_regulator:
regulator_put(drvdata->regulator); regulator_put(drvdata->regulator);
err: err:
for (i = 0; i < ARRAY_SIZE(attributes); i++)
device_remove_file(&pdev->dev, attributes[i]);
kfree(drvdata); kfree(drvdata);
return ret; return ret;
} }
static int regulator_virtual_consumer_remove(struct platform_device *pdev) static int __devexit regulator_virtual_remove(struct platform_device *pdev)
{ {
struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev); struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
int i;
for (i = 0; i < ARRAY_SIZE(attributes); i++) sysfs_remove_group(&pdev->dev.kobj, &regulator_virtual_attr_group);
device_remove_file(&pdev->dev, attributes[i]);
if (drvdata->enabled) if (drvdata->enabled)
regulator_disable(drvdata->regulator); regulator_disable(drvdata->regulator);
regulator_put(drvdata->regulator); regulator_put(drvdata->regulator);
kfree(drvdata); kfree(drvdata);
platform_set_drvdata(pdev, NULL);
return 0; return 0;
} }
static struct platform_driver regulator_virtual_consumer_driver = { static struct platform_driver regulator_virtual_consumer_driver = {
.probe = regulator_virtual_consumer_probe, .probe = regulator_virtual_probe,
.remove = regulator_virtual_consumer_remove, .remove = __devexit_p(regulator_virtual_remove),
.driver = { .driver = {
.name = "reg-virt-consumer", .name = "reg-virt-consumer",
.owner = THIS_MODULE,
}, },
}; };
static int __init regulator_virtual_consumer_init(void) static int __init regulator_virtual_consumer_init(void)
{ {
return platform_driver_register(&regulator_virtual_consumer_driver); return platform_driver_register(&regulator_virtual_consumer_driver);

View File

@ -600,6 +600,8 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x; struct wm831x *wm831x = dcdc->wm831x;
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, "HC"), dcdc);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator); regulator_unregister(dcdc->regulator);
@ -615,6 +617,7 @@ static struct platform_driver wm831x_buckv_driver = {
.remove = __devexit_p(wm831x_buckv_remove), .remove = __devexit_p(wm831x_buckv_remove),
.driver = { .driver = {
.name = "wm831x-buckv", .name = "wm831x-buckv",
.owner = THIS_MODULE,
}, },
}; };
@ -769,6 +772,8 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x; struct wm831x *wm831x = dcdc->wm831x;
platform_set_drvdata(pdev, NULL);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator); regulator_unregister(dcdc->regulator);
kfree(dcdc); kfree(dcdc);
@ -781,6 +786,7 @@ static struct platform_driver wm831x_buckp_driver = {
.remove = __devexit_p(wm831x_buckp_remove), .remove = __devexit_p(wm831x_buckp_remove),
.driver = { .driver = {
.name = "wm831x-buckp", .name = "wm831x-buckp",
.owner = THIS_MODULE,
}, },
}; };
@ -895,6 +901,8 @@ static __devexit int wm831x_boostp_remove(struct platform_device *pdev)
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
struct wm831x *wm831x = dcdc->wm831x; struct wm831x *wm831x = dcdc->wm831x;
platform_set_drvdata(pdev, NULL);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc); wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), dcdc);
regulator_unregister(dcdc->regulator); regulator_unregister(dcdc->regulator);
kfree(dcdc); kfree(dcdc);
@ -907,6 +915,7 @@ static struct platform_driver wm831x_boostp_driver = {
.remove = __devexit_p(wm831x_boostp_remove), .remove = __devexit_p(wm831x_boostp_remove),
.driver = { .driver = {
.name = "wm831x-boostp", .name = "wm831x-boostp",
.owner = THIS_MODULE,
}, },
}; };
@ -979,6 +988,8 @@ static __devexit int wm831x_epe_remove(struct platform_device *pdev)
{ {
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev); struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
regulator_unregister(dcdc->regulator); regulator_unregister(dcdc->regulator);
kfree(dcdc); kfree(dcdc);
@ -990,6 +1001,7 @@ static struct platform_driver wm831x_epe_driver = {
.remove = __devexit_p(wm831x_epe_remove), .remove = __devexit_p(wm831x_epe_remove),
.driver = { .driver = {
.name = "wm831x-epe", .name = "wm831x-epe",
.owner = THIS_MODULE,
}, },
}; };

View File

@ -222,6 +222,8 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev)
struct wm831x_isink *isink = platform_get_drvdata(pdev); struct wm831x_isink *isink = platform_get_drvdata(pdev);
struct wm831x *wm831x = isink->wm831x; struct wm831x *wm831x = isink->wm831x;
platform_set_drvdata(pdev, NULL);
wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink); wm831x_free_irq(wm831x, platform_get_irq(pdev, 0), isink);
regulator_unregister(isink->regulator); regulator_unregister(isink->regulator);
@ -235,6 +237,7 @@ static struct platform_driver wm831x_isink_driver = {
.remove = __devexit_p(wm831x_isink_remove), .remove = __devexit_p(wm831x_isink_remove),
.driver = { .driver = {
.name = "wm831x-isink", .name = "wm831x-isink",
.owner = THIS_MODULE,
}, },
}; };

View File

@ -371,6 +371,8 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)
struct wm831x_ldo *ldo = platform_get_drvdata(pdev); struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
struct wm831x *wm831x = ldo->wm831x; struct wm831x *wm831x = ldo->wm831x;
platform_set_drvdata(pdev, NULL);
wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo); wm831x_free_irq(wm831x, platform_get_irq_byname(pdev, "UV"), ldo);
regulator_unregister(ldo->regulator); regulator_unregister(ldo->regulator);
kfree(ldo); kfree(ldo);
@ -383,6 +385,7 @@ static struct platform_driver wm831x_gp_ldo_driver = {
.remove = __devexit_p(wm831x_gp_ldo_remove), .remove = __devexit_p(wm831x_gp_ldo_remove),
.driver = { .driver = {
.name = "wm831x-ldo", .name = "wm831x-ldo",
.owner = THIS_MODULE,
}, },
}; };
@ -640,6 +643,7 @@ static struct platform_driver wm831x_aldo_driver = {
.remove = __devexit_p(wm831x_aldo_remove), .remove = __devexit_p(wm831x_aldo_remove),
.driver = { .driver = {
.name = "wm831x-aldo", .name = "wm831x-aldo",
.owner = THIS_MODULE,
}, },
}; };
@ -811,6 +815,7 @@ static struct platform_driver wm831x_alive_ldo_driver = {
.remove = __devexit_p(wm831x_alive_ldo_remove), .remove = __devexit_p(wm831x_alive_ldo_remove),
.driver = { .driver = {
.name = "wm831x-alive-ldo", .name = "wm831x-alive-ldo",
.owner = THIS_MODULE,
}, },
}; };

View File

@ -290,6 +290,51 @@ static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
return -EINVAL; return -EINVAL;
} }
static int wm8350_isink_enable_time(struct regulator_dev *rdev)
{
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
int isink = rdev_get_id(rdev);
int reg;
switch (isink) {
case WM8350_ISINK_A:
reg = wm8350_reg_read(wm8350, WM8350_CSA_FLASH_CONTROL);
break;
case WM8350_ISINK_B:
reg = wm8350_reg_read(wm8350, WM8350_CSB_FLASH_CONTROL);
break;
default:
return -EINVAL;
}
if (reg & WM8350_CS1_FLASH_MODE) {
switch (reg & WM8350_CS1_ON_RAMP_MASK) {
case 0:
return 0;
case 1:
return 1950;
case 2:
return 3910;
case 3:
return 7800;
}
} else {
switch (reg & WM8350_CS1_ON_RAMP_MASK) {
case 0:
return 0;
case 1:
return 250000;
case 2:
return 500000;
case 3:
return 1000000;
}
}
return -EINVAL;
}
int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode, int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp, u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
u16 drive) u16 drive)
@ -1221,6 +1266,7 @@ static struct regulator_ops wm8350_isink_ops = {
.enable = wm8350_isink_enable, .enable = wm8350_isink_enable,
.disable = wm8350_isink_disable, .disable = wm8350_isink_disable,
.is_enabled = wm8350_isink_is_enabled, .is_enabled = wm8350_isink_is_enabled,
.enable_time = wm8350_isink_enable_time,
}; };
static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = { static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {

View File

@ -317,14 +317,17 @@ static struct regulator_desc regulators[] = {
static int __devinit wm8400_regulator_probe(struct platform_device *pdev) static int __devinit wm8400_regulator_probe(struct platform_device *pdev)
{ {
struct wm8400 *wm8400 = container_of(pdev, struct wm8400, regulators[pdev->id]);
struct regulator_dev *rdev; struct regulator_dev *rdev;
rdev = regulator_register(&regulators[pdev->id], &pdev->dev, rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
pdev->dev.platform_data, dev_get_drvdata(&pdev->dev)); pdev->dev.platform_data, wm8400);
if (IS_ERR(rdev)) if (IS_ERR(rdev))
return PTR_ERR(rdev); return PTR_ERR(rdev);
platform_set_drvdata(pdev, rdev);
return 0; return 0;
} }
@ -332,6 +335,7 @@ static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
{ {
struct regulator_dev *rdev = platform_get_drvdata(pdev); struct regulator_dev *rdev = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
regulator_unregister(rdev); regulator_unregister(rdev);
return 0; return 0;
@ -370,7 +374,6 @@ int wm8400_register_regulator(struct device *dev, int reg,
wm8400->regulators[reg].id = reg; wm8400->regulators[reg].id = reg;
wm8400->regulators[reg].dev.parent = dev; wm8400->regulators[reg].dev.parent = dev;
wm8400->regulators[reg].dev.platform_data = initdata; wm8400->regulators[reg].dev.platform_data = initdata;
dev_set_drvdata(&wm8400->regulators[reg].dev, wm8400);
return platform_device_register(&wm8400->regulators[reg]); return platform_device_register(&wm8400->regulators[reg]);
} }

View File

@ -0,0 +1,307 @@
/*
* wm8994-regulator.c -- Regulator driver for the WM8994
*
* Copyright 2009 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.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; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/gpio.h>
#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/mfd/wm8994/pdata.h>
struct wm8994_ldo {
int enable;
bool is_enabled;
struct regulator_dev *regulator;
struct wm8994 *wm8994;
};
#define WM8994_LDO1_MAX_SELECTOR 0x7
#define WM8994_LDO2_MAX_SELECTOR 0x3
static int wm8994_ldo_enable(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
/* If we have no soft control assume that the LDO is always enabled. */
if (!ldo->enable)
return 0;
gpio_set_value(ldo->enable, 1);
ldo->is_enabled = true;
return 0;
}
static int wm8994_ldo_disable(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
/* If we have no soft control assume that the LDO is always enabled. */
if (!ldo->enable)
return -EINVAL;
gpio_set_value(ldo->enable, 0);
ldo->is_enabled = false;
return 0;
}
static int wm8994_ldo_is_enabled(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
return ldo->is_enabled;
}
static int wm8994_ldo_enable_time(struct regulator_dev *rdev)
{
/* 3ms is fairly conservative but this shouldn't be too performance
* critical; can be tweaked per-system if required. */
return 3000;
}
static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
if (selector > WM8994_LDO1_MAX_SELECTOR)
return -EINVAL;
return (selector * 100000) + 2400000;
}
static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int val;
val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_1);
if (val < 0)
return val;
val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT;
return wm8994_ldo1_list_voltage(rdev, val);
}
static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int selector, v;
selector = (min_uV - 2400000) / 100000;
v = wm8994_ldo1_list_voltage(rdev, selector);
if (v < 0 || v > max_uV)
return -EINVAL;
selector <<= WM8994_LDO1_VSEL_SHIFT;
return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1,
WM8994_LDO1_VSEL_MASK, selector);
}
static struct regulator_ops wm8994_ldo1_ops = {
.enable = wm8994_ldo_enable,
.disable = wm8994_ldo_disable,
.is_enabled = wm8994_ldo_is_enabled,
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo1_list_voltage,
.get_voltage = wm8994_ldo1_get_voltage,
.set_voltage = wm8994_ldo1_set_voltage,
};
static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
if (selector > WM8994_LDO2_MAX_SELECTOR)
return -EINVAL;
return (selector * 100000) + 900000;
}
static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int val;
val = wm8994_reg_read(ldo->wm8994, WM8994_LDO_2);
if (val < 0)
return val;
val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT;
return wm8994_ldo2_list_voltage(rdev, val);
}
static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int selector, v;
selector = (min_uV - 900000) / 100000;
v = wm8994_ldo2_list_voltage(rdev, selector);
if (v < 0 || v > max_uV)
return -EINVAL;
selector <<= WM8994_LDO2_VSEL_SHIFT;
return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2,
WM8994_LDO2_VSEL_MASK, selector);
}
static struct regulator_ops wm8994_ldo2_ops = {
.enable = wm8994_ldo_enable,
.disable = wm8994_ldo_disable,
.is_enabled = wm8994_ldo_is_enabled,
.enable_time = wm8994_ldo_enable_time,
.list_voltage = wm8994_ldo2_list_voltage,
.get_voltage = wm8994_ldo2_get_voltage,
.set_voltage = wm8994_ldo2_set_voltage,
};
static struct regulator_desc wm8994_ldo_desc[] = {
{
.name = "LDO1",
.id = 1,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8994_LDO1_MAX_SELECTOR + 1,
.ops = &wm8994_ldo1_ops,
.owner = THIS_MODULE,
},
{
.name = "LDO2",
.id = 2,
.type = REGULATOR_VOLTAGE,
.n_voltages = WM8994_LDO2_MAX_SELECTOR + 1,
.ops = &wm8994_ldo2_ops,
.owner = THIS_MODULE,
},
};
static __devinit int wm8994_ldo_probe(struct platform_device *pdev)
{
struct wm8994 *wm8994 = dev_get_drvdata(pdev->dev.parent);
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
int id = pdev->id % ARRAY_SIZE(pdata->ldo);
struct wm8994_ldo *ldo;
int ret;
dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
if (!pdata)
return -ENODEV;
ldo = kzalloc(sizeof(struct wm8994_ldo), GFP_KERNEL);
if (ldo == NULL) {
dev_err(&pdev->dev, "Unable to allocate private data\n");
return -ENOMEM;
}
ldo->wm8994 = wm8994;
ldo->is_enabled = true;
if (pdata->ldo[id].enable && gpio_is_valid(pdata->ldo[id].enable)) {
ldo->enable = pdata->ldo[id].enable;
ret = gpio_request(ldo->enable, "WM8994 LDO enable");
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get enable GPIO: %d\n",
ret);
goto err;
}
ret = gpio_direction_output(ldo->enable, ldo->is_enabled);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to set GPIO up: %d\n",
ret);
goto err_gpio;
}
}
ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev,
pdata->ldo[id].init_data, ldo);
if (IS_ERR(ldo->regulator)) {
ret = PTR_ERR(ldo->regulator);
dev_err(wm8994->dev, "Failed to register LDO%d: %d\n",
id + 1, ret);
goto err_gpio;
}
platform_set_drvdata(pdev, ldo);
return 0;
err_gpio:
if (gpio_is_valid(ldo->enable))
gpio_free(ldo->enable);
err:
kfree(ldo);
return ret;
}
static __devexit int wm8994_ldo_remove(struct platform_device *pdev)
{
struct wm8994_ldo *ldo = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
regulator_unregister(ldo->regulator);
if (gpio_is_valid(ldo->enable))
gpio_free(ldo->enable);
kfree(ldo);
return 0;
}
static struct platform_driver wm8994_ldo_driver = {
.probe = wm8994_ldo_probe,
.remove = __devexit_p(wm8994_ldo_remove),
.driver = {
.name = "wm8994-ldo",
.owner = THIS_MODULE,
},
};
static int __init wm8994_ldo_init(void)
{
int ret;
ret = platform_driver_register(&wm8994_ldo_driver);
if (ret != 0)
pr_err("Failed to register Wm8994 GP LDO driver: %d\n", ret);
return ret;
}
subsys_initcall(wm8994_ldo_init);
static void __exit wm8994_ldo_exit(void)
{
platform_driver_unregister(&wm8994_ldo_driver);
}
module_exit(wm8994_ldo_exit);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("WM8994 LDO driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm8994-ldo");

View File

@ -108,6 +108,8 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode,
#define MC13783_REGU_V2 28 #define MC13783_REGU_V2 28
#define MC13783_REGU_V3 29 #define MC13783_REGU_V3 29
#define MC13783_REGU_V4 30 #define MC13783_REGU_V4 30
#define MC13783_REGU_PWGT1SPI 31
#define MC13783_REGU_PWGT2SPI 32
#define MC13783_IRQ_ADCDONE 0 #define MC13783_IRQ_ADCDONE 0
#define MC13783_IRQ_ADCBISDONE 1 #define MC13783_IRQ_ADCBISDONE 1

View File

@ -89,8 +89,9 @@
* REGULATION_OUT Regulator output is out of regulation. * REGULATION_OUT Regulator output is out of regulation.
* FAIL Regulator output has failed. * FAIL Regulator output has failed.
* OVER_TEMP Regulator over temp. * OVER_TEMP Regulator over temp.
* FORCE_DISABLE Regulator shut down by software. * FORCE_DISABLE Regulator forcibly shut down by software.
* VOLTAGE_CHANGE Regulator voltage changed. * VOLTAGE_CHANGE Regulator voltage changed.
* DISABLE Regulator was disabled.
* *
* NOTE: These events can be OR'ed together when passed into handler. * NOTE: These events can be OR'ed together when passed into handler.
*/ */
@ -102,6 +103,7 @@
#define REGULATOR_EVENT_OVER_TEMP 0x10 #define REGULATOR_EVENT_OVER_TEMP 0x10
#define REGULATOR_EVENT_FORCE_DISABLE 0x20 #define REGULATOR_EVENT_FORCE_DISABLE 0x20
#define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40 #define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40
#define REGULATOR_EVENT_DISABLE 0x80
struct regulator; struct regulator;

View File

@ -58,6 +58,9 @@ enum regulator_status {
* @get_optimum_mode: Get the most efficient operating mode for the regulator * @get_optimum_mode: Get the most efficient operating mode for the regulator
* when running with the specified parameters. * when running with the specified parameters.
* *
* @enable_time: Time taken for the regulator voltage output voltage to
* stabalise after being enabled, in microseconds.
*
* @set_suspend_voltage: Set the voltage for the regulator when the system * @set_suspend_voltage: Set the voltage for the regulator when the system
* is suspended. * is suspended.
* @set_suspend_enable: Mark the regulator as enabled when the system is * @set_suspend_enable: Mark the regulator as enabled when the system is
@ -93,6 +96,9 @@ struct regulator_ops {
int (*set_mode) (struct regulator_dev *, unsigned int mode); int (*set_mode) (struct regulator_dev *, unsigned int mode);
unsigned int (*get_mode) (struct regulator_dev *); unsigned int (*get_mode) (struct regulator_dev *);
/* Time taken to enable the regulator */
int (*enable_time) (struct regulator_dev *);
/* report regulator status ... most other accessors report /* report regulator status ... most other accessors report
* control inputs, this reports results of combining inputs * control inputs, this reports results of combining inputs
* from Linux (and other sources) with the actual load. * from Linux (and other sources) with the actual load.

View File

@ -25,6 +25,7 @@ struct regulator_init_data;
* @microvolts: Output voltage of regulator * @microvolts: Output voltage of regulator
* @gpio: GPIO to use for enable control * @gpio: GPIO to use for enable control
* set to -EINVAL if not used * set to -EINVAL if not used
* @startup_delay: Start-up time in microseconds
* @enable_high: Polarity of enable GPIO * @enable_high: Polarity of enable GPIO
* 1 = Active high, 0 = Active low * 1 = Active high, 0 = Active low
* @enabled_at_boot: Whether regulator has been enabled at * @enabled_at_boot: Whether regulator has been enabled at
@ -41,6 +42,7 @@ struct fixed_voltage_config {
const char *supply_name; const char *supply_name;
int microvolts; int microvolts;
int gpio; int gpio;
unsigned startup_delay;
unsigned enable_high:1; unsigned enable_high:1;
unsigned enabled_at_boot:1; unsigned enabled_at_boot:1;
struct regulator_init_data *init_data; struct regulator_init_data *init_data;

View File

@ -0,0 +1,44 @@
/*
* Interface of Maxim max8649
*
* Copyright (C) 2009-2010 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_REGULATOR_MAX8649_H
#define __LINUX_REGULATOR_MAX8649_H
#include <linux/regulator/machine.h>
enum {
MAX8649_EXTCLK_26MHZ = 0,
MAX8649_EXTCLK_13MHZ,
MAX8649_EXTCLK_19MHZ, /* 19.2MHz */
};
enum {
MAX8649_RAMP_32MV = 0,
MAX8649_RAMP_16MV,
MAX8649_RAMP_8MV,
MAX8649_RAMP_4MV,
MAX8649_RAMP_2MV,
MAX8649_RAMP_1MV,
MAX8649_RAMP_0_5MV,
MAX8649_RAMP_0_25MV,
};
struct max8649_platform_data {
struct regulator_init_data *regulator;
unsigned mode:2; /* bit[1:0] = VID1,VID0 */
unsigned extclk_freq:2;
unsigned extclk:1;
unsigned ramp_timing:3;
unsigned ramp_down:1;
};
#endif /* __LINUX_REGULATOR_MAX8649_H */