From 272e2315fac3bfca0edfa3252b8a643c425602af Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Wed, 13 Aug 2014 19:33:38 +0800 Subject: regulator: core: add const qualifier to ops in struct regulator_desc struct regulator_ops *ops is a member in struct regulator_desc, which gets its value from individual regulator driver upon regulator_register() and is used by regulator core APIs. It's not allowed for regulator core to modify any of these callbacks in *ops. Add 'const' qualifier to enforce that. Signed-off-by: Guodong Xu Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bbe03a1924c0..4b628139a9cb 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -245,7 +245,7 @@ struct regulator_desc { int id; bool continuous_voltage_range; unsigned n_voltages; - struct regulator_ops *ops; + const struct regulator_ops *ops; int irq; enum regulator_type type; struct module *owner; -- cgit v1.2.3-71-gd317 From 871f565055ed232e5751da18a331b73e8254adaf Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Wed, 13 Aug 2014 19:33:40 +0800 Subject: regulator: core: add guard delay between calling regulator_disable and _enable Some regulator require a minimum delay between its disable and next enable. This is to avoid damages when out-of-range frequent disable/enable of a single regulator can bring to the regulator chip. Add @off_on_delay to struct regulator_desc. Device drivers' can use this field to set this guard time. Add @last_off_jiffy to struct regulator_dev. When @off_on_delay is set by driver, regulator core can store its last off (disable) time into this field. Signed-off-by: Guodong Xu Signed-off-by: Mark Brown --- drivers/regulator/core.c | 31 +++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 6 ++++++ 2 files changed, 37 insertions(+) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index dc0e9813b62d..1e976b6320a2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1813,6 +1813,31 @@ static int _regulator_do_enable(struct regulator_dev *rdev) trace_regulator_enable(rdev_get_name(rdev)); + if (rdev->desc->off_on_delay) { + /* if needed, keep a distance of off_on_delay from last time + * this regulator was disabled. + */ + unsigned long start_jiffy = jiffies; + unsigned long intended, max_delay, remaining; + + max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); + intended = rdev->last_off_jiffy + max_delay; + + if (time_before(start_jiffy, intended)) { + /* calc remaining jiffies to deal with one-time + * timer wrapping. + * in case of multiple timer wrapping, either it can be + * detected by out-of-range remaining, or it cannot be + * detected and we gets a panelty of + * _regulator_enable_delay(). + */ + remaining = intended - start_jiffy; + if (remaining <= max_delay) + _regulator_enable_delay( + jiffies_to_usecs(remaining)); + } + } + if (rdev->ena_pin) { ret = regulator_ena_gpio_ctrl(rdev, true); if (ret < 0) @@ -1925,6 +1950,12 @@ static int _regulator_do_disable(struct regulator_dev *rdev) return ret; } + /* cares about last_off_jiffy only if off_on_delay is required by + * device. + */ + if (rdev->desc->off_on_delay) + rdev->last_off_jiffy = jiffies; + trace_regulator_disable_complete(rdev_get_name(rdev)); return 0; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4b628139a9cb..efe058f8f746 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -238,6 +238,7 @@ enum regulator_type { * @bypass_val_off: Disabling value for control when using regmap set_bypass * * @enable_time: Time taken for initial enable of regulator (in uS). + * @off_on_delay: guard time (in uS), before re-enabling a regulator */ struct regulator_desc { const char *name; @@ -276,6 +277,8 @@ struct regulator_desc { unsigned int bypass_val_off; unsigned int enable_time; + + unsigned int off_on_delay; }; /** @@ -348,6 +351,9 @@ struct regulator_dev { struct regulator_enable_gpio *ena_pin; unsigned int ena_gpio_state:1; + + /* time when this regulator was disabled last time */ + unsigned long last_off_jiffy; }; struct regulator_dev * -- cgit v1.2.3-71-gd317 From 716845ebeb505353d900320b4a74e8330520410d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 18 Aug 2014 10:34:08 +0800 Subject: regulator: core: Fix build error due to const qualifier for ops Drop const qualifier for ops of struct regulator_desc. Allow regulator drivers to update ops before registering regulator. Fix below build error: CC [M] drivers/regulator/mc13892-regulator.o drivers/regulator/mc13892-regulator.c: In function 'mc13892_regulator_probe': drivers/regulator/mc13892-regulator.c:586:3: error: assignment of member 'set_mode' in read-only object drivers/regulator/mc13892-regulator.c:588:3: error: assignment of member 'get_mode' in read-only object make[2]: *** [drivers/regulator/mc13892-regulator.o] Error 1 make[1]: *** [drivers/regulator] Error 2 make: *** [drivers] Error 2 Reported-by: Stephen Rothwell Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index efe058f8f746..3abda7554d82 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -246,7 +246,7 @@ struct regulator_desc { int id; bool continuous_voltage_range; unsigned n_voltages; - const struct regulator_ops *ops; + struct regulator_ops *ops; int irq; enum regulator_type type; struct module *owner; -- cgit v1.2.3-71-gd317 From df11e506d330d9a0e5a701cd2c5fcb7d461b6060 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 21 Aug 2014 10:11:34 +0800 Subject: regulator: core: Add back the const qualifier for ops of struct regulator_desc Fix below build warning: CC [M] drivers/regulator/hi6421-regulator.o drivers/regulator/hi6421-regulator.c:356:2: warning: initialization discards 'const' qualifier from pointer target type [enabled by default] This is a revert of commit 716845ebeb50 ("regulator: core: Fix build error due to const qualifier for ops"). The build error was fixed by commit 39f5460d7f9c ("regulator: core: add const to regulator_ops and fix build error in mc13892"). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- include/linux/regulator/driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 3abda7554d82..efe058f8f746 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -246,7 +246,7 @@ struct regulator_desc { int id; bool continuous_voltage_range; unsigned n_voltages; - struct regulator_ops *ops; + const struct regulator_ops *ops; int irq; enum regulator_type type; struct module *owner; -- cgit v1.2.3-71-gd317 From dec38b5ce6a9edb406c60c2670b26a1a4262fdb9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 6 Sep 2014 01:11:12 +0100 Subject: regulator: isl9305: Add Intersil ISL9305/H driver The ISL9305 and ISL9305H are mini-PMICs offering two DCDC regulators and two LDO regulators. While there are some register differences between them these do not affect the current Linux driver as the relevant features are not yet supported. Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/isl9305.txt | 36 +++ drivers/regulator/Kconfig | 6 + drivers/regulator/Makefile | 1 + drivers/regulator/isl9305.c | 247 +++++++++++++++++++++ include/linux/platform_data/isl9305.h | 30 +++ 5 files changed, 320 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/isl9305.txt create mode 100644 drivers/regulator/isl9305.c create mode 100644 include/linux/platform_data/isl9305.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/regulator/isl9305.txt b/Documentation/devicetree/bindings/regulator/isl9305.txt new file mode 100644 index 000000000000..a626fc1bbf0d --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/isl9305.txt @@ -0,0 +1,36 @@ +Intersil ISL9305/ISL9305H voltage regulator + +Required properties: + +- compatible: "isl,isl9305" or "isl,isl9305h" +- reg: I2C slave address, usually 0x68. +- regulators: A node that houses a sub-node for each regulator within the + device. Each sub-node is identified using the node's name, with valid + values being "dcd1", "dcd2", "ldo1" and "ldo2". The content of each sub-node + is defined by the standard binding for regulators; see regulator.txt. +- VINDCD1-supply: A phandle to a regulator node supplying VINDCD1. + VINDCD2-supply: A phandle to a regulator node supplying VINDCD2. + VINLDO1-supply: A phandle to a regulator node supplying VINLDO1. + VINLDO2-supply: A phandle to a regulator node supplying VINLDO2. + +Optional properties: +- Per-regulator optional properties are defined in regulator.txt + +Example + + pmic: isl9305@68 { + compatible = "isl,isl9305"; + reg = <0x68>; + + VINDCD1-supply = <&system_power>; + VINDCD2-supply = <&system_power>; + VINLDO1-supply = <&system_power>; + VINLDO2-supply = <&system_power>; + + regulators { + dcd1 { + regulator-name = "VDD_DSP"; + regulator-always-on; + }; + }; + }; diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index e6b98ed4c12f..3c8b6f401e4f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -250,6 +250,12 @@ config REGULATOR_HI6421 21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All of them come with support to either ECO (idle) or sleep mode. +config REGULATOR_ISL9305 + tristate "Intersil ISL9305 regulator" + depends on I2C + help + This driver supports ISL9305 voltage regulator chip. + config REGULATOR_ISL6271A tristate "Intersil ISL6271A Power regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 5513e2c141b1..e12fee8c943b 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o +obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c new file mode 100644 index 000000000000..b0d12d186b68 --- /dev/null +++ b/drivers/regulator/isl9305.c @@ -0,0 +1,247 @@ +/* + * isl9305 - Intersil ISL9305 DCDC regulator + * + * Copyright 2014 Linaro Ltd + * + * Author: Mark Brown + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Registers + */ +#define ISL9305_DCD1OUT 0x0 +#define ISL9305_DCD2OUT 0x1 +#define ISL9305_LDO1OUT 0x2 +#define ISL9305_LDO2OUT 0x3 +#define ISL9305_DCD_PARAMETER 0x4 +#define ISL9305_SYSTEM_PARAMETER 0x5 +#define ISL9305_DCD_SRCTL 0x6 + +#define ISL9305_MAX_REG ISL9305_DCD_SRCTL + +/* + * DCD_PARAMETER + */ +#define ISL9305_DCD_PHASE 0x40 +#define ISL9305_DCD2_ULTRA 0x20 +#define ISL9305_DCD1_ULTRA 0x10 +#define ISL9305_DCD2_BLD 0x08 +#define ISL9305_DCD1_BLD 0x04 +#define ISL9305_DCD2_MODE 0x02 +#define ISL9305_DCD1_MODE 0x01 + +/* + * SYSTEM_PARAMETER + */ +#define ISL9305_I2C_EN 0x40 +#define ISL9305_DCDPOR_MASK 0x30 +#define ISL9305_LDO2_EN 0x08 +#define ISL9305_LDO1_EN 0x04 +#define ISL9305_DCD2_EN 0x02 +#define ISL9305_DCD1_EN 0x01 + +/* + * DCD_SRCTL + */ +#define ISL9305_DCD2SR_MASK 0xc0 +#define ISL9305_DCD1SR_MASK 0x07 + +static const struct regulator_ops isl9305_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_linear, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, +}; + +static const struct regulator_desc isl9305_regulators[] = { + [ISL9305_DCD1] = { + .name = "DCD1", + .n_voltages = 0x70, + .min_uV = 825000, + .uV_step = 25000, + .vsel_reg = ISL9305_DCD1OUT, + .vsel_mask = 0x7f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_DCD1_EN, + .supply_name = "VINDCD1", + .ops = &isl9305_ops, + }, + [ISL9305_DCD2] = { + .name = "DCD2", + .n_voltages = 0x70, + .min_uV = 825000, + .uV_step = 25000, + .vsel_reg = ISL9305_DCD2OUT, + .vsel_mask = 0x7f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_DCD2_EN, + .supply_name = "VINDCD2", + .ops = &isl9305_ops, + }, + [ISL9305_LDO1] = { + .name = "LDO1", + .n_voltages = 0x37, + .min_uV = 900000, + .uV_step = 50000, + .vsel_reg = ISL9305_LDO1OUT, + .vsel_mask = 0x3f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_LDO1_EN, + .supply_name = "VINLDO1", + .ops = &isl9305_ops, + }, + [ISL9305_LDO2] = { + .name = "LDO2", + .n_voltages = 0x37, + .min_uV = 900000, + .uV_step = 50000, + .vsel_reg = ISL9305_LDO2OUT, + .vsel_mask = 0x3f, + .enable_reg = ISL9305_SYSTEM_PARAMETER, + .enable_mask = ISL9305_LDO2_EN, + .supply_name = "VINLDO2", + .ops = &isl9305_ops, + }, +}; + +#ifdef CONFIG_OF +static struct of_regulator_match isl9305_reg_matches[] = { + [ISL9305_DCD1] = { .name = "dcd1" }, + [ISL9305_DCD2] = { .name = "dcd2" }, + [ISL9305_LDO1] = { .name = "ldo1" }, + [ISL9305_LDO2] = { .name = "ldo2" }, +}; + +static struct of_regulator_match *isl9305_parse_dt(struct i2c_client *i2c) +{ + struct device_node *node = i2c->dev.of_node; + struct of_regulator_match *matches; + struct device_node *regs; + int count; + + regs = of_get_child_by_name(node, "regulators"); + if (!regs) + return NULL; + + matches = devm_kmemdup(&i2c->dev, isl9305_reg_matches, + sizeof(isl9305_reg_matches), GFP_KERNEL); + if (!matches) + return NULL; + + count = of_regulator_match(&i2c->dev, regs, matches, + ARRAY_SIZE(isl9305_reg_matches)); + of_node_put(regs); + if ((count < 0) || (count > ARRAY_SIZE(isl9305_reg_matches))) + return NULL; + + return matches; +} +#else +static struct of_regulator_match *isl9305_parse_dt(struct i2c_client *i2c) +{ + return NULL; +} +#endif + +static const struct regmap_config isl9305_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = ISL9305_MAX_REG, + .cache_type = REGCACHE_RBTREE, +}; + +static int isl9305_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct isl9305_pdata *pdata = i2c->dev.platform_data; + struct of_regulator_match *of_matches; + struct regulator_dev *rdev; + struct regmap *regmap; + int i, ret; + + of_matches = isl9305_parse_dt(i2c); + + regmap = devm_regmap_init_i2c(i2c, &isl9305_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to create regmap: %d\n", ret); + return ret; + } + + config.dev = &i2c->dev; + + for (i = 0; i < ARRAY_SIZE(isl9305_regulators); i++) { + config.of_node = NULL; + config.init_data = NULL; + + if (of_matches) { + config.init_data = of_matches[i].init_data; + config.of_node = of_matches[i].of_node; + } + + if (!config.init_data && pdata) + config.init_data = pdata->init_data[i]; + + rdev = devm_regulator_register(&i2c->dev, + &isl9305_regulators[i], + &config); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); + dev_err(&i2c->dev, "Failed to register %s: %d\n", + isl9305_regulators[i].name, ret); + return ret; + } + } + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id isl9305_dt_ids[] = { + { .compatible = "isl,isl9305" }, + { .compatible = "isl,isl9305h" }, + {}, +}; +#endif + +static const struct i2c_device_id isl9305_i2c_id[] = { + { "isl9305", }, + { "isl9305h", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id); + +static struct i2c_driver isl9305_regulator_driver = { + .driver = { + .name = "isl9305", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(isl9305_dt_ids), + }, + .probe = isl9305_i2c_probe, + .id_table = isl9305_i2c_id, +}; + +module_i2c_driver(isl9305_regulator_driver); + +MODULE_AUTHOR("Mark Brown"); +MODULE_DESCRIPTION("Intersil ISL9305 DCDC regulator"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/platform_data/isl9305.h b/include/linux/platform_data/isl9305.h new file mode 100644 index 000000000000..1419133fa69e --- /dev/null +++ b/include/linux/platform_data/isl9305.h @@ -0,0 +1,30 @@ +/* + * isl9305 - Intersil ISL9305 DCDC regulator + * + * Copyright 2014 Linaro Ltd + * + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __ISL9305_H +#define __ISL9305_H + +#define ISL9305_DCD1 0 +#define ISL9305_DCD2 1 +#define ISL9305_LDO1 2 +#define ISL9305_LDO2 3 + +#define ISL9305_MAX_REGULATOR ISL9305_LDO2 + +struct regulator_init_data; + +struct isl9305_pdata { + struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR]; +}; + +#endif -- cgit v1.2.3-71-gd317 From a0c7b164ad115ec0556dc0904ee2218cbc5cedfa Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 9 Sep 2014 23:13:57 +0100 Subject: regulator: of: Provide simplified DT parsing method Currently regulator drivers which support DT all repeat very similar code to supply a list of known regulator identifiers to be matched with DT, convert that to platform data which is then matched up with the regulators as they are registered. This is both fiddly to get right and for devices which can use the standard helpers to provide their operations is the main source of code in the driver. Since this code is essentially identical for most drivers we can factor it out into the core, moving the identifiers in the match table into the regulator descriptors and also allowing drivers to pass in the name of the subnode to search. When a driver provides an of_match string for the regulator the core will attempt to use that to obtain init_data, allowing the driver to remove all explicit code for DT parsing and simply provide data instead. The current code leaks the phandles for the child nodes, this will be addressed incrementally and makes no practical difference for FDT anyway as the DT data structures are never freed. Signed-off-by: Mark Brown --- drivers/regulator/core.c | 10 +++++--- drivers/regulator/internal.h | 4 ++++ drivers/regulator/of_regulator.c | 51 ++++++++++++++++++++++++++++++++++++++++ include/linux/regulator/driver.h | 4 ++++ 4 files changed, 66 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a3c3785901f5..496002efd961 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3516,12 +3516,17 @@ regulator_register(const struct regulator_desc *regulator_desc, return ERR_PTR(-EINVAL); } - init_data = config->init_data; - rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); + init_data = regulator_of_get_init_data(dev, regulator_desc, + &rdev->dev.of_node); + if (!init_data) { + init_data = config->init_data; + rdev->dev.of_node = of_node_get(config->of_node); + } + mutex_lock(®ulator_list_mutex); mutex_init(&rdev->mutex); @@ -3548,7 +3553,6 @@ regulator_register(const struct regulator_desc *regulator_desc, /* register with sysfs */ rdev->dev.class = ®ulator_class; - rdev->dev.of_node = of_node_get(config->of_node); rdev->dev.parent = dev; dev_set_name(&rdev->dev, "regulator.%d", atomic_inc_return(®ulator_no) - 1); diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index 84bbda10c396..a6043ad32ead 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -35,4 +35,8 @@ struct regulator { struct dentry *debugfs; }; +struct regulator_init_data *regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct device_node **node); + #endif diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index ee5e67bc8d5b..7a51814abdc5 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -14,8 +14,11 @@ #include #include #include +#include #include +#include "internal.h" + static void of_get_regulation_constraints(struct device_node *np, struct regulator_init_data **init_data) { @@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node, return count; } EXPORT_SYMBOL_GPL(of_regulator_match); + +struct regulator_init_data *regulator_of_get_init_data(struct device *dev, + const struct regulator_desc *desc, + struct device_node **node) +{ + struct device_node *search, *child; + struct regulator_init_data *init_data = NULL; + const char *name; + + if (!dev->of_node || !desc->of_match) + return NULL; + + if (desc->regulators_node) + search = of_get_child_by_name(dev->of_node, + desc->regulators_node); + else + search = dev->of_node; + + if (!search) { + dev_err(dev, "Failed to find regulator container node\n"); + return NULL; + } + + for_each_child_of_node(search, child) { + name = of_get_property(child, "regulator-compatible", NULL); + if (!name) + name = child->name; + + if (strcmp(desc->of_match, name)) + continue; + + init_data = of_get_regulator_init_data(dev, child); + if (!init_data) { + dev_err(dev, + "failed to parse DT for regulator %s\n", + child->name); + break; + } + + of_node_get(child); + *node = child; + break; + } + + of_node_put(search); + + return init_data; +} diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bbe03a1924c0..c35f5f97a147 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -203,6 +203,8 @@ enum regulator_type { * * @name: Identifying name for the regulator. * @supply_name: Identifying the regulator supply + * @of_match: Name used to identify regulator in DT. + * @regulators_node: Name of node containing regulator definitions in DT. * @id: Numerical identifier for the regulator. * @ops: Regulator operations table. * @irq: Interrupt number for the regulator. @@ -242,6 +244,8 @@ enum regulator_type { struct regulator_desc { const char *name; const char *supply_name; + const char *of_match; + const char *regulators_node; int id; bool continuous_voltage_range; unsigned n_voltages; -- cgit v1.2.3-71-gd317