diff options
Diffstat (limited to 'drivers/regulator')
29 files changed, 704 insertions, 45 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index d63fddb0fbb0..ca0d608f8248 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -16,6 +16,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/mfd/88pm860x.h> +#include <linux/module.h> struct pm8607_regulator_info { struct regulator_desc desc; @@ -412,7 +413,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; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c7fd2c0e3f2b..9713b1b860cb 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -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 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 040d5aa63535..93a6318f5328 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -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 diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index cd4104542f0d..5abeb3ac3e8d 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -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> diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 02f3c2333c83..6e1ae69646b3 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -13,6 +13,7 @@ */ #include <linux/init.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/ab8500.h> diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c index 068d488a4f71..e24d1b7d97a8 100644 --- a/drivers/regulator/bq24022.c +++ b/drivers/regulator/bq24022.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/gpio.h> #include <linux/regulator/bq24022.h> #include <linux/regulator/driver.h> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d8e6a429e8ba..669d02160221 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -28,6 +28,7 @@ #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> +#include <linux/module.h> #define CREATE_TRACE_POINTS #include <trace/events/regulator.h> @@ -1425,7 +1426,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; @@ -1552,6 +1553,68 @@ int regulator_force_disable(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_force_disable); +static void regulator_disable_work(struct work_struct *work) +{ + struct regulator_dev *rdev = container_of(work, struct regulator_dev, + disable_work.work); + int count, i, ret; + + mutex_lock(&rdev->mutex); + + BUG_ON(!rdev->deferred_disables); + + count = rdev->deferred_disables; + rdev->deferred_disables = 0; + + for (i = 0; i < count; i++) { + ret = _regulator_disable(rdev); + if (ret != 0) + rdev_err(rdev, "Deferred disable failed: %d\n", ret); + } + + mutex_unlock(&rdev->mutex); + + if (rdev->supply) { + for (i = 0; i < count; i++) { + ret = regulator_disable(rdev->supply); + if (ret != 0) { + rdev_err(rdev, + "Supply disable failed: %d\n", ret); + } + } + } +} + +/** + * regulator_disable_deferred - disable regulator output with delay + * @regulator: regulator source + * @ms: miliseconds until the regulator is disabled + * + * Execute regulator_disable() on the regulator after a delay. This + * is intended for use with devices that require some time to quiesce. + * + * NOTE: this will only disable the regulator output if no other consumer + * devices have it enabled, the regulator device supports disabling and + * machine constraints permit this operation. + */ +int regulator_disable_deferred(struct regulator *regulator, int ms) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret; + + mutex_lock(&rdev->mutex); + rdev->deferred_disables++; + mutex_unlock(&rdev->mutex); + + ret = schedule_delayed_work(&rdev->disable_work, + msecs_to_jiffies(ms)); + if (ret < 0) + return ret; + else + return 0; +} +EXPORT_SYMBOL_GPL(regulator_disable_deferred); + static int _regulator_is_enabled(struct regulator_dev *rdev) { /* If we don't know then assume that the regulator is always on */ @@ -2622,6 +2685,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, INIT_LIST_HEAD(&rdev->consumer_list); INIT_LIST_HEAD(&rdev->list); BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); + INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); /* preform any regulator specific init */ if (init_data->regulator_init) { @@ -2729,6 +2793,7 @@ void regulator_unregister(struct regulator_dev *rdev) #ifdef CONFIG_DEBUG_FS debugfs_remove_recursive(rdev->debugfs); #endif + flush_work_sync(&rdev->disable_work.work); WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); @@ -2907,6 +2972,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; @@ -2919,6 +3021,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(); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 362e08221085..e23ddfa8b2c6 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 2bb8f451cc06..78329751af54 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -13,10 +13,11 @@ #include <linux/err.h> #include <linux/spinlock.h> #include <linux/platform_device.h> -#include <linux/mfd/db8500-prcmu.h> +#include <linux/mfd/dbx500-prcmu.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/db8500-prcmu.h> +#include <linux/module.h> /* * power state reference count diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index f6ef6694ab98..b8f520513ce7 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -16,6 +16,7 @@ */ #include <linux/err.h> +#include <linux/export.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 2fe9d99c9f23..21ecf212a522 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -20,6 +20,7 @@ #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/fixed.h> diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c new file mode 100644 index 000000000000..f0acf52498bd --- /dev/null +++ b/drivers/regulator/gpio-regulator.c @@ -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"); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 0f22ef12601c..72b16b5f3db6 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/regulator/driver.h> #include <linux/regulator/lp3971.h> #include <linux/slab.h> diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 6aa1b506fb5d..fbc5e3741bef 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -12,6 +12,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/i2c.h> +#include <linux/module.h> #include <linux/kernel.h> #include <linux/regulator/driver.h> #include <linux/regulator/lp3972.h> diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 30eb9e54f7ec..1062cf9f02dc 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -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) diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index e4dbd667c043..cc9ec0e03271 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/i2c.h> diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 486ed8141fcd..3883d85c5b88 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -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); diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index ad6628ca94f4..6176129a27e5 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -26,6 +26,7 @@ #include <linux/err.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 730f43ad415b..8479082e1aea 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" #define MC13783_REG_SWITCHERS5 29 @@ -336,9 +337,9 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); - struct mc13783_regulator_platform_data *pdata = + struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13783_regulator_init_data *init_data; + struct mc13xxx_regulator_init_data *init_data; int i, ret; dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id); @@ -381,7 +382,7 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13783_regulator_platform_data *pdata = + struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); int i; diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 3285d41842f2..023d17d022cf 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -18,6 +18,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" #define MC13892_REVISION 7 diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index bc27ab136378..6532853a6ef5 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -23,6 +23,7 @@ #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> +#include <linux/module.h> #include "mc13xxx.h" static int mc13xxx_regulator_enable(struct regulator_dev *rdev) diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 701a5900f83f..9fb4c7b81753 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -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}, { }, }; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index bfffabc21eda..bdef70365f52 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -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; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index bb04a75a4c98..14b9389dd52a 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -14,6 +14,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/err.h> #include <linux/slab.h> @@ -332,6 +333,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 +405,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) diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 3a9313e00fac..39d4a1749e71 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -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 diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 9d5ba9357597..fc6655146999 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -18,6 +18,7 @@ #include <linux/err.h> #include <linux/mutex.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/regulator/userspace-consumer.h> diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 69e550f57638..858c1f861ba5 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> +#include <linux/module.h> struct virtual_consumer_data { struct mutex lock; diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 0f12c70bebc9..71632ddc3781 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -15,6 +15,7 @@ #include <linux/bug.h> #include <linux/err.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/regulator/driver.h> #include <linux/mfd/wm8400-private.h> diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 1a6a690f24db..b87bf5c841f8 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -140,6 +140,14 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 900000; case WM8958: return (selector * 100000) + 1000000; + case WM1811: + switch (selector) { + case 0: + return -EINVAL; + default: + return (selector * 100000) + 950000; + } + break; default: return -EINVAL; } @@ -170,6 +178,11 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, case WM8958: selector = (min_uV - 1000000) / 100000; break; + case WM1811: + selector = (min_uV - 950000) / 100000; + if (selector == 0) + selector = 1; + break; default: return -EINVAL; } |