mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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 ...
This commit is contained in:
commit
f3c3f06705
@ -16,7 +16,7 @@ initialisation code by creating a struct regulator_consumer_supply for
|
||||
each regulator.
|
||||
|
||||
struct regulator_consumer_supply {
|
||||
struct device *dev; /* consumer */
|
||||
const char *dev_name; /* consumer dev_name() */
|
||||
const char *supply; /* consumer supply - e.g. "vcc" */
|
||||
};
|
||||
|
||||
@ -24,13 +24,13 @@ e.g. for the machine above
|
||||
|
||||
static struct regulator_consumer_supply regulator1_consumers[] = {
|
||||
{
|
||||
.dev = &platform_consumerB_device.dev,
|
||||
.supply = "Vcc",
|
||||
.dev_name = "dev_name(consumer B)",
|
||||
.supply = "Vcc",
|
||||
},};
|
||||
|
||||
static struct regulator_consumer_supply regulator2_consumers[] = {
|
||||
{
|
||||
.dev = &platform_consumerA_device.dev,
|
||||
.dev = "dev_name(consumer A"),
|
||||
.supply = "Vcc",
|
||||
},};
|
||||
|
||||
@ -43,6 +43,7 @@ to their supply regulator :-
|
||||
|
||||
static struct regulator_init_data regulator1_data = {
|
||||
.constraints = {
|
||||
.name = "Regulator-1",
|
||||
.min_uV = 3300000,
|
||||
.max_uV = 3300000,
|
||||
.valid_modes_mask = REGULATOR_MODE_NORMAL,
|
||||
@ -51,13 +52,19 @@ static struct regulator_init_data regulator1_data = {
|
||||
.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
|
||||
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
|
||||
field below:-
|
||||
field below and co:-
|
||||
|
||||
static struct regulator_init_data regulator2_data = {
|
||||
.supply_regulator = "regulator_name",
|
||||
.supply_regulator = "Regulator-1",
|
||||
.constraints = {
|
||||
.min_uV = 1800000,
|
||||
.max_uV = 2000000,
|
||||
|
@ -412,7 +412,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
|
||||
if (info->desc.id == res->start)
|
||||
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",
|
||||
(unsigned long long)res->start);
|
||||
return -EINVAL;
|
||||
|
@ -64,6 +64,16 @@ config REGULATOR_USERSPACE_CONSUMER
|
||||
|
||||
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
|
||||
tristate "TI bq24022 Dual Input 1-Cell Li-Ion Charger IC"
|
||||
help
|
||||
|
@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
|
||||
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.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_BQ24022) += bq24022.o
|
||||
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
@ -1425,7 +1425,7 @@ int regulator_enable(struct regulator *regulator)
|
||||
ret = _regulator_enable(rdev);
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
if (ret != 0)
|
||||
if (ret != 0 && rdev->supply)
|
||||
regulator_disable(rdev->supply);
|
||||
|
||||
return ret;
|
||||
@ -2971,6 +2971,43 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
|
||||
}
|
||||
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, ®ulator_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)
|
||||
{
|
||||
int ret;
|
||||
@ -2983,6 +3020,10 @@ static int __init regulator_init(void)
|
||||
pr_warn("regulator: Failed to create debugfs directory\n");
|
||||
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
|
||||
|
||||
regulator_dummy_init();
|
||||
|
358
drivers/regulator/gpio-regulator.c
Normal file
358
drivers/regulator/gpio-regulator.c
Normal file
@ -0,0 +1,358 @@
|
||||
/*
|
||||
* 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)
|
||||
ret = (ret & MAX8649_RAMP_MASK) >> 5;
|
||||
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)
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/max8952.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
@ -47,7 +46,6 @@ enum {
|
||||
struct max8952_data {
|
||||
struct i2c_client *client;
|
||||
struct device *dev;
|
||||
struct mutex mutex;
|
||||
struct max8952_platform_data *pdata;
|
||||
struct regulator_dev *rdev;
|
||||
|
||||
@ -208,7 +206,6 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client,
|
||||
max8952->client = client;
|
||||
max8952->dev = &client->dev;
|
||||
max8952->pdata = pdata;
|
||||
mutex_init(&max8952->mutex);
|
||||
|
||||
max8952->rdev = regulator_register(®ulator, max8952->dev,
|
||||
&pdata->reg_data, max8952);
|
||||
|
@ -63,6 +63,13 @@
|
||||
#define TPS65023_REG_CTRL_LDO2_EN BIT(2)
|
||||
#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 */
|
||||
#define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id) ((ldo_id)*4)
|
||||
#define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id) (0xF0 >> ((ldo_id)*4))
|
||||
@ -85,7 +92,7 @@
|
||||
#define TPS65023_MAX_REG_ID TPS65023_LDO_2
|
||||
|
||||
/* Supported voltage values for regulators */
|
||||
static const u16 VDCDC1_VSEL_table[] = {
|
||||
static const u16 VCORE_VSEL_table[] = {
|
||||
800, 825, 850, 875,
|
||||
900, 925, 950, 975,
|
||||
1000, 1025, 1050, 1075,
|
||||
@ -96,20 +103,29 @@ static const u16 VDCDC1_VSEL_table[] = {
|
||||
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,
|
||||
2200, 2600, 2800, 3150,
|
||||
};
|
||||
|
||||
static const u16 LDO2_VSEL_table[] = {
|
||||
static const u16 TPS65023_LDO2_VSEL_table[] = {
|
||||
1050, 1200, 1300, 1800,
|
||||
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 */
|
||||
struct tps_info {
|
||||
const char *name;
|
||||
@ -127,6 +143,13 @@ struct tps_pmic {
|
||||
struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
|
||||
const struct tps_info *info[TPS65023_NUM_REGULATOR];
|
||||
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)
|
||||
@ -253,7 +276,7 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
|
||||
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
|
||||
return -EINVAL;
|
||||
|
||||
if (dcdc == TPS65023_DCDC_1) {
|
||||
if (dcdc == tps->core_regulator) {
|
||||
data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE);
|
||||
if (data < 0)
|
||||
return data;
|
||||
@ -270,10 +293,10 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
|
||||
struct tps_pmic *tps = rdev_get_drvdata(dev);
|
||||
int dcdc = rdev_get_id(dev);
|
||||
int vsel;
|
||||
int ret;
|
||||
|
||||
if (dcdc != TPS65023_DCDC_1)
|
||||
if (dcdc != tps->core_regulator)
|
||||
return -EINVAL;
|
||||
|
||||
if (min_uV < tps->info[dcdc]->min_uV
|
||||
|| min_uV > tps->info[dcdc]->max_uV)
|
||||
return -EINVAL;
|
||||
@ -292,11 +315,21 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
|
||||
|
||||
*selector = vsel;
|
||||
|
||||
/* write to the register in case we found a match */
|
||||
if (vsel == tps->info[dcdc]->table_len)
|
||||
return -EINVAL;
|
||||
else
|
||||
return tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel);
|
||||
goto failed;
|
||||
|
||||
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)
|
||||
@ -362,7 +395,7 @@ static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
|
||||
if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
|
||||
return -EINVAL;
|
||||
|
||||
if (dcdc == TPS65023_DCDC_1) {
|
||||
if (dcdc == tps->core_regulator) {
|
||||
if (selector >= tps->info[dcdc]->table_len)
|
||||
return -EINVAL;
|
||||
else
|
||||
@ -414,7 +447,8 @@ static struct regmap_config tps65023_regmap_config = {
|
||||
static int __devinit tps_65023_probe(struct i2c_client *client,
|
||||
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_dev *rdev;
|
||||
struct tps_pmic *tps;
|
||||
@ -446,6 +480,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
|
||||
|
||||
/* common for all regulators */
|
||||
tps->client = client;
|
||||
tps->core_regulator = drv_data->core_regulator;
|
||||
|
||||
for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
|
||||
/* Store regulator specific information */
|
||||
@ -453,7 +488,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
|
||||
|
||||
tps->desc[i].name = info->name;
|
||||
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 ?
|
||||
&tps65023_ldo_ops : &tps65023_dcdc_ops);
|
||||
tps->desc[i].type = REGULATOR_VOLTAGE;
|
||||
@ -475,6 +510,14 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
|
||||
|
||||
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;
|
||||
|
||||
fail:
|
||||
@ -507,13 +550,86 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
|
||||
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[] = {
|
||||
{
|
||||
.name = "VDCDC1",
|
||||
.min_uV = 800000,
|
||||
.max_uV = 1600000,
|
||||
.table_len = ARRAY_SIZE(VDCDC1_VSEL_table),
|
||||
.table = VDCDC1_VSEL_table,
|
||||
.table_len = ARRAY_SIZE(VCORE_VSEL_table),
|
||||
.table = VCORE_VSEL_table,
|
||||
},
|
||||
{
|
||||
.name = "VDCDC2",
|
||||
@ -531,23 +647,40 @@ static const struct tps_info tps65023_regs[] = {
|
||||
.name = "LDO1",
|
||||
.min_uV = 1000000,
|
||||
.max_uV = 3150000,
|
||||
.table_len = ARRAY_SIZE(LDO1_VSEL_table),
|
||||
.table = LDO1_VSEL_table,
|
||||
.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(LDO2_VSEL_table),
|
||||
.table = LDO2_VSEL_table,
|
||||
.table_len = ARRAY_SIZE(TPS65023_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[] = {
|
||||
{.name = "tps65023",
|
||||
.driver_data = (unsigned long) tps65023_regs,},
|
||||
.driver_data = (unsigned long) &tps65023_drv_data},
|
||||
{.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[] = {
|
||||
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 {
|
||||
const char *name;
|
||||
unsigned min_uV;
|
||||
@ -598,7 +592,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev)
|
||||
|
||||
tps->desc[i].name = info->name;
|
||||
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 ?
|
||||
&tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
|
||||
tps->desc[i].type = REGULATOR_VOLTAGE;
|
||||
|
@ -332,6 +332,36 @@ static inline int tps6586x_regulator_preinit(struct device *parent,
|
||||
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)
|
||||
{
|
||||
struct tps6586x_regulator *ri;
|
||||
@ -374,7 +404,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, rdev);
|
||||
|
||||
return 0;
|
||||
return tps6586x_regulator_set_slew_rate(pdev);
|
||||
}
|
||||
|
||||
static int __devexit tps6586x_regulator_remove(struct platform_device *pdev)
|
||||
|
@ -43,8 +43,6 @@
|
||||
#define TPS65912_REG_LDO9 12
|
||||
#define TPS65912_REG_LDO10 13
|
||||
|
||||
#define TPS65912_MAX_REG_ID TPS65912_REG_LDO_10
|
||||
|
||||
/* Number of step-down converters available */
|
||||
#define TPS65912_NUM_DCDC 4
|
||||
|
||||
|
@ -1,6 +1,18 @@
|
||||
#ifndef __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 {
|
||||
TPS6586X_ID_SM_0,
|
||||
TPS6586X_ID_SM_1,
|
||||
@ -48,6 +60,10 @@ enum {
|
||||
TPS6586X_INT_RTC_ALM2,
|
||||
};
|
||||
|
||||
struct tps6586x_settings {
|
||||
int slew_rate;
|
||||
};
|
||||
|
||||
struct tps6586x_subdev_info {
|
||||
int id;
|
||||
const char *name;
|
||||
|
87
include/linux/regulator/gpio-regulator.h
Normal file
87
include/linux/regulator/gpio-regulator.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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 {
|
||||
*/
|
||||
struct regulation_constraints {
|
||||
|
||||
char *name;
|
||||
const char *name;
|
||||
|
||||
/* voltage output range (inclusive) - for voltage control */
|
||||
int min_uV;
|
||||
|
Loading…
Reference in New Issue
Block a user