diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 10:20:34 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-01-10 10:20:34 -0800 |
commit | 269d430131b699c2cadf58495f025a4092959ef5 (patch) | |
tree | d9972cd7e03f82b6ac59bc471fb59e49dc6fcaab | |
parent | d52739c62e0096dccea59f012d80256c6e359a98 (diff) | |
parent | 0c437c4ae71c0a8110eb21c06b99853c7056b317 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (40 commits)
regulator: set constraints.apply_uV to 0 in of_get_fixed_voltage_config
regulator: max8925: fix enabled/disabled judgement mistake
regulator: add regulator_bulk_force_disable function
regulator: pass regulator_register of_node in fixed voltage driver
regulator: add regulator_force_disable() definition for !CONFIG_REGULATOR
regulator: Enable supply regulator if child rail is enabled.
regulator: mc13892: Convert to devm_kzalloc()
regulator: mc13783: Convert to devm_kzalloc()
regulator: Fix checking return value of create_regulator
regulator: Fix the error handling if create_regulator fails
regulator: Export regulator_is_supported_voltage()
regulator: mc13892: add device tree probe support
regulator: mc13892: remove the unnecessary prefix from regulator name
regulator: Convert wm831x regulator drivers to devm_kzalloc()
regulator: da9052: Staticize non-exported symbols
regulator: Replace kzalloc with devm_kzalloc and if-else with a switch-case for da9052-regulator
regulator: Update da9052-regulator for DT changes
regulator: DA9052/53 Regulator support
regulator: pass device_node to of_get_regulator_init_data()
regulator: If a single voltage is set with device tree then set apply_uV
...
57 files changed, 1368 insertions, 341 deletions
diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.txt b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt new file mode 100644 index 000000000000..9cf57fd042d2 --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.txt @@ -0,0 +1,29 @@ +Fixed Voltage regulators + +Required properties: +- compatible: Must be "regulator-fixed"; + +Optional properties: +- gpio: gpio to use for enable control +- startup-delay-us: startup time in microseconds +- enable-active-high: Polarity of GPIO is Active high +If this property is missing, the default assumed is Active low. + +Any property defined as part of the core regulator +binding, defined in regulator.txt, can also be used. +However a fixed voltage regulator is expected to have the +regulator-min-microvolt and regulator-max-microvolt +to be the same. + +Example: + + abc: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "fixed-supply"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + gpio = <&gpio1 16 0>; + startup-delay-us = <70000>; + enable-active-high; + regulator-boot-on + }; diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt new file mode 100644 index 000000000000..5b7a408acdaa --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -0,0 +1,54 @@ +Voltage/Current Regulators + +Optional properties: +- regulator-name: A string used as a descriptive name for regulator outputs +- regulator-min-microvolt: smallest voltage consumers may set +- regulator-max-microvolt: largest voltage consumers may set +- regulator-microvolt-offset: Offset applied to voltages to compensate for voltage drops +- regulator-min-microamp: smallest current consumers may set +- regulator-max-microamp: largest current consumers may set +- regulator-always-on: boolean, regulator should never be disabled +- regulator-boot-on: bootloader/firmware enabled regulator +- <name>-supply: phandle to the parent supply/regulator node + +Example: + + xyzreg: regulator@0 { + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + vin-supply = <&vin>; + }; + +Regulator Consumers: +Consumer nodes can reference one or more of its supplies/ +regulators using the below bindings. + +- <name>-supply: phandle to the regulator node + +These are the same bindings that a regulator in the above +example used to reference its own supply, in which case +its just seen as a special case of a regulator being a +consumer itself. + +Example of a consumer device node (mmc) referencing two +regulators (twl_reg1 and twl_reg2), + + twl_reg1: regulator@0 { + ... + ... + ... + }; + + twl_reg2: regulator@1 { + ... + ... + ... + }; + + mmc: mmc@0x0 { + ... + ... + vmmc-supply = <&twl_reg1>; + vmmcaux-supply = <&twl_reg2>; + }; diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt index 3f8b528f237e..e272d9909e39 100644 --- a/Documentation/power/regulator/regulator.txt +++ b/Documentation/power/regulator/regulator.txt @@ -12,7 +12,7 @@ Drivers can register a regulator by calling :- struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, struct device *dev, struct regulator_init_data *init_data, - void *driver_data); + void *driver_data, struct device_node *of_node); This will register the regulators capabilities and operations to the regulator core. diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index ca0d608f8248..df33530cec4a 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -427,7 +427,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) /* replace driver_data with info */ info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata, info); + pdata, info, NULL); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", info->desc.name); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 9713b1b860cb..7a61b17ddd04 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -93,6 +93,7 @@ config REGULATOR_MAX1586 config REGULATOR_MAX8649 tristate "Maxim 8649 voltage regulator" depends on I2C + select REGMAP_I2C help This driver controls a Maxim 8649 voltage output regulator via I2C bus. @@ -177,6 +178,13 @@ config REGULATOR_DA903X Say y here to support the BUCKs and LDOs regulators found on Dialog Semiconductor DA9030/DA9034 PMIC. +config REGULATOR_DA9052 + tristate "Dialog DA9052/DA9053 regulators" + depends on PMIC_DA9052 + help + This driver supports the voltage regulators of DA9052-BC and + DA9053-AA/Bx PMIC. + config REGULATOR_PCF50633 tristate "PCF50633 regulator driver" depends on MFD_PCF50633 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 93a6318f5328..503bac87715e 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_REGULATOR) += core.o dummy.o +obj-$(CONFIG_OF) += of_regulator.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o @@ -29,6 +30,7 @@ obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_WM8994) += wm8994-regulator.o obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o +obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 298c6c6a2795..685ad43b0749 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -63,7 +63,7 @@ static int aat2870_ldo_set_voltage_sel(struct regulator_dev *rdev, struct aat2870_data *aat2870 = dev_get_drvdata(ri->pdev->dev.parent); return aat2870->update(aat2870, ri->voltage_addr, ri->voltage_mask, - (selector << ri->voltage_shift) & ri->voltage_mask); + selector << ri->voltage_shift); } static int aat2870_ldo_get_voltage_sel(struct regulator_dev *rdev) @@ -188,7 +188,7 @@ static int aat2870_regulator_probe(struct platform_device *pdev) ri->pdev = pdev; rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri); + pdev->dev.platform_data, ri, NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "Failed to register regulator %s\n", ri->desc.name); diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 585e4946fe0a..042271aace6a 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -634,7 +634,7 @@ static int __devinit ab3100_regulators_probe(struct platform_device *pdev) rdev = regulator_register(&ab3100_regulator_desc[i], &pdev->dev, &plfdata->reg_constraints[i], - reg); + reg, NULL); if (IS_ERR(rdev)) { err = PTR_ERR(rdev); diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 6e1ae69646b3..e91b8ddc2793 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -822,7 +822,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* register regulator with framework */ info->regulator = regulator_register(&info->desc, &pdev->dev, - &pdata->regulator[i], info); + &pdata->regulator[i], info, NULL); if (IS_ERR(info->regulator)) { err = PTR_ERR(info->regulator); dev_err(&pdev->dev, "failed to register regulator %s\n", diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index a4be41614eeb..483c80930852 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -233,7 +233,7 @@ static int __devinit ad5398_probe(struct i2c_client *client, chip->current_mask = (chip->current_level - 1) << chip->current_offset; chip->rdev = regulator_register(&ad5398_reg, &client->dev, - init_data, chip); + init_data, chip, NULL); if (IS_ERR(chip->rdev)) { ret = PTR_ERR(chip->rdev); dev_err(&client->dev, "failed to register %s %s\n", diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c index e24d1b7d97a8..9fab6d1bbe80 100644 --- a/drivers/regulator/bq24022.c +++ b/drivers/regulator/bq24022.c @@ -107,7 +107,7 @@ static int __init bq24022_probe(struct platform_device *pdev) ret = gpio_direction_output(pdata->gpio_nce, 1); bq24022 = regulator_register(&bq24022_desc, &pdev->dev, - pdata->init_data, pdata); + pdata->init_data, pdata, NULL); if (IS_ERR(bq24022)) { dev_dbg(&pdev->dev, "couldn't register regulator\n"); ret = PTR_ERR(bq24022); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 938398f3e869..ca86f39a0fdc 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -25,6 +25,8 @@ #include <linux/mutex.h> #include <linux/suspend.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> @@ -132,6 +134,33 @@ static struct regulator *get_device_regulator(struct device *dev) return NULL; } +/** + * of_get_regulator - get a regulator device node based on supply name + * @dev: Device pointer for the consumer (of regulator) device + * @supply: regulator supply name + * + * Extract the regulator device node corresponding to the supply name. + * retruns the device node corresponding to the regulator if found, else + * returns NULL. + */ +static struct device_node *of_get_regulator(struct device *dev, const char *supply) +{ + struct device_node *regnode = NULL; + char prop_name[32]; /* 32 is max size of property name */ + + dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); + + snprintf(prop_name, 32, "%s-supply", supply); + regnode = of_parse_phandle(dev->of_node, prop_name, 0); + + if (!regnode) { + dev_warn(dev, "%s property in node %s references invalid phandle", + prop_name, dev->of_node->full_name); + return NULL; + } + return regnode; +} + /* Platform voltage constraint check */ static int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV) @@ -883,8 +912,12 @@ static int set_machine_constraints(struct regulator_dev *rdev, int ret = 0; struct regulator_ops *ops = rdev->desc->ops; - rdev->constraints = kmemdup(constraints, sizeof(*constraints), - GFP_KERNEL); + if (constraints) + rdev->constraints = kmemdup(constraints, sizeof(*constraints), + GFP_KERNEL); + else + rdev->constraints = kzalloc(sizeof(*constraints), + GFP_KERNEL); if (!rdev->constraints) return -ENOMEM; @@ -893,7 +926,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, goto out; /* do we need to setup our suspend state */ - if (constraints->initial_state) { + if (rdev->constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { rdev_err(rdev, "failed to set suspend state\n"); @@ -901,7 +934,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } - if (constraints->initial_mode) { + if (rdev->constraints->initial_mode) { if (!ops->set_mode) { rdev_err(rdev, "no set_mode operation\n"); ret = -EINVAL; @@ -952,9 +985,8 @@ static int set_supply(struct regulator_dev *rdev, rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); - if (IS_ERR(rdev->supply)) { - err = PTR_ERR(rdev->supply); - rdev->supply = NULL; + if (rdev->supply == NULL) { + err = -ENOMEM; return err; } @@ -1148,6 +1180,30 @@ static int _regulator_get_enable_time(struct regulator_dev *rdev) return rdev->desc->ops->enable_time(rdev); } +static struct regulator_dev *regulator_dev_lookup(struct device *dev, + const char *supply) +{ + struct regulator_dev *r; + struct device_node *node; + + /* first do a dt based lookup */ + if (dev && dev->of_node) { + node = of_get_regulator(dev, supply); + if (node) + list_for_each_entry(r, ®ulator_list, list) + if (r->dev.parent && + node == r->dev.of_node) + return r; + } + + /* if not found, try doing it non-dt way */ + list_for_each_entry(r, ®ulator_list, list) + if (strcmp(rdev_get_name(r), supply) == 0) + return r; + + return NULL; +} + /* Internal regulator request function */ static struct regulator *_regulator_get(struct device *dev, const char *id, int exclusive) @@ -1168,6 +1224,10 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, mutex_lock(®ulator_list_mutex); + rdev = regulator_dev_lookup(dev, id); + if (rdev) + goto found; + list_for_each_entry(map, ®ulator_map_list, list) { /* If the mapping has a device set up it must match */ if (map->dev_name && @@ -1221,6 +1281,7 @@ found: if (regulator == NULL) { regulator = ERR_PTR(-ENOMEM); module_put(rdev->owner); + goto out; } rdev->open_count++; @@ -1726,6 +1787,7 @@ int regulator_is_supported_voltage(struct regulator *regulator, return 0; } +EXPORT_SYMBOL_GPL(regulator_is_supported_voltage); static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) @@ -2429,6 +2491,43 @@ err: EXPORT_SYMBOL_GPL(regulator_bulk_disable); /** + * regulator_bulk_force_disable - force disable multiple regulator consumers + * + * @num_consumers: Number of consumers + * @consumers: Consumer data; clients are stored here. + * @return 0 on success, an errno on failure + * + * This convenience API allows consumers to forcibly disable multiple regulator + * clients in a single API call. + * NOTE: This should be used for situations when device damage will + * likely occur if the regulators are not disabled (e.g. over temp). + * Although regulator_force_disable function call for some consumers can + * return error numbers, the function is called for all consumers. + */ +int regulator_bulk_force_disable(int num_consumers, + struct regulator_bulk_data *consumers) +{ + int i; + int ret; + + for (i = 0; i < num_consumers; i++) + consumers[i].ret = + regulator_force_disable(consumers[i].consumer); + + for (i = 0; i < num_consumers; i++) { + if (consumers[i].ret != 0) { + ret = consumers[i].ret; + goto out; + } + } + + return 0; +out: + return ret; +} +EXPORT_SYMBOL_GPL(regulator_bulk_force_disable); + +/** * regulator_bulk_free - free multiple regulator consumers * * @num_consumers: Number of consumers @@ -2503,7 +2602,8 @@ static int add_regulator_attributes(struct regulator_dev *rdev) int status = 0; /* some attributes need specific methods to be displayed */ - if (ops->get_voltage || ops->get_voltage_sel) { + if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || + (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0)) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -2637,11 +2737,13 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) */ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, struct device *dev, const struct regulator_init_data *init_data, - void *driver_data) + void *driver_data, struct device_node *of_node) { + const struct regulation_constraints *constraints = NULL; static atomic_t regulator_no = ATOMIC_INIT(0); struct regulator_dev *rdev; int ret, i; + const char *supply = NULL; if (regulator_desc == NULL) return ERR_PTR(-EINVAL); @@ -2653,9 +2755,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, regulator_desc->type != REGULATOR_CURRENT) return ERR_PTR(-EINVAL); - if (!init_data) - return ERR_PTR(-EINVAL); - /* Only one of each should be implemented */ WARN_ON(regulator_desc->ops->get_voltage && regulator_desc->ops->get_voltage_sel); @@ -2688,7 +2787,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); /* preform any regulator specific init */ - if (init_data->regulator_init) { + if (init_data && init_data->regulator_init) { ret = init_data->regulator_init(rdev->reg_data); if (ret < 0) goto clean; @@ -2696,6 +2795,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; + rdev->dev.of_node = of_node; rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); @@ -2708,7 +2808,10 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, dev_set_drvdata(&rdev->dev, rdev); /* set regulator constraints */ - ret = set_machine_constraints(rdev, &init_data->constraints); + if (init_data) + constraints = &init_data->constraints; + + ret = set_machine_constraints(rdev, constraints); if (ret < 0) goto scrub; @@ -2717,21 +2820,18 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (ret < 0) goto scrub; - if (init_data->supply_regulator) { + if (init_data && init_data->supply_regulator) + supply = init_data->supply_regulator; + else if (regulator_desc->supply_name) + supply = regulator_desc->supply_name; + + if (supply) { struct regulator_dev *r; - int found = 0; - list_for_each_entry(r, ®ulator_list, list) { - if (strcmp(rdev_get_name(r), - init_data->supply_regulator) == 0) { - found = 1; - break; - } - } + r = regulator_dev_lookup(dev, supply); - if (!found) { - dev_err(dev, "Failed to find supply %s\n", - init_data->supply_regulator); + if (!r) { + dev_err(dev, "Failed to find supply %s\n", supply); ret = -ENODEV; goto scrub; } @@ -2739,18 +2839,28 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, ret = set_supply(rdev, r); if (ret < 0) goto scrub; + + /* Enable supply if rail is enabled */ + if (rdev->desc->ops->is_enabled && + rdev->desc->ops->is_enabled(rdev)) { + ret = regulator_enable(rdev->supply); + if (ret < 0) + goto scrub; + } } /* add consumers devices */ - for (i = 0; i < init_data->num_consumer_supplies; i++) { - ret = set_consumer_device_supply(rdev, - init_data->consumer_supplies[i].dev, - init_data->consumer_supplies[i].dev_name, - init_data->consumer_supplies[i].supply); - if (ret < 0) { - dev_err(dev, "Failed to set supply %s\n", + if (init_data) { + for (i = 0; i < init_data->num_consumer_supplies; i++) { + ret = set_consumer_device_supply(rdev, + init_data->consumer_supplies[i].dev, + init_data->consumer_supplies[i].dev_name, init_data->consumer_supplies[i].supply); - goto unset_supplies; + if (ret < 0) { + dev_err(dev, "Failed to set supply %s\n", + init_data->consumer_supplies[i].supply); + goto unset_supplies; + } } } diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index e23ddfa8b2c6..8dbc54da7d70 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -537,7 +537,7 @@ static int __devinit da903x_regulator_probe(struct platform_device *pdev) ri->desc.ops = &da9030_regulator_ldo1_15_ops; rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri); + pdev->dev.platform_data, ri, NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c new file mode 100644 index 000000000000..3767364452fd --- /dev/null +++ b/drivers/regulator/da9052-regulator.c @@ -0,0 +1,606 @@ +/* +* da9052-regulator.c: Regulator driver for DA9052 +* +* Copyright(c) 2011 Dialog Semiconductor Ltd. +* +* Author: David Dajun Chen <dchen@diasemi.com> +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> + +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/reg.h> +#include <linux/mfd/da9052/pdata.h> + +/* Buck step size */ +#define DA9052_BUCK_PERI_3uV_STEP 100000 +#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV 24 +#define DA9052_CONST_3uV 3000000 + +#define DA9052_MIN_UA 0 +#define DA9052_MAX_UA 3 +#define DA9052_CURRENT_RANGE 4 + +/* Bit masks */ +#define DA9052_BUCK_ILIM_MASK_EVEN 0x0c +#define DA9052_BUCK_ILIM_MASK_ODD 0xc0 + +static const u32 da9052_current_limits[3][4] = { + {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */ + {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */ + {800000, 1000000, 1200000, 1500000}, /* DA9053-AA/Bx BUCK-PRO, + * BUCK-MEM and BUCK-PERI + */ +}; + +struct da9052_regulator_info { + struct regulator_desc reg_desc; + int step_uV; + int min_uV; + int max_uV; + unsigned char volt_shift; + unsigned char en_bit; + unsigned char activate_bit; +}; + +struct da9052_regulator { + struct da9052 *da9052; + struct da9052_regulator_info *info; + struct regulator_dev *rdev; +}; + +static int verify_range(struct da9052_regulator_info *info, + int min_uV, int max_uV) +{ + if (min_uV > info->max_uV || max_uV < info->min_uV) + return -EINVAL; + + return 0; +} + +static int da9052_regulator_enable(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + + return da9052_reg_update(regulator->da9052, + DA9052_BUCKCORE_REG + offset, + 1 << info->en_bit, 1 << info->en_bit); +} + +static int da9052_regulator_disable(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + + return da9052_reg_update(regulator->da9052, + DA9052_BUCKCORE_REG + offset, + 1 << info->en_bit, 0); +} + +static int da9052_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); + if (ret < 0) + return ret; + + return ret & (1 << info->en_bit); +} + +static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + int offset = rdev_get_id(rdev); + int ret, row = 2; + + ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2); + if (ret < 0) + return ret; + + /* Determine the even or odd position of the buck current limit + * register field + */ + if (offset % 2 == 0) + ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2; + else + ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6; + + /* Select the appropriate current limit range */ + if (regulator->da9052->chip_id == DA9052) + row = 0; + else if (offset == 0) + row = 1; + + return da9052_current_limits[row][ret]; +} + +static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + int offset = rdev_get_id(rdev); + int reg_val = 0; + int i, row = 2; + + /* Select the appropriate current limit range */ + if (regulator->da9052->chip_id == DA9052) + row = 0; + else if (offset == 0) + row = 1; + + if (min_uA > da9052_current_limits[row][DA9052_MAX_UA] || + max_uA < da9052_current_limits[row][DA9052_MIN_UA]) + return -EINVAL; + + for (i = 0; i < DA9052_CURRENT_RANGE; i++) { + if (min_uA <= da9052_current_limits[row][i]) { + reg_val = i; + break; + } + } + + /* Determine the even or odd position of the buck current limit + * register field + */ + if (offset % 2 == 0) + return da9052_reg_update(regulator->da9052, + DA9052_BUCKA_REG + offset/2, + DA9052_BUCK_ILIM_MASK_EVEN, + reg_val << 2); + else + return da9052_reg_update(regulator->da9052, + DA9052_BUCKA_REG + offset/2, + DA9052_BUCK_ILIM_MASK_ODD, + reg_val << 6); +} + +static int da9052_list_buckperi_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int volt_uV; + + if ((regulator->da9052->chip_id == DA9052) && + (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { + volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) + + info->min_uV); + volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) + * (DA9052_BUCK_PERI_3uV_STEP); + } else + volt_uV = (selector * info->step_uV) + info->min_uV; + + if (volt_uV > info->max_uV) + return -EINVAL; + + return volt_uV; +} + +static int da9052_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int volt_uV; + + volt_uV = info->min_uV + info->step_uV * selector; + + if (volt_uV > info->max_uV) + return -EINVAL; + + return volt_uV; +} + +static int da9052_regulator_set_voltage_int(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned int *selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + int ret; + + ret = verify_range(info, min_uV, max_uV); + if (ret < 0) + return ret; + + if (min_uV < info->min_uV) + min_uV = info->min_uV; + + *selector = (min_uV - info->min_uV) / info->step_uV; + + ret = da9052_list_voltage(rdev, *selector); + if (ret < 0) + return ret; + + return da9052_reg_update(regulator->da9052, + DA9052_BUCKCORE_REG + offset, + (1 << info->volt_shift) - 1, *selector); +} + +static int da9052_set_ldo_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned int *selector) +{ + return da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); +} + +static int da9052_set_ldo5_6_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned int *selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int ret; + + ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); + if (ret < 0) + return ret; + + /* Some LDOs are DVC controlled which requires enabling of + * the LDO activate bit to implment the changes on the + * LDO output. + */ + return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0, + info->activate_bit); +} + +static int da9052_set_dcdc_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned int *selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int ret; + + ret = da9052_regulator_set_voltage_int(rdev, min_uV, max_uV, selector); + if (ret < 0) + return ret; + + /* Some DCDCs are DVC controlled which requires enabling of + * the DCDC activate bit to implment the changes on the + * DCDC output. + */ + return da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 0, + info->activate_bit); +} + +static int da9052_get_regulator_voltage_sel(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); + if (ret < 0) + return ret; + + ret &= ((1 << info->volt_shift) - 1); + + return ret; +} + +static int da9052_set_buckperi_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *selector) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + int ret; + + ret = verify_range(info, min_uV, max_uV); + if (ret < 0) + return ret; + + if (min_uV < info->min_uV) + min_uV = info->min_uV; + + if ((regulator->da9052->chip_id == DA9052) && + (min_uV >= DA9052_CONST_3uV)) + *selector = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + + ((min_uV - DA9052_CONST_3uV) / + (DA9052_BUCK_PERI_3uV_STEP)); + else + *selector = (min_uV - info->min_uV) / info->step_uV; + + ret = da9052_list_buckperi_voltage(rdev, *selector); + if (ret < 0) + return ret; + + return da9052_reg_update(regulator->da9052, + DA9052_BUCKCORE_REG + offset, + (1 << info->volt_shift) - 1, *selector); +} + +static int da9052_get_buckperi_voltage_sel(struct regulator_dev *rdev) +{ + struct da9052_regulator *regulator = rdev_get_drvdata(rdev); + struct da9052_regulator_info *info = regulator->info; + int offset = rdev_get_id(rdev); + int ret; + + ret = da9052_reg_read(regulator->da9052, DA9052_BUCKCORE_REG + offset); + if (ret < 0) + return ret; + + ret &= ((1 << info->volt_shift) - 1); + + return ret; +} + +static struct regulator_ops da9052_buckperi_ops = { + .list_voltage = da9052_list_buckperi_voltage, + .get_voltage_sel = da9052_get_buckperi_voltage_sel, + .set_voltage = da9052_set_buckperi_voltage, + + .get_current_limit = da9052_dcdc_get_current_limit, + .set_current_limit = da9052_dcdc_set_current_limit, + + .is_enabled = da9052_regulator_is_enabled, + .enable = da9052_regulator_enable, + .disable = da9052_regulator_disable, +}; + +static struct regulator_ops da9052_dcdc_ops = { + .set_voltage = da9052_set_dcdc_voltage, + .get_current_limit = da9052_dcdc_get_current_limit, + .set_current_limit = da9052_dcdc_set_current_limit, + + .list_voltage = da9052_list_voltage, + .get_voltage_sel = da9052_get_regulator_voltage_sel, + .is_enabled = da9052_regulator_is_enabled, + .enable = da9052_regulator_enable, + .disable = da9052_regulator_disable, +}; + +static struct regulator_ops da9052_ldo5_6_ops = { + .set_voltage = da9052_set_ldo5_6_voltage, + + .list_voltage = da9052_list_voltage, + .get_voltage_sel = da9052_get_regulator_voltage_sel, + .is_enabled = da9052_regulator_is_enabled, + .enable = da9052_regulator_enable, + .disable = da9052_regulator_disable, +}; + +static struct regulator_ops da9052_ldo_ops = { + .set_voltage = da9052_set_ldo_voltage, + + .list_voltage = da9052_list_voltage, + .get_voltage_sel = da9052_get_regulator_voltage_sel, + .is_enabled = da9052_regulator_is_enabled, + .enable = da9052_regulator_enable, + .disable = da9052_regulator_disable, +}; + +#define DA9052_LDO5_6(_id, step, min, max, sbits, ebits, abits) \ +{\ + .reg_desc = {\ + .name = "LDO" #_id,\ + .ops = &da9052_ldo5_6_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .min_uV = (min) * 1000,\ + .max_uV = (max) * 1000,\ + .step_uV = (step) * 1000,\ + .volt_shift = (sbits),\ + .en_bit = (ebits),\ + .activate_bit = (abits),\ +} + +#define DA9052_LDO(_id, step, min, max, sbits, ebits, abits) \ +{\ + .reg_desc = {\ + .name = "LDO" #_id,\ + .ops = &da9052_ldo_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .min_uV = (min) * 1000,\ + .max_uV = (max) * 1000,\ + .step_uV = (step) * 1000,\ + .volt_shift = (sbits),\ + .en_bit = (ebits),\ + .activate_bit = (abits),\ +} + +#define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ +{\ + .reg_desc = {\ + .name = "BUCK" #_id,\ + .ops = &da9052_dcdc_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .min_uV = (min) * 1000,\ + .max_uV = (max) * 1000,\ + .step_uV = (step) * 1000,\ + .volt_shift = (sbits),\ + .en_bit = (ebits),\ + .activate_bit = (abits),\ +} + +#define DA9052_BUCKPERI(_id, step, min, max, sbits, ebits, abits) \ +{\ + .reg_desc = {\ + .name = "BUCK" #_id,\ + .ops = &da9052_buckperi_ops,\ + .type = REGULATOR_VOLTAGE,\ + .id = _id,\ + .owner = THIS_MODULE,\ + },\ + .min_uV = (min) * 1000,\ + .max_uV = (max) * 1000,\ + .step_uV = (step) * 1000,\ + .volt_shift = (sbits),\ + .en_bit = (ebits),\ + .activate_bit = (abits),\ +} + +static struct da9052_regulator_info da9052_regulator_info[] = { + /* Buck1 - 4 */ + DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_BUCKPERI(3, 50, 1800, 3600, 5, 6, 0), + /* LD01 - LDO10 */ + DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), + DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), +}; + +static struct da9052_regulator_info da9053_regulator_info[] = { + /* Buck1 - 4 */ + DA9052_DCDC(0, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), + DA9052_DCDC(1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), + DA9052_DCDC(2, 25, 925, 2500, 6, 6, DA9052_SUPPLY_VBMEMGO), + DA9052_BUCKPERI(3, 25, 925, 2500, 6, 6, 0), + /* LD01 - LDO10 */ + DA9052_LDO(4, 50, 600, 1800, 5, 6, 0), + DA9052_LDO5_6(5, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), + DA9052_LDO5_6(6, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), + DA9052_LDO(7, 25, 1725, 3300, 6, 6, 0), + DA9052_LDO(8, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(9, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(10, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(11, 50, 1200, 3600, 6, 6, 0), + DA9052_LDO(12, 50, 1250, 3650, 6, 6, 0), + DA9052_LDO(13, 50, 1200, 3600, 6, 6, 0), +}; + +static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, + int id) +{ + struct da9052_regulator_info *info; + int i; + + switch (chip_id) { + case DA9052: + for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) { + info = &da9052_regulator_info[i]; + if (info->reg_desc.id == id) + return info; + } + break; + case DA9053_AA: + case DA9053_BA: + case DA9053_BB: + for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { + info = &da9053_regulator_info[i]; + if (info->reg_desc.id == id) + return info; + } + break; + } + + return NULL; +} + +static int __devinit da9052_regulator_probe(struct platform_device *pdev) +{ + struct da9052_regulator *regulator; + struct da9052 *da9052; + struct da9052_pdata *pdata; + int ret; + + regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator), + GFP_KERNEL); + if (!regulator) + return -ENOMEM; + + da9052 = dev_get_drvdata(pdev->dev.parent); + pdata = da9052->dev->platform_data; + regulator->da9052 = da9052; + + regulator->info = find_regulator_info(regulator->da9052->chip_id, + pdev->id); + if (regulator->info == NULL) { + dev_err(&pdev->dev, "invalid regulator ID specified\n"); + ret = -EINVAL; + goto err; + } + regulator->rdev = regulator_register(®ulator->info->reg_desc, + &pdev->dev, + pdata->regulators[pdev->id], + regulator, NULL); + if (IS_ERR(regulator->rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + regulator->info->reg_desc.name); + ret = PTR_ERR(regulator->rdev); + goto err; + } + + platform_set_drvdata(pdev, regulator); + + return 0; +err: + devm_kfree(&pdev->dev, regulator); + return ret; +} + +static int __devexit da9052_regulator_remove(struct platform_device *pdev) +{ + struct da9052_regulator *regulator = platform_get_drvdata(pdev); + + regulator_unregister(regulator->rdev); + devm_kfree(&pdev->dev, regulator); + + return 0; +} + +static struct platform_driver da9052_regulator_driver = { + .probe = da9052_regulator_probe, + .remove = __devexit_p(da9052_regulator_remove), + .driver = { + .name = "da9052-regulator", + .owner = THIS_MODULE, + }, +}; + +static int __init da9052_regulator_init(void) +{ + return platform_driver_register(&da9052_regulator_driver); +} +subsys_initcall(da9052_regulator_init); + +static void __exit da9052_regulator_exit(void) +{ + platform_driver_unregister(&da9052_regulator_driver); +} +module_exit(da9052_regulator_exit); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9052-regulator"); diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 78329751af54..515443fcd26b 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -486,7 +486,7 @@ static int __devinit db8500_regulator_probe(struct platform_device *pdev) /* register with the regulator framework */ info->rdev = regulator_register(&info->desc, &pdev->dev, - init_data, info); + init_data, info, NULL); if (IS_ERR(info->rdev)) { err = PTR_ERR(info->rdev); dev_err(&pdev->dev, "failed to register %s: err %i\n", diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c index b8f520513ce7..0ee00de4be72 100644 --- a/drivers/regulator/dummy.c +++ b/drivers/regulator/dummy.c @@ -42,7 +42,7 @@ static int __devinit dummy_regulator_probe(struct platform_device *pdev) int ret; dummy_regulator_rdev = regulator_register(&dummy_desc, NULL, - &dummy_initdata, NULL); + &dummy_initdata, NULL, NULL); if (IS_ERR(dummy_regulator_rdev)) { ret = PTR_ERR(dummy_regulator_rdev); pr_err("Failed to register regulator: %d\n", ret); diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 21ecf212a522..e24e3a174c4b 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -27,6 +27,10 @@ #include <linux/gpio.h> #include <linux/delay.h> #include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/regulator/of_regulator.h> +#include <linux/regulator/machine.h> struct fixed_voltage_data { struct regulator_desc desc; @@ -38,6 +42,58 @@ struct fixed_voltage_data { bool is_enabled; }; + +/** + * of_get_fixed_voltage_config - extract fixed_voltage_config structure info + * @dev: device requesting for fixed_voltage_config + * + * Populates fixed_voltage_config structure by extracting data from device + * tree node, returns a pointer to the populated structure of NULL if memory + * alloc fails. + */ +static struct fixed_voltage_config * +of_get_fixed_voltage_config(struct device *dev) +{ + struct fixed_voltage_config *config; + struct device_node *np = dev->of_node; + const __be32 *delay; + struct regulator_init_data *init_data; + + config = devm_kzalloc(dev, sizeof(struct fixed_voltage_config), + GFP_KERNEL); + if (!config) + return NULL; + + config->init_data = of_get_regulator_init_data(dev, dev->of_node); + if (!config->init_data) + return NULL; + + init_data = config->init_data; + init_data->constraints.apply_uV = 0; + + config->supply_name = init_data->constraints.name; + if (init_data->constraints.min_uV == init_data->constraints.max_uV) { + config->microvolts = init_data->constraints.min_uV; + } else { + dev_err(dev, + "Fixed regulator specified with variable voltages\n"); + return NULL; + } + + if (init_data->constraints.boot_on) + config->enabled_at_boot = true; + + config->gpio = of_get_named_gpio(np, "gpio", 0); + delay = of_get_property(np, "startup-delay-us", NULL); + if (delay) + config->startup_delay = be32_to_cpu(*delay); + + if (of_find_property(np, "enable-active-high", NULL)) + config->enable_high = true; + + return config; +} + static int fixed_voltage_is_enabled(struct regulator_dev *dev) { struct fixed_voltage_data *data = rdev_get_drvdata(dev); @@ -80,7 +136,10 @@ static int fixed_voltage_get_voltage(struct regulator_dev *dev) { struct fixed_voltage_data *data = rdev_get_drvdata(dev); - return data->microvolts; + if (data->microvolts) + return data->microvolts; + else + return -EINVAL; } static int fixed_voltage_list_voltage(struct regulator_dev *dev, @@ -105,10 +164,18 @@ static struct regulator_ops fixed_voltage_ops = { static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) { - struct fixed_voltage_config *config = pdev->dev.platform_data; + struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; int ret; + if (pdev->dev.of_node) + config = of_get_fixed_voltage_config(&pdev->dev); + else + config = pdev->dev.platform_data; + + if (!config) + return -ENOMEM; + drvdata = kzalloc(sizeof(struct fixed_voltage_data), GFP_KERNEL); if (drvdata == NULL) { dev_err(&pdev->dev, "Failed to allocate device data\n"); @@ -180,7 +247,8 @@ static int __devinit reg_fixed_voltage_probe(struct platform_device *pdev) } drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, - config->init_data, drvdata); + config->init_data, drvdata, + pdev->dev.of_node); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); @@ -217,12 +285,23 @@ static int __devexit reg_fixed_voltage_remove(struct platform_device *pdev) return 0; } +#if defined(CONFIG_OF) +static const struct of_device_id fixed_of_match[] __devinitconst = { + { .compatible = "regulator-fixed", }, + {}, +}; +MODULE_DEVICE_TABLE(of, fixed_of_match); +#else +#define fixed_of_match NULL +#endif + static struct platform_driver regulator_fixed_voltage_driver = { .probe = reg_fixed_voltage_probe, .remove = __devexit_p(reg_fixed_voltage_remove), .driver = { .name = "reg-fixed-voltage", .owner = THIS_MODULE, + .of_match_table = fixed_of_match, }, }; diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index f0acf52498bd..42e1cb1835e5 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -284,7 +284,7 @@ static int __devinit gpio_regulator_probe(struct platform_device *pdev) drvdata->state = state; drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, - config->init_data, drvdata); + config->init_data, drvdata, NULL); if (IS_ERR(drvdata->dev)) { ret = PTR_ERR(drvdata->dev); dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index e4b3592e8176..c1a456c4257c 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -170,7 +170,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, for (i = 0; i < 3; i++) { pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev, - init_data, pmic); + init_data, pmic, NULL); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); err = PTR_ERR(pmic->rdev[i]); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 72b16b5f3db6..0cfabd318a59 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -451,7 +451,7 @@ static int __devinit setup_regulators(struct lp3971 *lp3971, for (i = 0; i < pdata->num_regulators; i++) { struct lp3971_regulator_subdev *reg = &pdata->regulators[i]; lp3971->rdev[i] = regulator_register(®ulators[reg->id], - lp3971->dev, reg->initdata, lp3971); + lp3971->dev, reg->initdata, lp3971, NULL); if (IS_ERR(lp3971->rdev[i])) { err = PTR_ERR(lp3971->rdev[i]); diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index fbc5e3741bef..49a15eefe5fe 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -555,7 +555,7 @@ static int __devinit setup_regulators(struct lp3972 *lp3972, for (i = 0; i < pdata->num_regulators; i++) { struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; lp3972->rdev[i] = regulator_register(®ulators[reg->id], - lp3972->dev, reg->initdata, lp3972); + lp3972->dev, reg->initdata, lp3972, NULL); if (IS_ERR(lp3972->rdev[i])) { err = PTR_ERR(lp3972->rdev[i]); diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 3f49512c5134..40e7a4db2853 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -214,7 +214,7 @@ static int __devinit max1586_pmic_probe(struct i2c_client *client, } rdev[i] = regulator_register(&max1586_reg[id], &client->dev, pdata->subdevs[i].platform_data, - max1586); + max1586, NULL); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 1062cf9f02dc..b06a2399587c 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -16,6 +16,7 @@ #include <linux/regulator/driver.h> #include <linux/slab.h> #include <linux/regulator/max8649.h> +#include <linux/regmap.h> #define MAX8649_DCDC_VMIN 750000 /* uV */ #define MAX8649_DCDC_VMAX 1380000 /* uV */ @@ -49,9 +50,8 @@ struct max8649_regulator_info { struct regulator_dev *regulator; - struct i2c_client *i2c; struct device *dev; - struct mutex io_lock; + struct regmap *regmap; int vol_reg; unsigned mode:2; /* bit[1:0] = VID1, VID0 */ @@ -63,71 +63,6 @@ struct max8649_regulator_info { /* I2C operations */ -static inline int max8649_read_device(struct i2c_client *i2c, - int reg, int bytes, void *dest) -{ - unsigned char data; - int ret; - - data = (unsigned char)reg; - ret = i2c_master_send(i2c, &data, 1); - if (ret < 0) - return ret; - ret = i2c_master_recv(i2c, dest, bytes); - if (ret < 0) - return ret; - return 0; -} - -static inline int max8649_write_device(struct i2c_client *i2c, - int reg, int bytes, void *src) -{ - unsigned char buf[bytes + 1]; - int ret; - - buf[0] = (unsigned char)reg; - memcpy(&buf[1], src, bytes); - - ret = i2c_master_send(i2c, buf, bytes + 1); - if (ret < 0) - return ret; - return 0; -} - -static int max8649_reg_read(struct i2c_client *i2c, int reg) -{ - struct max8649_regulator_info *info = i2c_get_clientdata(i2c); - unsigned char data; - int ret; - - mutex_lock(&info->io_lock); - ret = max8649_read_device(i2c, reg, 1, &data); - mutex_unlock(&info->io_lock); - - if (ret < 0) - return ret; - return (int)data; -} - -static int max8649_set_bits(struct i2c_client *i2c, int reg, - unsigned char mask, unsigned char data) -{ - struct max8649_regulator_info *info = i2c_get_clientdata(i2c); - unsigned char value; - int ret; - - mutex_lock(&info->io_lock); - ret = max8649_read_device(i2c, reg, 1, &value); - if (ret < 0) - goto out; - value &= ~mask; - value |= data; - ret = max8649_write_device(i2c, reg, 1, &value); -out: - mutex_unlock(&info->io_lock); - return ret; -} - static inline int check_range(int min_uV, int max_uV) { if ((min_uV < MAX8649_DCDC_VMIN) || (max_uV > MAX8649_DCDC_VMAX) @@ -144,13 +79,14 @@ static int max8649_list_voltage(struct regulator_dev *rdev, unsigned index) static int max8649_get_voltage(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); + unsigned int val; unsigned char data; int ret; - ret = max8649_reg_read(info->i2c, info->vol_reg); - if (ret < 0) + ret = regmap_read(info->regmap, info->vol_reg, &val); + if (ret != 0) return ret; - data = (unsigned char)ret & MAX8649_VOL_MASK; + data = (unsigned char)val & MAX8649_VOL_MASK; return max8649_list_voltage(rdev, data); } @@ -170,14 +106,14 @@ static int max8649_set_voltage(struct regulator_dev *rdev, mask = MAX8649_VOL_MASK; *selector = data & mask; - return max8649_set_bits(info->i2c, info->vol_reg, mask, data); + return regmap_update_bits(info->regmap, info->vol_reg, mask, data); } /* EN_PD means pulldown on EN input */ static int max8649_enable(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, 0); + return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, 0); } /* @@ -187,38 +123,40 @@ static int max8649_enable(struct regulator_dev *rdev) static int max8649_disable(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); - return max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_EN_PD, + return regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_EN_PD, MAX8649_EN_PD); } static int max8649_is_enabled(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); + unsigned int val; int ret; - ret = max8649_reg_read(info->i2c, MAX8649_CONTROL); - if (ret < 0) + ret = regmap_read(info->regmap, MAX8649_CONTROL, &val); + if (ret != 0) return ret; - return !((unsigned char)ret & MAX8649_EN_PD); + return !((unsigned char)val & MAX8649_EN_PD); } static int max8649_enable_time(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); int voltage, rate, ret; + unsigned int val; /* get voltage */ - ret = max8649_reg_read(info->i2c, info->vol_reg); - if (ret < 0) + ret = regmap_read(info->regmap, info->vol_reg, &val); + if (ret != 0) return ret; - ret &= MAX8649_VOL_MASK; + val &= MAX8649_VOL_MASK; voltage = max8649_list_voltage(rdev, (unsigned char)ret); /* uV */ /* get rate */ - ret = max8649_reg_read(info->i2c, MAX8649_RAMP); - if (ret < 0) + ret = regmap_read(info->regmap, MAX8649_RAMP, &val); + if (ret != 0) return ret; - ret = (ret & MAX8649_RAMP_MASK) >> 5; + ret = (val & MAX8649_RAMP_MASK) >> 5; rate = (32 * 1000) >> ret; /* uV/uS */ return DIV_ROUND_UP(voltage, rate); @@ -230,12 +168,12 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) switch (mode) { case REGULATOR_MODE_FAST: - max8649_set_bits(info->i2c, info->vol_reg, MAX8649_FORCE_PWM, - MAX8649_FORCE_PWM); + regmap_update_bits(info->regmap, info->vol_reg, MAX8649_FORCE_PWM, + MAX8649_FORCE_PWM); break; case REGULATOR_MODE_NORMAL: - max8649_set_bits(info->i2c, info->vol_reg, - MAX8649_FORCE_PWM, 0); + regmap_update_bits(info->regmap, info->vol_reg, + MAX8649_FORCE_PWM, 0); break; default: return -EINVAL; @@ -246,10 +184,13 @@ static int max8649_set_mode(struct regulator_dev *rdev, unsigned int mode) static unsigned int max8649_get_mode(struct regulator_dev *rdev) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); + unsigned int val; int ret; - ret = max8649_reg_read(info->i2c, info->vol_reg); - if (ret & MAX8649_FORCE_PWM) + ret = regmap_read(info->regmap, info->vol_reg, &val); + if (ret != 0) + return ret; + if (val & MAX8649_FORCE_PWM) return REGULATOR_MODE_FAST; return REGULATOR_MODE_NORMAL; } @@ -275,11 +216,17 @@ static struct regulator_desc dcdc_desc = { .owner = THIS_MODULE, }; +static struct regmap_config max8649_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + static int __devinit max8649_regulator_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max8649_platform_data *pdata = client->dev.platform_data; struct max8649_regulator_info *info = NULL; + unsigned int val; unsigned char data; int ret; @@ -289,9 +236,14 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, return -ENOMEM; } - info->i2c = client; + info->regmap = regmap_init_i2c(client, &max8649_regmap_config); + if (IS_ERR(info->regmap)) { + ret = PTR_ERR(info->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); + goto fail; + } + info->dev = &client->dev; - mutex_init(&info->io_lock); i2c_set_clientdata(client, info); info->mode = pdata->mode; @@ -312,8 +264,8 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, break; } - ret = max8649_reg_read(info->i2c, MAX8649_CHIP_ID1); - if (ret < 0) { + ret = regmap_read(info->regmap, MAX8649_CHIP_ID1, &val); + if (ret != 0) { dev_err(info->dev, "Failed to detect ID of MAX8649:%d\n", ret); goto out; @@ -321,33 +273,33 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, dev_info(info->dev, "Detected MAX8649 (ID:%x)\n", ret); /* enable VID0 & VID1 */ - max8649_set_bits(info->i2c, MAX8649_CONTROL, MAX8649_VID_MASK, 0); + regmap_update_bits(info->regmap, MAX8649_CONTROL, MAX8649_VID_MASK, 0); /* enable/disable external clock synchronization */ info->extclk = pdata->extclk; data = (info->extclk) ? MAX8649_SYNC_EXTCLK : 0; - max8649_set_bits(info->i2c, info->vol_reg, MAX8649_SYNC_EXTCLK, data); + regmap_update_bits(info->regmap, info->vol_reg, MAX8649_SYNC_EXTCLK, data); if (info->extclk) { /* set external clock frequency */ info->extclk_freq = pdata->extclk_freq; - max8649_set_bits(info->i2c, MAX8649_SYNC, MAX8649_EXT_MASK, - info->extclk_freq << 6); + regmap_update_bits(info->regmap, MAX8649_SYNC, MAX8649_EXT_MASK, + info->extclk_freq << 6); } if (pdata->ramp_timing) { info->ramp_timing = pdata->ramp_timing; - max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_MASK, - info->ramp_timing << 5); + regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_MASK, + info->ramp_timing << 5); } info->ramp_down = pdata->ramp_down; if (info->ramp_down) { - max8649_set_bits(info->i2c, MAX8649_RAMP, MAX8649_RAMP_DOWN, - MAX8649_RAMP_DOWN); + regmap_update_bits(info->regmap, MAX8649_RAMP, MAX8649_RAMP_DOWN, + MAX8649_RAMP_DOWN); } info->regulator = regulator_register(&dcdc_desc, &client->dev, - pdata->regulator, info); + pdata->regulator, info, NULL); if (IS_ERR(info->regulator)) { dev_err(info->dev, "failed to register regulator %s\n", dcdc_desc.name); @@ -358,6 +310,8 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client, dev_info(info->dev, "Max8649 regulator device is detected.\n"); return 0; out: + regmap_exit(info->regmap); +fail: kfree(info); return ret; } @@ -369,6 +323,7 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client) if (info) { if (info->regulator) regulator_unregister(info->regulator); + regmap_exit(info->regmap); kfree(info); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 33f5d9a492ef..a838e664569f 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -449,7 +449,7 @@ static int __devinit max8660_probe(struct i2c_client *client, rdev[i] = regulator_register(&max8660_reg[id], &client->dev, pdata->subdevs[i].platform_data, - max8660); + max8660, NULL); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(&client->dev, "failed to register %s\n", diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index cc9ec0e03271..cc290d37c463 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -24,9 +24,13 @@ #define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ #define SD1_DVM_EN 6 /* SDV1 bit 6 */ -/* bit definitions in SD & LDO control registers */ -#define OUT_ENABLE 0x1f /* Power U/D sequence as I2C */ -#define OUT_DISABLE 0x1e /* Power U/D sequence as I2C */ +/* bit definitions in LDO control registers */ +#define LDO_SEQ_I2C 0x7 /* Power U/D by i2c */ +#define LDO_SEQ_MASK 0x7 /* Power U/D sequence mask */ +#define LDO_SEQ_SHIFT 2 /* Power U/D sequence offset */ +#define LDO_I2C_EN 0x1 /* Enable by i2c */ +#define LDO_I2C_EN_MASK 0x1 /* Enable mask by i2c */ +#define LDO_I2C_EN_SHIFT 0 /* Enable offset by i2c */ struct max8925_regulator_info { struct regulator_desc desc; @@ -40,7 +44,6 @@ struct max8925_regulator_info { int vol_reg; int vol_shift; int vol_nbits; - int enable_bit; int enable_reg; }; @@ -98,8 +101,10 @@ static int max8925_enable(struct regulator_dev *rdev) struct max8925_regulator_info *info = rdev_get_drvdata(rdev); return max8925_set_bits(info->i2c, info->enable_reg, - OUT_ENABLE << info->enable_bit, - OUT_ENABLE << info->enable_bit); + LDO_SEQ_MASK << LDO_SEQ_SHIFT | + LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT, + LDO_SEQ_I2C << LDO_SEQ_SHIFT | + LDO_I2C_EN << LDO_I2C_EN_SHIFT); } static int max8925_disable(struct regulator_dev *rdev) @@ -107,20 +112,24 @@ static int max8925_disable(struct regulator_dev *rdev) struct max8925_regulator_info *info = rdev_get_drvdata(rdev); return max8925_set_bits(info->i2c, info->enable_reg, - OUT_ENABLE << info->enable_bit, - OUT_DISABLE << info->enable_bit); + LDO_SEQ_MASK << LDO_SEQ_SHIFT | + LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT, + LDO_SEQ_I2C << LDO_SEQ_SHIFT); } static int max8925_is_enabled(struct regulator_dev *rdev) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); - int ret; + int ldo_seq, ret; ret = max8925_reg_read(info->i2c, info->enable_reg); if (ret < 0) return ret; - - return ret & (1 << info->enable_bit); + ldo_seq = (ret >> LDO_SEQ_SHIFT) & LDO_SEQ_MASK; + if (ldo_seq != LDO_SEQ_I2C) + return 1; + else + return ret & (LDO_I2C_EN_MASK << LDO_I2C_EN_SHIFT); } static int max8925_set_dvm_voltage(struct regulator_dev *rdev, int uV) @@ -188,7 +197,6 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .vol_shift = 0, \ .vol_nbits = 6, \ .enable_reg = MAX8925_SDCTL##_id, \ - .enable_bit = 0, \ } #define MAX8925_LDO(_id, min, max, step) \ @@ -207,7 +215,6 @@ static struct regulator_ops max8925_regulator_ldo_ops = { .vol_shift = 0, \ .vol_nbits = 6, \ .enable_reg = MAX8925_LDOCTL##_id, \ - .enable_bit = 0, \ } static struct max8925_regulator_info max8925_regulator_info[] = { @@ -266,7 +273,7 @@ static int __devinit max8925_regulator_probe(struct platform_device *pdev) ri->chip = chip; rdev = regulator_register(&ri->desc, &pdev->dev, - pdata->regulator[pdev->id], ri); + pdata->regulator[pdev->id], ri, NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 3883d85c5b88..75d89400c123 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -208,7 +208,7 @@ static int __devinit max8952_pmic_probe(struct i2c_client *client, max8952->pdata = pdata; max8952->rdev = regulator_register(®ulator, max8952->dev, - &pdata->reg_data, max8952); + &pdata->reg_data, max8952, NULL); if (IS_ERR(max8952->rdev)) { ret = PTR_ERR(max8952->rdev); diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c index 6176129a27e5..d26e8646277b 100644 --- a/drivers/regulator/max8997.c +++ b/drivers/regulator/max8997.c @@ -1146,7 +1146,7 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev) regulators[id].n_voltages = 16; rdev[i] = regulator_register(®ulators[id], max8997->dev, - pdata->regulators[i].initdata, max8997); + pdata->regulators[i].initdata, max8997, NULL); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(max8997->dev, "regulator init failed for %d\n", diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 41a1495eec2b..2d38c2493a07 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -847,7 +847,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) regulators[index].n_voltages = count; } rdev[i] = regulator_register(®ulators[index], max8998->dev, - pdata->regulators[i].initdata, max8998); + pdata->regulators[i].initdata, max8998, NULL); if (IS_ERR(rdev[i])) { ret = PTR_ERR(rdev[i]); dev_err(max8998->dev, "regulator init failed\n"); diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 8479082e1aea..8e9b90ad88ae 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -344,7 +344,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id); - priv = kzalloc(sizeof(*priv) + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + pdata->num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); if (!priv) @@ -357,7 +357,7 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) init_data = &pdata->regulators[i]; priv->regulators[i] = regulator_register( &mc13783_regulators[init_data->id].desc, - &pdev->dev, init_data->init_data, priv); + &pdev->dev, init_data->init_data, priv, NULL); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -374,8 +374,6 @@ err: while (--i >= 0) regulator_unregister(priv->regulators[i]); - kfree(priv); - return ret; } @@ -391,7 +389,6 @@ static int __devexit mc13783_regulator_remove(struct platform_device *pdev) for (i = 0; i < pdata->num_regulators; i++) regulator_unregister(priv->regulators[i]); - kfree(priv); return 0; } diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 023d17d022cf..e8cfc99dd8f0 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -527,18 +527,27 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); struct mc13xxx_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct mc13xxx_regulator_init_data *init_data; + struct mc13xxx_regulator_init_data *mc13xxx_data; int i, ret; + int num_regulators = 0; u32 val; - priv = kzalloc(sizeof(*priv) + - pdata->num_regulators * sizeof(priv->regulators[0]), + num_regulators = mc13xxx_get_num_regulators_dt(pdev); + if (num_regulators <= 0 && pdata) + num_regulators = pdata->num_regulators; + if (num_regulators <= 0) + return -EINVAL; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + + num_regulators * sizeof(priv->regulators[0]), GFP_KERNEL); if (!priv) return -ENOMEM; + priv->num_regulators = num_regulators; priv->mc13xxx_regulators = mc13892_regulators; priv->mc13xxx = mc13892; + platform_set_drvdata(pdev, priv); mc13xxx_lock(mc13892); ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); @@ -569,11 +578,27 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) = mc13892_vcam_set_mode; mc13892_regulators[MC13892_VCAM].desc.ops->get_mode = mc13892_vcam_get_mode; - for (i = 0; i < pdata->num_regulators; i++) { - init_data = &pdata->regulators[i]; + + mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, + ARRAY_SIZE(mc13892_regulators)); + for (i = 0; i < num_regulators; i++) { + struct regulator_init_data *init_data; + struct regulator_desc *desc; + struct device_node *node = NULL; + int id; + + if (mc13xxx_data) { + id = mc13xxx_data[i].id; + init_data = mc13xxx_data[i].init_data; + node = mc13xxx_data[i].node; + } else { + id = pdata->regulators[i].id; + init_data = pdata->regulators[i].init_data; + } + desc = &mc13892_regulators[id].desc; + priv->regulators[i] = regulator_register( - &mc13892_regulators[init_data->id].desc, - &pdev->dev, init_data->init_data, priv); + desc, &pdev->dev, init_data, priv, node); if (IS_ERR(priv->regulators[i])) { dev_err(&pdev->dev, "failed to register regulator %s\n", @@ -583,8 +608,6 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, priv); - return 0; err: while (--i >= 0) @@ -592,7 +615,6 @@ err: err_free: mc13xxx_unlock(mc13892); - kfree(priv); return ret; } @@ -600,16 +622,13 @@ err_free: static int __devexit mc13892_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13xxx_regulator_platform_data *pdata = - dev_get_platdata(&pdev->dev); int i; platform_set_drvdata(pdev, NULL); - for (i = 0; i < pdata->num_regulators; i++) + for (i = 0; i < priv->num_regulators; i++) regulator_unregister(priv->regulators[i]); - kfree(priv); return 0; } diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 6532853a6ef5..80ecafef1bc3 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -18,12 +18,14 @@ #include <linux/mfd/mc13xxx.h> #include <linux/regulator/machine.h> #include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> #include <linux/platform_device.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/err.h> #include <linux/module.h> +#include <linux/of.h> #include "mc13xxx.h" static int mc13xxx_regulator_enable(struct regulator_dev *rdev) @@ -236,6 +238,61 @@ int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) } EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled); +#ifdef CONFIG_OF +int __devinit mc13xxx_get_num_regulators_dt(struct platform_device *pdev) +{ + struct device_node *parent, *child; + int num = 0; + + of_node_get(pdev->dev.parent->of_node); + parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + if (!parent) + return -ENODEV; + + for_each_child_of_node(parent, child) + num++; + + return num; +} + +struct mc13xxx_regulator_init_data * __devinit mc13xxx_parse_regulators_dt( + struct platform_device *pdev, struct mc13xxx_regulator *regulators, + int num_regulators) +{ + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_init_data *data, *p; + struct device_node *parent, *child; + int i; + + of_node_get(pdev->dev.parent->of_node); + parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); + if (!parent) + return NULL; + + data = devm_kzalloc(&pdev->dev, sizeof(*data) * priv->num_regulators, + GFP_KERNEL); + if (!data) + return NULL; + p = data; + + for_each_child_of_node(parent, child) { + for (i = 0; i < num_regulators; i++) { + if (!of_node_cmp(child->name, + regulators[i].desc.name)) { + p->id = i; + p->init_data = of_get_regulator_init_data( + &pdev->dev, child); + p->node = child; + p++; + break; + } + } + } + + return data; +} +#endif + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yong Shen <yong.shen@linaro.org>"); MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC"); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h index 27758267e122..b3961c658b05 100644 --- a/drivers/regulator/mc13xxx.h +++ b/drivers/regulator/mc13xxx.h @@ -29,6 +29,7 @@ struct mc13xxx_regulator_priv { struct mc13xxx *mc13xxx; u32 powermisc_pwgt_state; struct mc13xxx_regulator *mc13xxx_regulators; + int num_regulators; struct regulator_dev *regulators[]; }; @@ -42,13 +43,32 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector); extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); +#ifdef CONFIG_OF +extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); +extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( + struct platform_device *pdev, struct mc13xxx_regulator *regulators, + int num_regulators); +#else +static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) +{ + return -ENODEV; +} + +static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( + struct platform_device *pdev, struct mc13xxx_regulator *regulators, + int num_regulators) +{ + return NULL; +} +#endif + extern struct regulator_ops mc13xxx_regulator_ops; extern struct regulator_ops mc13xxx_fixed_regulator_ops; #define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #prefix "_" #_name, \ + .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -66,7 +86,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; #define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #prefix "_" #_name, \ + .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ @@ -81,7 +101,7 @@ extern struct regulator_ops mc13xxx_fixed_regulator_ops; #define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ [prefix ## _name] = { \ .desc = { \ - .name = #prefix "_" #_name, \ + .name = #_name, \ .n_voltages = ARRAY_SIZE(_voltages), \ .ops = &_ops, \ .type = REGULATOR_VOLTAGE, \ diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c new file mode 100644 index 000000000000..f1651eb69648 --- /dev/null +++ b/drivers/regulator/of_regulator.c @@ -0,0 +1,87 @@ +/* + * OF helpers for regulator framework + * + * Copyright (C) 2011 Texas Instruments, Inc. + * Rajendra Nayak <rnayak@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/regulator/machine.h> + +static void of_get_regulation_constraints(struct device_node *np, + struct regulator_init_data **init_data) +{ + const __be32 *min_uV, *max_uV, *uV_offset; + const __be32 *min_uA, *max_uA; + struct regulation_constraints *constraints = &(*init_data)->constraints; + + constraints->name = of_get_property(np, "regulator-name", NULL); + + min_uV = of_get_property(np, "regulator-min-microvolt", NULL); + if (min_uV) + constraints->min_uV = be32_to_cpu(*min_uV); + max_uV = of_get_property(np, "regulator-max-microvolt", NULL); + if (max_uV) + constraints->max_uV = be32_to_cpu(*max_uV); + + /* Voltage change possible? */ + if (constraints->min_uV != constraints->max_uV) + constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; + /* Only one voltage? Then make sure it's set. */ + if (constraints->min_uV == constraints->max_uV) + constraints->apply_uV = true; + + uV_offset = of_get_property(np, "regulator-microvolt-offset", NULL); + if (uV_offset) + constraints->uV_offset = be32_to_cpu(*uV_offset); + min_uA = of_get_property(np, "regulator-min-microamp", NULL); + if (min_uA) + constraints->min_uA = be32_to_cpu(*min_uA); + max_uA = of_get_property(np, "regulator-max-microamp", NULL); + if (max_uA) + constraints->max_uA = be32_to_cpu(*max_uA); + + /* Current change possible? */ + if (constraints->min_uA != constraints->max_uA) + constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; + + if (of_find_property(np, "regulator-boot-on", NULL)) + constraints->boot_on = true; + + if (of_find_property(np, "regulator-always-on", NULL)) + constraints->always_on = true; + else /* status change should be possible if not always on. */ + constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; +} + +/** + * of_get_regulator_init_data - extract regulator_init_data structure info + * @dev: device requesting for regulator_init_data + * + * Populates regulator_init_data structure by extracting data from device + * tree node, returns a pointer to the populated struture or NULL if memory + * alloc fails. + */ +struct regulator_init_data *of_get_regulator_init_data(struct device *dev, + struct device_node *node) +{ + struct regulator_init_data *init_data; + + if (!node) + return NULL; + + init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL); + if (!init_data) + return NULL; /* Out of memory? */ + + of_get_regulation_constraints(node, &init_data); + return init_data; +} +EXPORT_SYMBOL_GPL(of_get_regulator_init_data); diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 31f6e11a7f16..a5aab1b08bcf 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -277,7 +277,7 @@ static int __devinit pcap_regulator_probe(struct platform_device *pdev) void *pcap = dev_get_drvdata(pdev->dev.parent); rdev = regulator_register(&pcap_regulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pcap); + pdev->dev.platform_data, pcap, NULL); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 69a11d9dd87f..1d1c31056297 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -320,7 +320,7 @@ static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) pcf = dev_to_pcf50633(pdev->dev.parent); rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, pcf); + pdev->dev.platform_data, pcf, NULL); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index 1011873896dc..d9278da18a9e 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -151,7 +151,8 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) /* Register regulator with framework */ tps6105x->regulator = regulator_register(&tps6105x_regulator_desc, &tps6105x->client->dev, - pdata->regulator_data, tps6105x); + pdata->regulator_data, tps6105x, + NULL); if (IS_ERR(tps6105x->regulator)) { ret = PTR_ERR(tps6105x->regulator); dev_err(&tps6105x->client->dev, diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index 9fb4c7b81753..18d61a0529a9 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -152,48 +152,21 @@ struct tps_driver_data { u8 core_regulator; }; -static int tps_65023_set_bits(struct tps_pmic *tps, u8 reg, u8 mask) -{ - return regmap_update_bits(tps->regmap, reg, mask, mask); -} - -static int tps_65023_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask) -{ - return regmap_update_bits(tps->regmap, reg, mask, 0); -} - -static int tps_65023_reg_read(struct tps_pmic *tps, u8 reg) -{ - unsigned int val; - int ret; - - ret = regmap_read(tps->regmap, reg, &val); - - if (ret != 0) - return ret; - else - return val; -} - -static int tps_65023_reg_write(struct tps_pmic *tps, u8 reg, u8 val) -{ - return regmap_write(tps->regmap, reg, val); -} - static int tps65023_dcdc_is_enabled(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, dcdc = rdev_get_id(dev); + int ret; u8 shift; if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) return -EINVAL; shift = TPS65023_NUM_REGULATOR - dcdc; - data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); + ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data); - if (data < 0) - return data; + if (ret != 0) + return ret; else return (data & 1<<shift) ? 1 : 0; } @@ -202,16 +175,17 @@ static int tps65023_ldo_is_enabled(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, ldo = rdev_get_id(dev); + int ret; u8 shift; if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) return -EINVAL; shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - data = tps_65023_reg_read(tps, TPS65023_REG_REG_CTRL); + ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data); - if (data < 0) - return data; + if (ret != 0) + return ret; else return (data & 1<<shift) ? 1 : 0; } @@ -226,7 +200,7 @@ static int tps65023_dcdc_enable(struct regulator_dev *dev) return -EINVAL; shift = TPS65023_NUM_REGULATOR - dcdc; - return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); + return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift); } static int tps65023_dcdc_disable(struct regulator_dev *dev) @@ -239,7 +213,7 @@ static int tps65023_dcdc_disable(struct regulator_dev *dev) return -EINVAL; shift = TPS65023_NUM_REGULATOR - dcdc; - return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); + return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0); } static int tps65023_ldo_enable(struct regulator_dev *dev) @@ -252,7 +226,7 @@ static int tps65023_ldo_enable(struct regulator_dev *dev) return -EINVAL; shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - return tps_65023_set_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); + return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift); } static int tps65023_ldo_disable(struct regulator_dev *dev) @@ -265,21 +239,22 @@ static int tps65023_ldo_disable(struct regulator_dev *dev) return -EINVAL; shift = (ldo == TPS65023_LDO_1 ? 1 : 2); - return tps_65023_clear_bits(tps, TPS65023_REG_REG_CTRL, 1 << shift); + return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0); } static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); + int ret; int data, dcdc = rdev_get_id(dev); if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3) return -EINVAL; if (dcdc == tps->core_regulator) { - data = tps_65023_reg_read(tps, TPS65023_REG_DEF_CORE); - if (data < 0) - return data; + ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data); + if (ret != 0) + return ret; data &= (tps->info[dcdc]->table_len - 1); return tps->info[dcdc]->table[data] * 1000; } else @@ -318,13 +293,13 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[dcdc]->table_len) goto failed; - ret = tps_65023_reg_write(tps, TPS65023_REG_DEF_CORE, vsel); + ret = regmap_write(tps->regmap, 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); + regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, + TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO); return ret; @@ -336,13 +311,14 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, ldo = rdev_get_id(dev); + int ret; if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) return -EINVAL; - data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); - if (data < 0) - return data; + ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data); + if (ret != 0) + return ret; data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)); data &= (tps->info[ldo]->table_len - 1); @@ -354,6 +330,7 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev, { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); + int ret; if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2) return -EINVAL; @@ -377,13 +354,13 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev, *selector = vsel; - data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); - if (data < 0) - return data; + ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data); + if (ret != 0) + return ret; data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1); data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1))); - return tps_65023_reg_write(tps, TPS65023_REG_LDO_CTRL, data); + return regmap_write(tps->regmap, TPS65023_REG_LDO_CTRL, data); } static int tps65023_dcdc_list_voltage(struct regulator_dev *dev, @@ -496,7 +473,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client, /* Register the regulators */ rdev = regulator_register(&tps->desc[i], &client->dev, - init_data, tps); + init_data, tps, NULL); if (IS_ERR(rdev)) { dev_err(&client->dev, "failed to register %s\n", id->name); @@ -511,12 +488,12 @@ 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); + regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, + TPS65023_REG_CTRL2_CORE_ADJ, 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); + regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2, + TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ); return 0; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index bdef70365f52..0b63ef71a5fe 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -599,7 +599,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev) tps->desc[i].owner = THIS_MODULE; rdev = regulator_register(&tps->desc[i], - tps6507x_dev->dev, init_data, tps); + tps6507x_dev->dev, init_data, tps, NULL); if (IS_ERR(rdev)) { dev_err(tps6507x_dev->dev, "failed to register %s regulator\n", diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c index 9166aa0a9df7..70b7b1f4f000 100644 --- a/drivers/regulator/tps6524x-regulator.c +++ b/drivers/regulator/tps6524x-regulator.c @@ -651,7 +651,7 @@ static int __devinit pmic_probe(struct spi_device *spi) hw->desc[i].n_voltages = 1; hw->rdev[i] = regulator_register(&hw->desc[i], dev, - init_data, hw); + init_data, hw, NULL); if (IS_ERR(hw->rdev[i])) { ret = PTR_ERR(hw->rdev[i]); hw->rdev[i] = NULL; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 14b9389dd52a..c75fb20faa57 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -396,7 +396,7 @@ static int __devinit tps6586x_regulator_probe(struct platform_device *pdev) return err; rdev = regulator_register(&ri->desc, &pdev->dev, - pdev->dev.platform_data, ri); + pdev->dev.platform_data, ri, NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc.name); diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index b552aae55b41..5c15ba01e9c7 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -25,30 +25,6 @@ #include <linux/gpio.h> #include <linux/mfd/tps65910.h> -#define TPS65910_REG_VRTC 0 -#define TPS65910_REG_VIO 1 -#define TPS65910_REG_VDD1 2 -#define TPS65910_REG_VDD2 3 -#define TPS65910_REG_VDD3 4 -#define TPS65910_REG_VDIG1 5 -#define TPS65910_REG_VDIG2 6 -#define TPS65910_REG_VPLL 7 -#define TPS65910_REG_VDAC 8 -#define TPS65910_REG_VAUX1 9 -#define TPS65910_REG_VAUX2 10 -#define TPS65910_REG_VAUX33 11 -#define TPS65910_REG_VMMC 12 - -#define TPS65911_REG_VDDCTRL 4 -#define TPS65911_REG_LDO1 5 -#define TPS65911_REG_LDO2 6 -#define TPS65911_REG_LDO3 7 -#define TPS65911_REG_LDO4 8 -#define TPS65911_REG_LDO5 9 -#define TPS65911_REG_LDO6 10 -#define TPS65911_REG_LDO7 11 -#define TPS65911_REG_LDO8 12 - #define TPS65910_SUPPLY_STATE_ENABLED 0x1 /* supported VIO voltages in milivolts */ @@ -885,8 +861,6 @@ static __devinit int tps65910_probe(struct platform_device *pdev) if (!pmic_plat_data) return -EINVAL; - reg_data = pmic_plat_data->tps65910_pmic_init_data; - pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); if (!pmic) return -ENOMEM; @@ -937,7 +911,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) goto err_free_info; } - for (i = 0; i < pmic->num_regulators; i++, info++, reg_data++) { + for (i = 0; i < pmic->num_regulators && i < TPS65910_NUM_REGS; + i++, info++) { + + reg_data = pmic_plat_data->tps65910_pmic_init_data[i]; + + /* Regulator API handles empty constraints but not NULL + * constraints */ + if (!reg_data) + continue; + /* Register the regulators */ pmic->info[i] = info; @@ -965,7 +948,7 @@ static __devinit int tps65910_probe(struct platform_device *pdev) pmic->desc[i].owner = THIS_MODULE; rdev = regulator_register(&pmic->desc[i], - tps65910->dev, reg_data, pmic); + tps65910->dev, reg_data, pmic, NULL); if (IS_ERR(rdev)) { dev_err(tps65910->dev, "failed to register %s regulator\n", diff --git a/drivers/regulator/tps65912-regulator.c b/drivers/regulator/tps65912-regulator.c index 39d4a1749e71..da00d88f94b7 100644 --- a/drivers/regulator/tps65912-regulator.c +++ b/drivers/regulator/tps65912-regulator.c @@ -727,7 +727,7 @@ static __devinit int tps65912_probe(struct platform_device *pdev) pmic->desc[i].owner = THIS_MODULE; range = tps65912_get_range(pmic, i); rdev = regulator_register(&pmic->desc[i], - tps65912->dev, reg_data, pmic); + tps65912->dev, reg_data, pmic, NULL); if (IS_ERR(rdev)) { dev_err(tps65912->dev, "failed to register %s regulator\n", diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 11cc308d66e9..181a2cfe180c 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -1112,7 +1112,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev) break; } - rdev = regulator_register(&info->desc, &pdev->dev, initdata, info); + rdev = regulator_register(&info->desc, &pdev->dev, initdata, info, NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "can't register %s, %ld\n", info->desc.name, PTR_ERR(rdev)); diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index fc6655146999..518667ef9a0d 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -185,18 +185,7 @@ static struct platform_driver regulator_userspace_consumer_driver = { }, }; - -static int __init regulator_userspace_consumer_init(void) -{ - return platform_driver_register(®ulator_userspace_consumer_driver); -} -module_init(regulator_userspace_consumer_init); - -static void __exit regulator_userspace_consumer_exit(void) -{ - platform_driver_unregister(®ulator_userspace_consumer_driver); -} -module_exit(regulator_userspace_consumer_exit); +module_platform_driver(regulator_userspace_consumer_driver); MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); MODULE_DESCRIPTION("Userspace consumer for voltage and current regulators"); diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index 858c1f861ba5..ee0b161c998f 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -352,17 +352,7 @@ static struct platform_driver regulator_virtual_consumer_driver = { }, }; -static int __init regulator_virtual_consumer_init(void) -{ - return platform_driver_register(®ulator_virtual_consumer_driver); -} -module_init(regulator_virtual_consumer_init); - -static void __exit regulator_virtual_consumer_exit(void) -{ - platform_driver_unregister(®ulator_virtual_consumer_driver); -} -module_exit(regulator_virtual_consumer_exit); +module_platform_driver(regulator_virtual_consumer_driver); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("Virtual regulator consumer"); diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index bd3531d8b2ac..4904a40b0d46 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -511,7 +511,8 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) if (pdata == NULL || pdata->dcdc[id] == NULL) return -ENODEV; - dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL); + dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), + GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -553,7 +554,7 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) wm831x_buckv_dvs_init(dcdc, pdata->dcdc[id]->driver_data); dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc); + pdata->dcdc[id], dcdc, NULL); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -590,7 +591,6 @@ err_regulator: err: if (dcdc->dvs_gpio) gpio_free(dcdc->dvs_gpio); - kfree(dcdc); return ret; } @@ -605,7 +605,6 @@ static __devexit int wm831x_buckv_remove(struct platform_device *pdev) regulator_unregister(dcdc->regulator); if (dcdc->dvs_gpio) gpio_free(dcdc->dvs_gpio); - kfree(dcdc); return 0; } @@ -722,7 +721,8 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) if (pdata == NULL || pdata->dcdc[id] == NULL) return -ENODEV; - dcdc = kzalloc(sizeof(struct wm831x_dcdc), GFP_KERNEL); + dcdc = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_dcdc), + GFP_KERNEL); if (dcdc == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -747,7 +747,7 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) dcdc->desc.owner = THIS_MODULE; dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc); + pdata->dcdc[id], dcdc, NULL); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -771,7 +771,6 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) err_regulator: regulator_unregister(dcdc->regulator); err: - kfree(dcdc); return ret; } @@ -783,7 +782,6 @@ static __devexit int wm831x_buckp_remove(struct platform_device *pdev) free_irq(platform_get_irq_byname(pdev, "UV"), dcdc); regulator_unregister(dcdc->regulator); - kfree(dcdc); return 0; } @@ -874,7 +872,7 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) dcdc->desc.owner = THIS_MODULE; dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->dcdc[id], dcdc); + pdata->dcdc[id], dcdc, NULL); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register DCDC%d: %d\n", @@ -973,7 +971,7 @@ static __devinit int wm831x_epe_probe(struct platform_device *pdev) dcdc->desc.owner = THIS_MODULE; dcdc->regulator = regulator_register(&dcdc->desc, &pdev->dev, - pdata->epe[id], dcdc); + pdata->epe[id], dcdc, NULL); if (IS_ERR(dcdc->regulator)) { ret = PTR_ERR(dcdc->regulator); dev_err(wm831x->dev, "Failed to register EPE%d: %d\n", diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 01f27c7f4236..634aac3f2d5f 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -162,7 +162,8 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) if (pdata == NULL || pdata->isink[id] == NULL) return -ENODEV; - isink = kzalloc(sizeof(struct wm831x_isink), GFP_KERNEL); + isink = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_isink), + GFP_KERNEL); if (isink == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -189,7 +190,7 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) isink->desc.owner = THIS_MODULE; isink->regulator = regulator_register(&isink->desc, &pdev->dev, - pdata->isink[id], isink); + pdata->isink[id], isink, NULL); if (IS_ERR(isink->regulator)) { ret = PTR_ERR(isink->regulator); dev_err(wm831x->dev, "Failed to register ISINK%d: %d\n", @@ -213,7 +214,6 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) err_regulator: regulator_unregister(isink->regulator); err: - kfree(isink); return ret; } @@ -226,7 +226,6 @@ static __devexit int wm831x_isink_remove(struct platform_device *pdev) free_irq(platform_get_irq(pdev, 0), isink); regulator_unregister(isink->regulator); - kfree(isink); return 0; } diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 6709710a059e..f1e4ab0f9fda 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -326,7 +326,7 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; - ldo = kzalloc(sizeof(struct wm831x_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -351,7 +351,7 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->desc.owner = THIS_MODULE; ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo); + pdata->ldo[id], ldo, NULL); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -376,7 +376,6 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) err_regulator: regulator_unregister(ldo->regulator); err: - kfree(ldo); return ret; } @@ -388,7 +387,6 @@ static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev) free_irq(platform_get_irq_byname(pdev, "UV"), ldo); regulator_unregister(ldo->regulator); - kfree(ldo); return 0; } @@ -596,7 +594,7 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; - ldo = kzalloc(sizeof(struct wm831x_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -621,7 +619,7 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) ldo->desc.owner = THIS_MODULE; ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo); + pdata->ldo[id], ldo, NULL); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -645,7 +643,6 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) err_regulator: regulator_unregister(ldo->regulator); err: - kfree(ldo); return ret; } @@ -655,7 +652,6 @@ static __devexit int wm831x_aldo_remove(struct platform_device *pdev) free_irq(platform_get_irq_byname(pdev, "UV"), ldo); regulator_unregister(ldo->regulator); - kfree(ldo); return 0; } @@ -793,7 +789,7 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) if (pdata == NULL || pdata->ldo[id] == NULL) return -ENODEV; - ldo = kzalloc(sizeof(struct wm831x_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL); if (ldo == NULL) { dev_err(&pdev->dev, "Unable to allocate private data\n"); return -ENOMEM; @@ -818,7 +814,7 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) ldo->desc.owner = THIS_MODULE; ldo->regulator = regulator_register(&ldo->desc, &pdev->dev, - pdata->ldo[id], ldo); + pdata->ldo[id], ldo, NULL); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm831x->dev, "Failed to register LDO%d: %d\n", @@ -831,7 +827,6 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) return 0; err: - kfree(ldo); return ret; } @@ -840,7 +835,6 @@ static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev) struct wm831x_ldo *ldo = platform_get_drvdata(pdev); regulator_unregister(ldo->regulator); - kfree(ldo); return 0; } diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 1bcb22c44095..6894009d815a 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1428,7 +1428,7 @@ static int wm8350_regulator_probe(struct platform_device *pdev) /* register regulator */ rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev, pdev->dev.platform_data, - dev_get_drvdata(&pdev->dev)); + dev_get_drvdata(&pdev->dev), NULL); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register %s\n", wm8350_reg[pdev->id].name); diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 71632ddc3781..706f39563a7b 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -326,7 +326,7 @@ static int __devinit wm8400_regulator_probe(struct platform_device *pdev) struct regulator_dev *rdev; rdev = regulator_register(®ulators[pdev->id], &pdev->dev, - pdev->dev.platform_data, wm8400); + pdev->dev.platform_data, wm8400, NULL); if (IS_ERR(rdev)) return PTR_ERR(rdev); diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index b87bf5c841f8..435e335d6e67 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -269,7 +269,7 @@ static __devinit int wm8994_ldo_probe(struct platform_device *pdev) ldo->is_enabled = true; ldo->regulator = regulator_register(&wm8994_ldo_desc[id], &pdev->dev, - pdata->ldo[id].init_data, ldo); + pdata->ldo[id].init_data, ldo, NULL); if (IS_ERR(ldo->regulator)) { ret = PTR_ERR(ldo->regulator); dev_err(wm8994->dev, "Failed to register LDO%d: %d\n", diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h index 3816c2fac0ad..a98e2a316d1f 100644 --- a/include/linux/mfd/mc13xxx.h +++ b/include/linux/mfd/mc13xxx.h @@ -69,6 +69,7 @@ struct regulator_init_data; struct mc13xxx_regulator_init_data { int id; struct regulator_init_data *init_data; + struct device_node *node; }; struct mc13xxx_regulator_platform_data { diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index 8bf2cb9502dd..d0cb12eba402 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h @@ -740,6 +740,34 @@ #define TPS65910_GPIO_STS BIT(1) #define TPS65910_GPIO_SET BIT(0) +/* Regulator Index Definitions */ +#define TPS65910_REG_VRTC 0 +#define TPS65910_REG_VIO 1 +#define TPS65910_REG_VDD1 2 +#define TPS65910_REG_VDD2 3 +#define TPS65910_REG_VDD3 4 +#define TPS65910_REG_VDIG1 5 +#define TPS65910_REG_VDIG2 6 +#define TPS65910_REG_VPLL 7 +#define TPS65910_REG_VDAC 8 +#define TPS65910_REG_VAUX1 9 +#define TPS65910_REG_VAUX2 10 +#define TPS65910_REG_VAUX33 11 +#define TPS65910_REG_VMMC 12 + +#define TPS65911_REG_VDDCTRL 4 +#define TPS65911_REG_LDO1 5 +#define TPS65911_REG_LDO2 6 +#define TPS65911_REG_LDO3 7 +#define TPS65911_REG_LDO4 8 +#define TPS65911_REG_LDO5 9 +#define TPS65911_REG_LDO6 10 +#define TPS65911_REG_LDO7 11 +#define TPS65911_REG_LDO8 12 + +/* Max number of TPS65910/11 regulators */ +#define TPS65910_NUM_REGS 13 + /** * struct tps65910_board * Board platform data may be used to initialize regulators. @@ -751,7 +779,7 @@ struct tps65910_board { int irq_base; int vmbch_threshold; int vmbch2_threshold; - struct regulator_init_data *tps65910_pmic_init_data; + struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; }; /** diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index f7756d146c61..f2698a0edfc4 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -149,6 +149,8 @@ int regulator_bulk_enable(int num_consumers, struct regulator_bulk_data *consumers); int regulator_bulk_disable(int num_consumers, struct regulator_bulk_data *consumers); +int regulator_bulk_force_disable(int num_consumers, + struct regulator_bulk_data *consumers); void regulator_bulk_free(int num_consumers, struct regulator_bulk_data *consumers); @@ -212,6 +214,11 @@ static inline int regulator_disable(struct regulator *regulator) return 0; } +static inline int regulator_force_disable(struct regulator *regulator) +{ + return 0; +} + static inline int regulator_disable_deferred(struct regulator *regulator, int ms) { @@ -242,6 +249,12 @@ static inline int regulator_bulk_disable(int num_consumers, return 0; } +static inline int regulator_bulk_force_disable(int num_consumers, + struct regulator_bulk_data *consumers) +{ + return 0; +} + static inline void regulator_bulk_free(int num_consumers, struct regulator_bulk_data *consumers) { diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 52c89ae32f64..4214b9a9d1c9 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -154,6 +154,7 @@ enum regulator_type { * this type. * * @name: Identifying name for the regulator. + * @supply_name: Identifying the regulator supply * @id: Numerical identifier for the regulator. * @n_voltages: Number of selectors available for ops.list_voltage(). * @ops: Regulator operations table. @@ -163,6 +164,7 @@ enum regulator_type { */ struct regulator_desc { const char *name; + const char *supply_name; int id; unsigned n_voltages; struct regulator_ops *ops; @@ -212,7 +214,7 @@ struct regulator_dev { struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, struct device *dev, const struct regulator_init_data *init_data, - void *driver_data); + void *driver_data, struct device_node *of_node); void regulator_unregister(struct regulator_dev *rdev); int regulator_notifier_call_chain(struct regulator_dev *rdev, diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h new file mode 100644 index 000000000000..769704f296e5 --- /dev/null +++ b/include/linux/regulator/of_regulator.h @@ -0,0 +1,22 @@ +/* + * OpenFirmware regulator support routines + * + */ + +#ifndef __LINUX_OF_REG_H +#define __LINUX_OF_REG_H + +#if defined(CONFIG_OF) +extern struct regulator_init_data + *of_get_regulator_init_data(struct device *dev, + struct device_node *node); +#else +static inline struct regulator_init_data + *of_get_regulator_init_data(struct device *dev, + struct device_node *node) +{ + return NULL; +} +#endif /* CONFIG_OF */ + +#endif /* __LINUX_OF_REG_H */ diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index bbcf921166f7..f6b6551940ab 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -833,7 +833,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec, ldo->voltage = voltage; ldo->dev = regulator_register(&ldo->desc, codec->dev, - init_data, ldo); + init_data, ldo, NULL); if (IS_ERR(ldo->dev)) { int ret = PTR_ERR(ldo->dev); |