提交 f3c3f067 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://opensource.wolfsonmicro.com/regulator

* 'for-linus' of git://opensource.wolfsonmicro.com/regulator: (22 commits)
  regulator: Constify constraints name
  regulator: Fix possible nullpointer dereference in regulator_enable()
  regulator: gpio-regulator add dependency on GENERIC_GPIO
  regulator: Add module.h include to gpio-regulator
  regulator: Add driver for gpio-controlled regulators
  regulator: remove duplicate REG_CTRL2 defines in tps65023
  regulator: Clarify documentation for regulator-regulator supplies
  regulator: Fix some bitrot in the machine driver documentation
  regulator: tps65023: Added support for the similiar TPS65020 chip
  regulator: tps65023: Setting correct core regulator for tps65021
  regulator: tps65023: Set missing bit for update core-voltage
  regulator: tps65023: Fixes i2c configuration issues
  regulator: Add debugfs file showing the supply map table
  regulator: tps6586x: add SMx slew rate setting
  regulator: tps65023: Fixes i2c configuration issues
  regulator: tps6507x: Remove num_voltages array
  regulator: max8952: removed unused mutex.
  regulator: fix regulator/consumer.h kernel-doc warning
  regulator: Ensure enough enable time for max8649
  regulator: 88pm8607: Fix off-by-one value range checking in the case of no id is matched
  ...
...@@ -16,7 +16,7 @@ initialisation code by creating a struct regulator_consumer_supply for ...@@ -16,7 +16,7 @@ initialisation code by creating a struct regulator_consumer_supply for
each regulator. each regulator.
struct regulator_consumer_supply { struct regulator_consumer_supply {
struct device *dev; /* consumer */ const char *dev_name; /* consumer dev_name() */
const char *supply; /* consumer supply - e.g. "vcc" */ const char *supply; /* consumer supply - e.g. "vcc" */
}; };
...@@ -24,13 +24,13 @@ e.g. for the machine above ...@@ -24,13 +24,13 @@ e.g. for the machine above
static struct regulator_consumer_supply regulator1_consumers[] = { static struct regulator_consumer_supply regulator1_consumers[] = {
{ {
.dev = &platform_consumerB_device.dev, .dev_name = "dev_name(consumer B)",
.supply = "Vcc", .supply = "Vcc",
},}; },};
static struct regulator_consumer_supply regulator2_consumers[] = { static struct regulator_consumer_supply regulator2_consumers[] = {
{ {
.dev = &platform_consumerA_device.dev, .dev = "dev_name(consumer A"),
.supply = "Vcc", .supply = "Vcc",
},}; },};
...@@ -43,6 +43,7 @@ to their supply regulator :- ...@@ -43,6 +43,7 @@ to their supply regulator :-
static struct regulator_init_data regulator1_data = { static struct regulator_init_data regulator1_data = {
.constraints = { .constraints = {
.name = "Regulator-1",
.min_uV = 3300000, .min_uV = 3300000,
.max_uV = 3300000, .max_uV = 3300000,
.valid_modes_mask = REGULATOR_MODE_NORMAL, .valid_modes_mask = REGULATOR_MODE_NORMAL,
...@@ -51,13 +52,19 @@ static struct regulator_init_data regulator1_data = { ...@@ -51,13 +52,19 @@ static struct regulator_init_data regulator1_data = {
.consumer_supplies = regulator1_consumers, .consumer_supplies = regulator1_consumers,
}; };
The name field should be set to something that is usefully descriptive
for the board for configuration of supplies for other regulators and
for use in logging and other diagnostic output. Normally the name
used for the supply rail in the schematic is a good choice. If no
name is provided then the subsystem will choose one.
Regulator-1 supplies power to Regulator-2. This relationship must be registered Regulator-1 supplies power to Regulator-2. This relationship must be registered
with the core so that Regulator-1 is also enabled when Consumer A enables its with the core so that Regulator-1 is also enabled when Consumer A enables its
supply (Regulator-2). The supply regulator is set by the supply_regulator supply (Regulator-2). The supply regulator is set by the supply_regulator
field below:- field below and co:-
static struct regulator_init_data regulator2_data = { static struct regulator_init_data regulator2_data = {
.supply_regulator = "regulator_name", .supply_regulator = "Regulator-1",
.constraints = { .constraints = {
.min_uV = 1800000, .min_uV = 1800000,
.max_uV = 2000000, .max_uV = 2000000,
......
...@@ -412,7 +412,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) ...@@ -412,7 +412,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
if (info->desc.id == res->start) if (info->desc.id == res->start)
break; break;
} }
if ((i < 0) || (i > PM8607_ID_RG_MAX)) { if (i == ARRAY_SIZE(pm8607_regulator_info)) {
dev_err(&pdev->dev, "Failed to find regulator %llu\n", dev_err(&pdev->dev, "Failed to find regulator %llu\n",
(unsigned long long)res->start); (unsigned long long)res->start);
return -EINVAL; return -EINVAL;
......
...@@ -64,6 +64,16 @@ config REGULATOR_USERSPACE_CONSUMER ...@@ -64,6 +64,16 @@ config REGULATOR_USERSPACE_CONSUMER
If unsure, say no. If unsure, say no.
config REGULATOR_GPIO
tristate "GPIO regulator support"
depends on GENERIC_GPIO
help
This driver provides support for regulators that can be
controlled via gpios.
It is capable of supporting current and voltage regulators
and the platform has to provide a mapping of GPIO-states
to target volts/amps.
config REGULATOR_BQ24022 config REGULATOR_BQ24022
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC" tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
help help
......
...@@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o ...@@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o 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_GPIO) += gpio-regulator.o
obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
...@@ -1425,7 +1425,7 @@ int regulator_enable(struct regulator *regulator) ...@@ -1425,7 +1425,7 @@ int regulator_enable(struct regulator *regulator)
ret = _regulator_enable(rdev); ret = _regulator_enable(rdev);
mutex_unlock(&rdev->mutex); mutex_unlock(&rdev->mutex);
if (ret != 0) if (ret != 0 && rdev->supply)
regulator_disable(rdev->supply); regulator_disable(rdev->supply);
return ret; return ret;
...@@ -2971,6 +2971,43 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) ...@@ -2971,6 +2971,43 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
} }
EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
#ifdef CONFIG_DEBUG_FS
static ssize_t supply_map_read_file(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
ssize_t len, ret = 0;
struct regulator_map *map;
if (!buf)
return -ENOMEM;
list_for_each_entry(map, &regulator_map_list, list) {
len = snprintf(buf + ret, PAGE_SIZE - ret,
"%s -> %s.%s\n",
rdev_get_name(map->regulator), map->dev_name,
map->supply);
if (len >= 0)
ret += len;
if (ret > PAGE_SIZE) {
ret = PAGE_SIZE;
break;
}
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
kfree(buf);
return ret;
}
static const struct file_operations supply_map_fops = {
.read = supply_map_read_file,
.llseek = default_llseek,
};
#endif
static int __init regulator_init(void) static int __init regulator_init(void)
{ {
int ret; int ret;
...@@ -2983,6 +3020,10 @@ static int __init regulator_init(void) ...@@ -2983,6 +3020,10 @@ static int __init regulator_init(void)
pr_warn("regulator: Failed to create debugfs directory\n"); pr_warn("regulator: Failed to create debugfs directory\n");
debugfs_root = NULL; debugfs_root = NULL;
} }
if (IS_ERR(debugfs_create_file("supply_map", 0444, debugfs_root,
NULL, &supply_map_fops)))
pr_warn("regulator: Failed to create supplies debugfs\n");
#endif #endif
regulator_dummy_init(); regulator_dummy_init();
......
/*
* gpio-regulator.c
*
* Copyright 2011 Heiko Stuebner <heiko@sntech.de>
*
* based on fixed.c
*
* Copyright 2008 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.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/mutex.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/gpio-regulator.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/slab.h>
struct gpio_regulator_data {
struct regulator_desc desc;
struct regulator_dev *dev;
int enable_gpio;
bool enable_high;
bool is_enabled;
unsigned startup_delay;
struct gpio *gpios;
int nr_gpios;
struct gpio_regulator_state *states;
int nr_states;
int state;
};
static int gpio_regulator_is_enabled(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
return data->is_enabled;
}
static int gpio_regulator_enable(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
if (gpio_is_valid(data->enable_gpio)) {
gpio_set_value_cansleep(data->enable_gpio, data->enable_high);
data->is_enabled = true;
}
return 0;
}
static int gpio_regulator_disable(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
if (gpio_is_valid(data->enable_gpio)) {
gpio_set_value_cansleep(data->enable_gpio, !data->enable_high);
data->is_enabled = false;
}
return 0;
}
static int gpio_regulator_enable_time(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
return data->startup_delay;
}
static int gpio_regulator_get_value(struct regulator_dev *dev)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
int ptr;
for (ptr = 0; ptr < data->nr_states; ptr++)
if (data->states[ptr].gpios == data->state)
return data->states[ptr].value;
return -EINVAL;
}
static int gpio_regulator_set_value(struct regulator_dev *dev,
int min, int max)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
int ptr, target, state;
target = -1;
for (ptr = 0; ptr < data->nr_states; ptr++)
if (data->states[ptr].value >= min &&
data->states[ptr].value <= max)
target = data->states[ptr].gpios;
if (target < 0)
return -EINVAL;
for (ptr = 0; ptr < data->nr_gpios; ptr++) {
state = (target & (1 << ptr)) >> ptr;
gpio_set_value(data->gpios[ptr].gpio, state);
}
data->state = target;
return 0;
}
static int gpio_regulator_set_voltage(struct regulator_dev *dev,
int min_uV, int max_uV,
unsigned *selector)
{
return gpio_regulator_set_value(dev, min_uV, max_uV);
}
static int gpio_regulator_list_voltage(struct regulator_dev *dev,
unsigned selector)
{
struct gpio_regulator_data *data = rdev_get_drvdata(dev);
if (selector >= data->nr_states)
return -EINVAL;
return data->states[selector].value;
}
static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
int min_uA, int max_uA)
{
return gpio_regulator_set_value(dev, min_uA, max_uA);
}
static struct regulator_ops gpio_regulator_voltage_ops = {
.is_enabled = gpio_regulator_is_enabled,
.enable = gpio_regulator_enable,
.disable = gpio_regulator_disable,
.enable_time = gpio_regulator_enable_time,
.get_voltage = gpio_regulator_get_value,
.set_voltage = gpio_regulator_set_voltage,
.list_voltage = gpio_regulator_list_voltage,
};
static struct regulator_ops gpio_regulator_current_ops = {
.is_enabled = gpio_regulator_is_enabled,
.enable = gpio_regulator_enable,
.disable = gpio_regulator_disable,
.enable_time = gpio_regulator_enable_time,
.get_current_limit = gpio_regulator_get_value,
.set_current_limit = gpio_regulator_set_current_limit,
};
static int __devinit gpio_regulator_probe(struct platform_device *pdev)
{
struct gpio_regulator_config *config = pdev->dev.platform_data;
struct gpio_regulator_data *drvdata;
int ptr, ret, state;
drvdata = kzalloc(sizeof(struct gpio_regulator_data), GFP_KERNEL);
if (drvdata == NULL) {
dev_err(&pdev->dev, "Failed to allocate device data\n");
return -ENOMEM;
}
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
if (drvdata->desc.name == NULL) {
dev_err(&pdev->dev, "Failed to allocate supply name\n");
ret = -ENOMEM;
goto err;
}
drvdata->gpios = kmemdup(config->gpios,
config->nr_gpios * sizeof(struct gpio),
GFP_KERNEL);
if (drvdata->gpios == NULL) {
dev_err(&pdev->dev, "Failed to allocate gpio data\n");
ret = -ENOMEM;
goto err_name;
}
drvdata->states = kmemdup(config->states,
config->nr_states *
sizeof(struct gpio_regulator_state),
GFP_KERNEL);
if (drvdata->states == NULL) {
dev_err(&pdev->dev, "Failed to allocate state data\n");
ret = -ENOMEM;
goto err_memgpio;
}
drvdata->nr_states = config->nr_states;
drvdata->desc.owner = THIS_MODULE;
/* handle regulator type*/
switch (config->type) {
case REGULATOR_VOLTAGE:
drvdata->desc.type = REGULATOR_VOLTAGE;
drvdata->desc.ops = &gpio_regulator_voltage_ops;
drvdata->desc.n_voltages = config->nr_states;
break;
case REGULATOR_CURRENT:
drvdata->desc.type = REGULATOR_CURRENT;
drvdata->desc.ops = &gpio_regulator_current_ops;
break;
default:
dev_err(&pdev->dev, "No regulator type set\n");
ret = -EINVAL;
goto err_memgpio;
break;
}
drvdata->enable_gpio = config->enable_gpio;
drvdata->startup_delay = config->startup_delay;
if (gpio_is_valid(config->enable_gpio)) {
drvdata->enable_high = config->enable_high;
ret = gpio_request(config->enable_gpio, config->supply_name);
if (ret) {
dev_err(&pdev->dev,
"Could not obtain regulator enable GPIO %d: %d\n",
config->enable_gpio, ret);
goto err_memstate;
}
/* set output direction without changing state
* to prevent glitch
*/
if (config->enabled_at_boot) {
drvdata->is_enabled = true;
ret = gpio_direction_output(config->enable_gpio,
config->enable_high);
} else {
drvdata->is_enabled = false;
ret = gpio_direction_output(config->enable_gpio,
!config->enable_high);
}
if (ret) {
dev_err(&pdev->dev,
"Could not configure regulator enable GPIO %d direction: %d\n",
config->enable_gpio, ret);
goto err_enablegpio;
}
} else {
/* Regulator without GPIO control is considered
* always enabled
*/
drvdata->is_enabled = true;
}
drvdata->nr_gpios = config->nr_gpios;
ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
if (ret) {
dev_err(&pdev->dev,
"Could not obtain regulator setting GPIOs: %d\n", ret);
goto err_enablegpio;
}
/* build initial state from gpio init data. */
state = 0;
for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) {
if (config->gpios[ptr].flags & GPIOF_OUT_INIT_HIGH)
state |= (1 << ptr);
}
drvdata->state = state;
drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev,
config->init_data, drvdata);
if (IS_ERR(drvdata->dev)) {
ret = PTR_ERR(drvdata->dev);
dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret);
goto err_stategpio;
}
platform_set_drvdata(pdev, drvdata);
return 0;
err_stategpio:
gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
err_enablegpio:
if (gpio_is_valid(config->enable_gpio))
gpio_free(config->enable_gpio);
err_memstate:
kfree(drvdata->states);
err_memgpio:
kfree(drvdata->gpios);
err_name:
kfree(drvdata->desc.name);
err:
kfree(drvdata);
return ret;
}
static int __devexit gpio_regulator_remove(struct platform_device *pdev)
{
struct gpio_regulator_data *drvdata = platform_get_drvdata(pdev);
regulator_unregister(drvdata->dev);
gpio_free_array(drvdata->gpios, drvdata->nr_gpios);
kfree(drvdata->states);
kfree(drvdata->gpios);
if (gpio_is_valid(drvdata->enable_gpio))
gpio_free(drvdata->enable_gpio);
kfree(drvdata->desc.name);
kfree(drvdata);
return 0;
}
static struct platform_driver gpio_regulator_driver = {
.probe = gpio_regulator_probe,
.remove = __devexit_p(gpio_regulator_remove),
.driver = {
.name = "gpio-regulator",
.owner = THIS_MODULE,
},
};
static int __init gpio_regulator_init(void)
{
return platform_driver_register(&gpio_regulator_driver);
}
subsys_initcall(gpio_regulator_init);
static void __exit gpio_regulator_exit(void)
{
platform_driver_unregister(&gpio_regulator_driver);
}
module_exit(gpio_regulator_exit);
MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
MODULE_DESCRIPTION("gpio voltage regulator");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:gpio-regulator");
...@@ -221,7 +221,7 @@ static int max8649_enable_time(struct regulator_dev *rdev) ...@@ -221,7 +221,7 @@ static int max8649_enable_time(struct regulator_dev *rdev)
ret = (ret & MAX8649_RAMP_MASK) >> 5; ret = (ret & MAX8649_RAMP_MASK) >> 5;
rate = (32 * 1000) >> ret; /* uV/uS */ rate = (32 * 1000) >> ret; /* uV/uS */
return (voltage / rate); return DIV_ROUND_UP(voltage, rate);
} }
static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode)
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/regulator/driver.h> #include <linux/regulator/driver.h>
#include <linux/regulator/max8952.h> #include <linux/regulator/max8952.h>
#include <linux/mutex.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -47,7 +46,6 @@ enum { ...@@ -47,7 +46,6 @@ enum {
struct max8952_data { struct max8952_data {
struct i2c_client *client; struct i2c_client *client;
struct device *dev; struct device *dev;
struct mutex mutex;
struct max8952_platform_data *pdata; struct max8952_platform_data *pdata;
struct regulator_dev *rdev; struct regulator_dev *rdev;
...@@ -208,7 +206,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, ...@@ -208,7 +206,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
max8952->client = client; max8952->client = client;
max8952->dev = &client->dev; max8952->dev = &client->dev;
max8952->pdata = pdata; max8952->pdata = pdata;
mutex_init(&max8952->mutex);
max8952->rdev = regulator_register(&regulator, max8952->dev, max8952->rdev = regulator_register(&regulator, max8952->dev,
&pdata->reg_data, max8952); &pdata->reg_data, max8952);
......
...@@ -63,6 +63,13 @@ ...@@ -63,6 +63,13 @@
#define TPS65023_REG_CTRL_LDO2_EN BIT(2) #define TPS65023_REG_CTRL_LDO2_EN BIT(2)
#define TPS65023_REG_CTRL_LDO1_EN BIT(1) #define TPS65023_REG_CTRL_LDO1_EN BIT(1)
/* REG_CTRL2 bitfields */
#define TPS65023_REG_CTRL2_GO BIT(7)
#define TPS65023_REG_CTRL2_CORE_ADJ BIT(6)
#define TPS65023_REG_CTRL2_DCDC2 BIT(2)
#define TPS65023_REG_CTRL2_DCDC1 BIT(1)
#define TPS65023_REG_CTRL2_DCDC3 BIT(0)
/* LDO_CTRL bitfields */ /* LDO_CTRL bitfields */
#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4) #define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4)) #define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4))
...@@ -85,7 +92,7 @@ ...@@ -85,7 +92,7 @@
#define TPS65023_MAX_REG_ID TPS65023_LDO_2 #define TPS65023_MAX_REG_ID TPS65023_LDO_2
/* Supported voltage values for regulators */ /* Supported voltage values for regulators */
static const u16 VDCDC1_VSEL_table[] = { static const u16 VCORE_VSEL_table[] = {
800, 825, 850, 875, 800, 825, 850, 875,
900, 925, 950, 975, 900, 925, 950, 975,
1000, 1025, 1050, 1075, 1000, 1025, 1050, 1075,
...@@ -96,20 +103,29 @@ static const u16 VDCDC1_VSEL_table[] = { ...@@ -96,20 +103,29 @@ static const u16 VDCDC1_VSEL_table[] = {
1500, 1525, 1550, 1600, 1500, 1525, 1550, 1600,
}; };
static const u16 LDO1_VSEL_table[] = { /* Supported voltage values for LDO regulators for tps65020 */
static const u16 TPS65020_LDO1_VSEL_table[] = {
1000, 1050, 1100, 1300,
1800, 2500, 3000, 3300,
};
static const u16 TPS65020_LDO2_VSEL_table[] = {
1000, 1050, 1100, 1300,
1800, 2500, 3000, 3300,
};
/* Supported voltage values for LDO regulators
* for tps65021 and tps65023 */
static const u16 TPS65023_LDO1_VSEL_table[] = {
1000, 1100, 1300, 1800, 1000, 1100, 1300, 1800,
2200, 2600, 2800, 3150, 2200, 2600, 2800, 3150,
}; };
static const u16 LDO2_VSEL_table[] = { static const u16 TPS65023_LDO2_VSEL_table[] = {
1050, 1200, 1300, 1800, 1050, 1200, 1300, 1800,
2500, 2800, 3000, 3300, 2500, 2800, 3000, 3300,
}; };
static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDC1_VSEL_table),
0, 0, ARRAY_SIZE(LDO1_VSEL_table),
ARRAY_SIZE(LDO2_VSEL_table)};
/* Regulator specific details */ /* Regulator specific details */
struct tps_info { struct tps_info {
const char *name; const char *name;
...@@ -127,6 +143,13 @@ struct tps_pmic { ...@@ -127,6 +143,13 @@ struct tps_pmic {
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR]; struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
const struct tps_info *info[TPS65023_NUM_REGULATOR]; const struct tps_info *info[TPS65023_NUM_REGULATOR];
struct regmap *regmap; struct regmap *regmap;
u8 core_regulator;
};
/* Struct passed as driver data */
struct tps_driver_data {
const struct tps_info *info;
u8 core_regulator;
}; };
static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
...@@ -253,7 +276,7 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) ...@@ -253,7 +276,7 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL; return -EINVAL;
if (dcdc == TPS65023_DCDC_1) { if (dcdc == tps->core_regulator) {
data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE); data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE);
if (data < 0) if (data < 0)
return data; return data;
...@@ -270,10 +293,10 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, ...@@ -270,10 +293,10 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
struct tps_pmic *tps = rdev_get_drvdata(dev); struct tps_pmic *tps = rdev_get_drvdata(dev);
int dcdc = rdev_get_id(dev); int dcdc = rdev_get_id(dev);
int vsel; int vsel;
int ret;
if (dcdc != TPS65023_DCDC_1) if (dcdc != tps->core_regulator)
return -EINVAL; return -EINVAL;
if (min_uV < tps->info[dcdc]->min_uV if (min_uV < tps->info[dcdc]->min_uV
|| min_uV > tps->info[dcdc]->max_uV) || min_uV > tps->info[dcdc]->max_uV)
return -EINVAL; return -EINVAL;
...@@ -292,11 +315,21 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, ...@@ -292,11 +315,21 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
*selector = vsel; *selector = vsel;
/* write to the register in case we found a match */
if (vsel == tps->info[dcdc]->table_len) if (vsel == tps->info[dcdc]->table_len)
return -EINVAL; goto failed;
else
return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel); ret = tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
/* Tell the chip that we have changed the value in DEFCORE
* and its time to update the core voltage
*/
tps_65023_set_bits(tps, TPS65023_REG_CON_CTRL2,
TPS65023_REG_CTRL2_GO);
return ret;
failed:
return -EINVAL;
} }
static int tps65023_ldo_get_voltage(struct regulator_dev *dev) static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
...@@ -362,7 +395,7 @@ static int tps65023_dcdc_list_voltage(struct regulator_dev *dev, ...@@ -362,7 +395,7 @@ static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
return -EINVAL; return -EINVAL;
if (dcdc == TPS65023_DCDC_1) { if (dcdc == tps->core_regulator) {
if (selector >= tps->info[dcdc]->table_len) if (selector >= tps->info[dcdc]->table_len)
return -EINVAL; return -EINVAL;
else else
...@@ -414,7 +447,8 @@ static struct regmap_config tps65023_regmap_config = { ...@@ -414,7 +447,8 @@ static struct regmap_config tps65023_regmap_config = {
static int __devinit tps_65023_probe(struct i2c_client *client, static int __devinit tps_65023_probe(struct i2c_client *client,
const struct i2c_device_id *id) const struct i2c_device_id *id)
{ {
const struct tps_info *info = (void *)id->driver_data; const struct tps_driver_data *drv_data = (void *)id->driver_data;
const struct tps_info *info = drv_data->info;
struct regulator_init_data *init_data; struct regulator_init_data *init_data;
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct tps_pmic *tps; struct tps_pmic *tps;
...@@ -446,6 +480,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, ...@@ -446,6 +480,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
/* common for all regulators */ /* common for all regulators */
tps->client = client; tps->client = client;
tps->core_regulator = drv_data->core_regulator;
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) { for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
/* Store regulator specific information */ /* Store regulator specific information */
...@@ -453,7 +488,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, ...@@ -453,7 +488,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
tps->desc[i].name = info->name; tps->desc[i].name = info->name;
tps->desc[i].id = i; tps->desc[i].id = i;
tps->desc[i].n_voltages = num_voltages[i]; tps->desc[i].n_voltages = info->table_len;
tps->desc[i].ops = (i > TPS65023_DCDC_3 ? tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops); &tps65023_ldo_ops : &tps65023_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].type = REGULATOR_VOLTAGE;
...@@ -475,6 +510,14 @@ static int __devinit tps_65023_probe(struct i2c_client *client, ...@@ -475,6 +510,14 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
i2c_set_clientdata(client, tps); i2c_set_clientdata(client, tps);
/* Enable setting output voltage by I2C */
tps_65023_clear_bits(tps, TPS65023_REG_CON_CTRL2,
TPS65023_REG_CTRL2_CORE_ADJ);
/* Enable setting output voltage by I2C */
tps_65023_clear_bits(tps, TPS65023_REG_CON_CTRL2,
TPS65023_REG_CTRL2_CORE_ADJ);
return 0; return 0;
fail: fail:
...@@ -507,13 +550,86 @@ static int __devexit tps_65023_remove(struct i2c_client *client) ...@@ -507,13 +550,86 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
return 0; return 0;
} }
static const struct tps_info tps65020_regs[] = {
{
.name = "VDCDC1",
.min_uV = 3300000,
.max_uV = 3300000,
.fixed = 1,
},
{
.name = "VDCDC2",
.min_uV = 1800000,
.max_uV = 1800000,
.fixed = 1,
},
{
.name = "VDCDC3",
.min_uV = 800000,
.max_uV = 1600000,
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3150000,
.table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
.table = TPS65020_LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 1050000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
.table = TPS65020_LDO2_VSEL_table,
},
};
static const struct tps_info tps65021_regs[] = {
{
.name = "VDCDC1",
.min_uV = 3300000,
.max_uV = 3300000,
.fixed = 1,
},
{
.name = "VDCDC2",
.min_uV = 1800000,
.max_uV = 1800000,
.fixed = 1,
},
{
.name = "VDCDC3",
.min_uV = 800000,
.max_uV = 1600000,
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VCORE_VSEL_table,
},
{
.name = "LDO1",
.min_uV = 1000000,
.max_uV = 3150000,
.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = TPS65023_LDO1_VSEL_table,
},
{
.name = "LDO2",
.min_uV = 1050000,
.max_uV = 3300000,
.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = TPS65023_LDO2_VSEL_table,
},
};
static const struct tps_info tps65023_regs[] = { static const struct tps_info tps65023_regs[] = {
{ {
.name = "VDCDC1", .name = "VDCDC1",
.min_uV = 800000, .min_uV = 800000,
.max_uV = 1600000, .max_uV = 1600000,
.table_len = ARRAY_SIZE(VDCDC1_VSEL_table), .table_len = ARRAY_SIZE(VCORE_VSEL_table),
.table = VDCDC1_VSEL_table, .table = VCORE_VSEL_table,
}, },
{ {
.name = "VDCDC2", .name = "VDCDC2",
...@@ -531,23 +647,40 @@ static const struct tps_info tps65023_regs[] = { ...@@ -531,23 +647,40 @@ static const struct tps_info tps65023_regs[] = {
.name = "LDO1", .name = "LDO1",
.min_uV = 1000000, .min_uV = 1000000,
.max_uV = 3150000, .max_uV = 3150000,
.table_len = ARRAY_SIZE(LDO1_VSEL_table), .table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
.table = LDO1_VSEL_table, .table = TPS65023_LDO1_VSEL_table,
}, },
{ {
.name = "LDO2", .name = "LDO2",
.min_uV = 1050000, .min_uV = 1050000,
.max_uV = 3300000, .max_uV = 3300000,
.table_len = ARRAY_SIZE(LDO2_VSEL_table), .table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
.table = LDO2_VSEL_table, .table = TPS65023_LDO2_VSEL_table,
}, },
}; };
static struct tps_driver_data tps65020_drv_data = {
.info = tps65020_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65021_drv_data = {
.info = tps65021_regs,
.core_regulator = TPS65023_DCDC_3,
};
static struct tps_driver_data tps65023_drv_data = {
.info = tps65023_regs,
.core_regulator = TPS65023_DCDC_1,
};
static const struct i2c_device_id tps_65023_id[] = { static const struct i2c_device_id tps_65023_id[] = {
{.name = "tps65023", {.name = "tps65023",
.driver_data = (unsigned long) tps65023_regs,}, .driver_data = (unsigned long) &tps65023_drv_data},
{.name = "tps65021", {.name = "tps65021",
.driver_data = (unsigned long) tps65023_regs,}, .driver_data = (unsigned long) &tps65021_drv_data,},
{.name = "tps65020",
.driver_data = (unsigned long) &tps65020_drv_data},
{ }, { },
}; };
......
...@@ -90,12 +90,6 @@ static const u16 LDO2_VSEL_table[] = { ...@@ -90,12 +90,6 @@ static const u16 LDO2_VSEL_table[] = {
3000, 3100, 3200, 3300, 3000, 3100, 3200, 3300,
}; };
static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(VDCDCx_VSEL_table),
ARRAY_SIZE(LDO1_VSEL_table),
ARRAY_SIZE(LDO2_VSEL_table)};
struct tps_info { struct tps_info {
const char *name; const char *name;
unsigned min_uV; unsigned min_uV;
...@@ -598,7 +592,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev) ...@@ -598,7 +592,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev)
tps->desc[i].name = info->name; tps->desc[i].name = info->name;
tps->desc[i].id = i; tps->desc[i].id = i;
tps->desc[i].n_voltages = num_voltages[i]; tps->desc[i].n_voltages = info->table_len;
tps->desc[i].ops = (i > TPS6507X_DCDC_3 ? tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
&tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops); &tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
tps->desc[i].type = REGULATOR_VOLTAGE; tps->desc[i].type = REGULATOR_VOLTAGE;
......
...@@ -332,6 +332,36 @@ static inline int tps6586x_regulator_preinit(struct device *parent, ...@@ -332,6 +332,36 @@ static inline int tps6586x_regulator_preinit(struct device *parent,
1 << ri->enable_bit[1]); 1 << ri->enable_bit[1]);
} }
static int tps6586x_regulator_set_slew_rate(struct platform_device *pdev)
{
struct device *parent = pdev->dev.parent;
struct regulator_init_data *p = pdev->dev.platform_data;
struct tps6586x_settings *setting = p->driver_data;
uint8_t reg;
if (setting == NULL)
return 0;
if (!(setting->slew_rate & TPS6586X_SLEW_RATE_SET))
return 0;
/* only SM0 and SM1 can have the slew rate settings */
switch (pdev->id) {
case TPS6586X_ID_SM_0:
reg = TPS6586X_SM0SL;
break;
case TPS6586X_ID_SM_1:
reg = TPS6586X_SM1SL;
break;
default:
dev_warn(&pdev->dev, "Only SM0/SM1 can set slew rate\n");
return -EINVAL;
}
return tps6586x_write(parent, reg,
setting->slew_rate & TPS6586X_SLEW_RATE_MASK);
}
static inline struct tps6586x_regulator *find_regulator_info(int id) static inline struct tps6586x_regulator *find_regulator_info(int id)
{ {
struct tps6586x_regulator *ri; struct tps6586x_regulator *ri;
...@@ -374,7 +404,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) ...@@ -374,7 +404,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rdev); platform_set_drvdata(pdev, rdev);
return 0; return tps6586x_regulator_set_slew_rate(pdev);
} }
static int __devexit tps6586x_regulator_remove(struct platform_device *pdev) static int __devexit tps6586x_regulator_remove(struct platform_device *pdev)
......
...@@ -43,8 +43,6 @@ ...@@ -43,8 +43,6 @@
#define TPS65912_REG_LDO9 12 #define TPS65912_REG_LDO9 12
#define TPS65912_REG_LDO10 13 #define TPS65912_REG_LDO10 13
#define TPS65912_MAX_REG_ID TPS65912_REG_LDO_10
/* Number of step-down converters available */ /* Number of step-down converters available */
#define TPS65912_NUM_DCDC 4 #define TPS65912_NUM_DCDC 4
......
#ifndef __LINUX_MFD_TPS6586X_H #ifndef __LINUX_MFD_TPS6586X_H
#define __LINUX_MFD_TPS6586X_H #define __LINUX_MFD_TPS6586X_H
#define TPS6586X_SLEW_RATE_INSTANTLY 0x00
#define TPS6586X_SLEW_RATE_110UV 0x01
#define TPS6586X_SLEW_RATE_220UV 0x02
#define TPS6586X_SLEW_RATE_440UV 0x03
#define TPS6586X_SLEW_RATE_880UV 0x04
#define TPS6586X_SLEW_RATE_1760UV 0x05
#define TPS6586X_SLEW_RATE_3520UV 0x06
#define TPS6586X_SLEW_RATE_7040UV 0x07
#define TPS6586X_SLEW_RATE_SET 0x08
#define TPS6586X_SLEW_RATE_MASK 0x07
enum { enum {
TPS6586X_ID_SM_0, TPS6586X_ID_SM_0,
TPS6586X_ID_SM_1, TPS6586X_ID_SM_1,
...@@ -48,6 +60,10 @@ enum { ...@@ -48,6 +60,10 @@ enum {
TPS6586X_INT_RTC_ALM2, TPS6586X_INT_RTC_ALM2,
}; };
struct tps6586x_settings {
int slew_rate;
};
struct tps6586x_subdev_info { struct tps6586x_subdev_info {
int id; int id;
const char *name; const char *name;
......
/*
* gpio-regulator.h
*
* Copyright 2011 Heiko Stuebner <heiko@sntech.de>
*
* based on fixed.h
*
* Copyright 2008 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* Copyright (c) 2009 Nokia Corporation
* Roger Quadros <ext-roger.quadros@nokia.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.
*/
#ifndef __REGULATOR_GPIO_H
#define __REGULATOR_GPIO_H
struct regulator_init_data;
enum regulator_type;
/**
* struct gpio_regulator_state - state description
* @value: microvolts or microamps
* @gpios: bitfield of gpio target-states for the value
*
* This structure describes a supported setting of the regulator
* and the necessary gpio-state to achieve it.
*
* The n-th bit in the bitfield describes the state of the n-th GPIO
* from the gpios-array defined in gpio_regulator_config below.
*/
struct gpio_regulator_state {
int value;
int gpios;
};
/**
* struct gpio_regulator_config - config structure
* @supply_name: Name of the regulator supply
* @enable_gpio: GPIO to use for enable control
* set to -EINVAL if not used
* @enable_high: Polarity of enable GPIO
* 1 = Active high, 0 = Active low
* @enabled_at_boot: Whether regulator has been enabled at
* boot or not. 1 = Yes, 0 = No
* This is used to keep the regulator at
* the default state
* @startup_delay: Start-up time in microseconds
* @gpios: Array containing the gpios needed to control
* the setting of the regulator
* @nr_gpios: Number of gpios
* @states: Array of gpio_regulator_state entries describing
* the gpio state for specific voltages
* @nr_states: Number of states available
* @regulator_type: either REGULATOR_CURRENT or REGULATOR_VOLTAGE
* @init_data: regulator_init_data
*
* This structure contains gpio-voltage regulator configuration
* information that must be passed by platform code to the
* gpio-voltage regulator driver.
*/
struct gpio_regulator_config {
const char *supply_name;
int enable_gpio;
unsigned enable_high:1;
unsigned enabled_at_boot:1;
unsigned startup_delay;
struct gpio *gpios;
int nr_gpios;
struct gpio_regulator_state *states;
int nr_states;
enum regulator_type type;
struct regulator_init_data *init_data;
};
#endif
...@@ -95,7 +95,7 @@ struct regulator_state { ...@@ -95,7 +95,7 @@ struct regulator_state {
*/ */
struct regulation_constraints { struct regulation_constraints {
char *name; const char *name;
/* voltage output range (inclusive) - for voltage control */ /* voltage output range (inclusive) - for voltage control */
int min_uV; int min_uV;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册