18f446e6fSRajendra Nayak /*
28f446e6fSRajendra Nayak  * OF helpers for regulator framework
38f446e6fSRajendra Nayak  *
48f446e6fSRajendra Nayak  * Copyright (C) 2011 Texas Instruments, Inc.
58f446e6fSRajendra Nayak  * Rajendra Nayak <rnayak@ti.com>
68f446e6fSRajendra Nayak  *
78f446e6fSRajendra Nayak  * This program is free software; you can redistribute it and/or modify
88f446e6fSRajendra Nayak  * it under the terms of the GNU General Public License as published by
98f446e6fSRajendra Nayak  * the Free Software Foundation; either version 2 of the License, or
108f446e6fSRajendra Nayak  * (at your option) any later version.
118f446e6fSRajendra Nayak  */
128f446e6fSRajendra Nayak 
13e69af5e9SAxel Lin #include <linux/module.h>
148f446e6fSRajendra Nayak #include <linux/slab.h>
158f446e6fSRajendra Nayak #include <linux/of.h>
168f446e6fSRajendra Nayak #include <linux/regulator/machine.h>
17a0c7b164SMark Brown #include <linux/regulator/driver.h>
181c8fa58fSThierry Reding #include <linux/regulator/of_regulator.h>
198f446e6fSRajendra Nayak 
20a0c7b164SMark Brown #include "internal.h"
21a0c7b164SMark Brown 
22f32fa89cSKrzysztof Kozlowski static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
2340e20d68SChanwoo Choi 	[PM_SUSPEND_MEM]	= "regulator-state-mem",
2440e20d68SChanwoo Choi 	[PM_SUSPEND_MAX]	= "regulator-state-disk",
2540e20d68SChanwoo Choi };
2640e20d68SChanwoo Choi 
278f446e6fSRajendra Nayak static void of_get_regulation_constraints(struct device_node *np,
285e5e3a42SJavier Martinez Canillas 					struct regulator_init_data **init_data,
295e5e3a42SJavier Martinez Canillas 					const struct regulator_desc *desc)
308f446e6fSRajendra Nayak {
318f446e6fSRajendra Nayak 	struct regulation_constraints *constraints = &(*init_data)->constraints;
3240e20d68SChanwoo Choi 	struct regulator_state *suspend_state;
3340e20d68SChanwoo Choi 	struct device_node *suspend_np;
3440e20d68SChanwoo Choi 	int ret, i;
3500c877c6SLaxman Dewangan 	u32 pval;
368f446e6fSRajendra Nayak 
378f446e6fSRajendra Nayak 	constraints->name = of_get_property(np, "regulator-name", NULL);
388f446e6fSRajendra Nayak 
39a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
40a34785f1SLaxman Dewangan 		constraints->min_uV = pval;
41a34785f1SLaxman Dewangan 
42a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
43a34785f1SLaxman Dewangan 		constraints->max_uV = pval;
448f446e6fSRajendra Nayak 
458f446e6fSRajendra Nayak 	/* Voltage change possible? */
4645fa2038SMark Brown 	if (constraints->min_uV != constraints->max_uV)
478f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
4845fa2038SMark Brown 
4945fa2038SMark Brown 	/* Do we have a voltage range, if so try to apply it? */
5045fa2038SMark Brown 	if (constraints->min_uV && constraints->max_uV)
51ab62aa93SMark Brown 		constraints->apply_uV = true;
528f446e6fSRajendra Nayak 
531e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
541e050eabSSergei Shtylyov 		constraints->uV_offset = pval;
551e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
561e050eabSSergei Shtylyov 		constraints->min_uA = pval;
571e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
581e050eabSSergei Shtylyov 		constraints->max_uA = pval;
598f446e6fSRajendra Nayak 
6036e4f839SStephen Boyd 	if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
6136e4f839SStephen Boyd 				  &pval))
6236e4f839SStephen Boyd 		constraints->ilim_uA = pval;
6336e4f839SStephen Boyd 
648f446e6fSRajendra Nayak 	/* Current change possible? */
658f446e6fSRajendra Nayak 	if (constraints->min_uA != constraints->max_uA)
668f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
678f446e6fSRajendra Nayak 
681e050eabSSergei Shtylyov 	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
691e050eabSSergei Shtylyov 	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
701e050eabSSergei Shtylyov 	if (!constraints->always_on) /* status change should be possible. */
718f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
726f0b2c69SYadwinder Singh Brar 
7323c779b9SStephen Boyd 	constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
7423c779b9SStephen Boyd 
7593134c7bSKishon Vijay Abraham I 	if (of_property_read_bool(np, "regulator-allow-bypass"))
7693134c7bSKishon Vijay Abraham I 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
7793134c7bSKishon Vijay Abraham I 
78b263d203SBjorn Andersson 	if (of_property_read_bool(np, "regulator-allow-set-load"))
79b263d203SBjorn Andersson 		constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
80b263d203SBjorn Andersson 
811e050eabSSergei Shtylyov 	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
821e050eabSSergei Shtylyov 	if (!ret) {
831e050eabSSergei Shtylyov 		if (pval)
841e050eabSSergei Shtylyov 			constraints->ramp_delay = pval;
851653ccf4SYadwinder Singh Brar 		else
861653ccf4SYadwinder Singh Brar 			constraints->ramp_disable = true;
871653ccf4SYadwinder Singh Brar 	}
8800c877c6SLaxman Dewangan 
89d6c1dc3fSLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
90d6c1dc3fSLaxman Dewangan 	if (!ret)
91d6c1dc3fSLaxman Dewangan 		constraints->settling_time = pval;
92d6c1dc3fSLaxman Dewangan 
933ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
943ffad468SMatthias Kaehlcke 	if (!ret)
953ffad468SMatthias Kaehlcke 		constraints->settling_time_up = pval;
963ffad468SMatthias Kaehlcke 	if (constraints->settling_time_up && constraints->settling_time) {
973ffad468SMatthias Kaehlcke 		pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
983ffad468SMatthias Kaehlcke 			np->name);
993ffad468SMatthias Kaehlcke 		constraints->settling_time_up = 0;
1003ffad468SMatthias Kaehlcke 	}
1013ffad468SMatthias Kaehlcke 
1023ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-down-us",
1033ffad468SMatthias Kaehlcke 				   &pval);
1043ffad468SMatthias Kaehlcke 	if (!ret)
1053ffad468SMatthias Kaehlcke 		constraints->settling_time_down = pval;
1063ffad468SMatthias Kaehlcke 	if (constraints->settling_time_down && constraints->settling_time) {
1073ffad468SMatthias Kaehlcke 		pr_warn("%s: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
1083ffad468SMatthias Kaehlcke 			np->name);
1093ffad468SMatthias Kaehlcke 		constraints->settling_time_down = 0;
1103ffad468SMatthias Kaehlcke 	}
1113ffad468SMatthias Kaehlcke 
11200c877c6SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
11300c877c6SLaxman Dewangan 	if (!ret)
11400c877c6SLaxman Dewangan 		constraints->enable_time = pval;
11540e20d68SChanwoo Choi 
11657f66b78SStephen Boyd 	constraints->soft_start = of_property_read_bool(np,
11757f66b78SStephen Boyd 					"regulator-soft-start");
118670666b9SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
119670666b9SLaxman Dewangan 	if (!ret) {
120670666b9SLaxman Dewangan 		constraints->active_discharge =
121670666b9SLaxman Dewangan 				(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
122670666b9SLaxman Dewangan 					REGULATOR_ACTIVE_DISCHARGE_DISABLE;
123670666b9SLaxman Dewangan 	}
12457f66b78SStephen Boyd 
1255e5e3a42SJavier Martinez Canillas 	if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
1265e5e3a42SJavier Martinez Canillas 		if (desc && desc->of_map_mode) {
1275e5e3a42SJavier Martinez Canillas 			ret = desc->of_map_mode(pval);
1285e5e3a42SJavier Martinez Canillas 			if (ret == -EINVAL)
1295e5e3a42SJavier Martinez Canillas 				pr_err("%s: invalid mode %u\n", np->name, pval);
1305e5e3a42SJavier Martinez Canillas 			else
1315e5e3a42SJavier Martinez Canillas 				constraints->initial_mode = ret;
1325e5e3a42SJavier Martinez Canillas 		} else {
1335e5e3a42SJavier Martinez Canillas 			pr_warn("%s: mapping for mode %d not defined\n",
1345e5e3a42SJavier Martinez Canillas 				np->name, pval);
1355e5e3a42SJavier Martinez Canillas 		}
1365e5e3a42SJavier Martinez Canillas 	}
1375e5e3a42SJavier Martinez Canillas 
13822a10bcaSStephen Boyd 	if (!of_property_read_u32(np, "regulator-system-load", &pval))
13922a10bcaSStephen Boyd 		constraints->system_load = pval;
14022a10bcaSStephen Boyd 
1413a003baeSStephen Boyd 	constraints->over_current_protection = of_property_read_bool(np,
1423a003baeSStephen Boyd 					"regulator-over-current-protection");
1433a003baeSStephen Boyd 
14440e20d68SChanwoo Choi 	for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
14540e20d68SChanwoo Choi 		switch (i) {
14640e20d68SChanwoo Choi 		case PM_SUSPEND_MEM:
14740e20d68SChanwoo Choi 			suspend_state = &constraints->state_mem;
14840e20d68SChanwoo Choi 			break;
14940e20d68SChanwoo Choi 		case PM_SUSPEND_MAX:
15040e20d68SChanwoo Choi 			suspend_state = &constraints->state_disk;
15140e20d68SChanwoo Choi 			break;
15240e20d68SChanwoo Choi 		case PM_SUSPEND_ON:
15340e20d68SChanwoo Choi 		case PM_SUSPEND_FREEZE:
15440e20d68SChanwoo Choi 		case PM_SUSPEND_STANDBY:
15540e20d68SChanwoo Choi 		default:
15640e20d68SChanwoo Choi 			continue;
1577cf225b9SKrzysztof Kozlowski 		}
15840e20d68SChanwoo Choi 
15940e20d68SChanwoo Choi 		suspend_np = of_get_child_by_name(np, regulator_states[i]);
16040e20d68SChanwoo Choi 		if (!suspend_np || !suspend_state)
16140e20d68SChanwoo Choi 			continue;
16240e20d68SChanwoo Choi 
1635e5e3a42SJavier Martinez Canillas 		if (!of_property_read_u32(suspend_np, "regulator-mode",
1645e5e3a42SJavier Martinez Canillas 					  &pval)) {
1655e5e3a42SJavier Martinez Canillas 			if (desc && desc->of_map_mode) {
1665e5e3a42SJavier Martinez Canillas 				ret = desc->of_map_mode(pval);
1675e5e3a42SJavier Martinez Canillas 				if (ret == -EINVAL)
1685e5e3a42SJavier Martinez Canillas 					pr_err("%s: invalid mode %u\n",
1695e5e3a42SJavier Martinez Canillas 					       np->name, pval);
1705e5e3a42SJavier Martinez Canillas 				else
1715e5e3a42SJavier Martinez Canillas 					suspend_state->mode = ret;
1725e5e3a42SJavier Martinez Canillas 			} else {
1735e5e3a42SJavier Martinez Canillas 				pr_warn("%s: mapping for mode %d not defined\n",
1745e5e3a42SJavier Martinez Canillas 					np->name, pval);
1755e5e3a42SJavier Martinez Canillas 			}
1765e5e3a42SJavier Martinez Canillas 		}
1775e5e3a42SJavier Martinez Canillas 
17840e20d68SChanwoo Choi 		if (of_property_read_bool(suspend_np,
17940e20d68SChanwoo Choi 					"regulator-on-in-suspend"))
18040e20d68SChanwoo Choi 			suspend_state->enabled = true;
18140e20d68SChanwoo Choi 		else if (of_property_read_bool(suspend_np,
18240e20d68SChanwoo Choi 					"regulator-off-in-suspend"))
18340e20d68SChanwoo Choi 			suspend_state->disabled = true;
18440e20d68SChanwoo Choi 
1858cbcaea8SDoug Anderson 		if (!of_property_read_u32(suspend_np,
1868cbcaea8SDoug Anderson 					"regulator-suspend-microvolt", &pval))
1878cbcaea8SDoug Anderson 			suspend_state->uV = pval;
1888cbcaea8SDoug Anderson 
189a0f78bc8SKeerthy 		if (i == PM_SUSPEND_MEM)
190a0f78bc8SKeerthy 			constraints->initial_state = PM_SUSPEND_MEM;
191a0f78bc8SKeerthy 
1924eafec83SJavier Martinez Canillas 		of_node_put(suspend_np);
19340e20d68SChanwoo Choi 		suspend_state = NULL;
19440e20d68SChanwoo Choi 		suspend_np = NULL;
19540e20d68SChanwoo Choi 	}
1968f446e6fSRajendra Nayak }
1978f446e6fSRajendra Nayak 
1988f446e6fSRajendra Nayak /**
1998f446e6fSRajendra Nayak  * of_get_regulator_init_data - extract regulator_init_data structure info
2008f446e6fSRajendra Nayak  * @dev: device requesting for regulator_init_data
201072e78b1SJavier Martinez Canillas  * @node: regulator device node
202072e78b1SJavier Martinez Canillas  * @desc: regulator description
2038f446e6fSRajendra Nayak  *
2048f446e6fSRajendra Nayak  * Populates regulator_init_data structure by extracting data from device
2058f446e6fSRajendra Nayak  * tree node, returns a pointer to the populated struture or NULL if memory
2068f446e6fSRajendra Nayak  * alloc fails.
2078f446e6fSRajendra Nayak  */
208d9a861ccSShawn Guo struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
209072e78b1SJavier Martinez Canillas 					  struct device_node *node,
210072e78b1SJavier Martinez Canillas 					  const struct regulator_desc *desc)
2118f446e6fSRajendra Nayak {
2128f446e6fSRajendra Nayak 	struct regulator_init_data *init_data;
2138f446e6fSRajendra Nayak 
214d9a861ccSShawn Guo 	if (!node)
2158f446e6fSRajendra Nayak 		return NULL;
2168f446e6fSRajendra Nayak 
2178f446e6fSRajendra Nayak 	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
2188f446e6fSRajendra Nayak 	if (!init_data)
2198f446e6fSRajendra Nayak 		return NULL; /* Out of memory? */
2208f446e6fSRajendra Nayak 
2215e5e3a42SJavier Martinez Canillas 	of_get_regulation_constraints(node, &init_data, desc);
2228f446e6fSRajendra Nayak 	return init_data;
2238f446e6fSRajendra Nayak }
224e69af5e9SAxel Lin EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
2251c8fa58fSThierry Reding 
22613b3fde8SCharles Keepax struct devm_of_regulator_matches {
22713b3fde8SCharles Keepax 	struct of_regulator_match *matches;
22813b3fde8SCharles Keepax 	unsigned int num_matches;
22913b3fde8SCharles Keepax };
23013b3fde8SCharles Keepax 
23113b3fde8SCharles Keepax static void devm_of_regulator_put_matches(struct device *dev, void *res)
23213b3fde8SCharles Keepax {
23313b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches = res;
23413b3fde8SCharles Keepax 	int i;
23513b3fde8SCharles Keepax 
23613b3fde8SCharles Keepax 	for (i = 0; i < devm_matches->num_matches; i++)
23713b3fde8SCharles Keepax 		of_node_put(devm_matches->matches[i].of_node);
23813b3fde8SCharles Keepax }
23913b3fde8SCharles Keepax 
2401c8fa58fSThierry Reding /**
24113511defSStephen Warren  * of_regulator_match - extract multiple regulator init data from device tree.
2421c8fa58fSThierry Reding  * @dev: device requesting the data
2431c8fa58fSThierry Reding  * @node: parent device node of the regulators
2441c8fa58fSThierry Reding  * @matches: match table for the regulators
2451c8fa58fSThierry Reding  * @num_matches: number of entries in match table
2461c8fa58fSThierry Reding  *
24713511defSStephen Warren  * This function uses a match table specified by the regulator driver to
24813511defSStephen Warren  * parse regulator init data from the device tree. @node is expected to
24913511defSStephen Warren  * contain a set of child nodes, each providing the init data for one
25013511defSStephen Warren  * regulator. The data parsed from a child node will be matched to a regulator
25113511defSStephen Warren  * based on either the deprecated property regulator-compatible if present,
25213511defSStephen Warren  * or otherwise the child node's name. Note that the match table is modified
253bd0dda74SCharles Keepax  * in place and an additional of_node reference is taken for each matched
254bd0dda74SCharles Keepax  * regulator.
2551c8fa58fSThierry Reding  *
2561c8fa58fSThierry Reding  * Returns the number of matches found or a negative error code on failure.
2571c8fa58fSThierry Reding  */
2581c8fa58fSThierry Reding int of_regulator_match(struct device *dev, struct device_node *node,
2591c8fa58fSThierry Reding 		       struct of_regulator_match *matches,
2601c8fa58fSThierry Reding 		       unsigned int num_matches)
2611c8fa58fSThierry Reding {
2621c8fa58fSThierry Reding 	unsigned int count = 0;
2631c8fa58fSThierry Reding 	unsigned int i;
26413511defSStephen Warren 	const char *name;
2655260cd2bSLaxman Dewangan 	struct device_node *child;
26613b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches;
2671c8fa58fSThierry Reding 
2681c8fa58fSThierry Reding 	if (!dev || !node)
2691c8fa58fSThierry Reding 		return -EINVAL;
2701c8fa58fSThierry Reding 
27113b3fde8SCharles Keepax 	devm_matches = devres_alloc(devm_of_regulator_put_matches,
27213b3fde8SCharles Keepax 				    sizeof(struct devm_of_regulator_matches),
27313b3fde8SCharles Keepax 				    GFP_KERNEL);
27413b3fde8SCharles Keepax 	if (!devm_matches)
27513b3fde8SCharles Keepax 		return -ENOMEM;
27613b3fde8SCharles Keepax 
27713b3fde8SCharles Keepax 	devm_matches->matches = matches;
27813b3fde8SCharles Keepax 	devm_matches->num_matches = num_matches;
27913b3fde8SCharles Keepax 
28013b3fde8SCharles Keepax 	devres_add(dev, devm_matches);
28113b3fde8SCharles Keepax 
282a2f95c36SStephen Warren 	for (i = 0; i < num_matches; i++) {
283a2f95c36SStephen Warren 		struct of_regulator_match *match = &matches[i];
284a2f95c36SStephen Warren 		match->init_data = NULL;
285a2f95c36SStephen Warren 		match->of_node = NULL;
286a2f95c36SStephen Warren 	}
287a2f95c36SStephen Warren 
2885260cd2bSLaxman Dewangan 	for_each_child_of_node(node, child) {
28913511defSStephen Warren 		name = of_get_property(child,
2905260cd2bSLaxman Dewangan 					"regulator-compatible", NULL);
29113511defSStephen Warren 		if (!name)
29213511defSStephen Warren 			name = child->name;
2931c8fa58fSThierry Reding 		for (i = 0; i < num_matches; i++) {
2941c8fa58fSThierry Reding 			struct of_regulator_match *match = &matches[i];
2955260cd2bSLaxman Dewangan 			if (match->of_node)
2961c8fa58fSThierry Reding 				continue;
2971c8fa58fSThierry Reding 
29813511defSStephen Warren 			if (strcmp(match->name, name))
2995260cd2bSLaxman Dewangan 				continue;
3005260cd2bSLaxman Dewangan 
3015260cd2bSLaxman Dewangan 			match->init_data =
30275d6b2faSJavier Martinez Canillas 				of_get_regulator_init_data(dev, child,
30375d6b2faSJavier Martinez Canillas 							   match->desc);
3041c8fa58fSThierry Reding 			if (!match->init_data) {
3055260cd2bSLaxman Dewangan 				dev_err(dev,
3065260cd2bSLaxman Dewangan 					"failed to parse DT for regulator %s\n",
3071c8fa58fSThierry Reding 					child->name);
3081c8fa58fSThierry Reding 				return -EINVAL;
3091c8fa58fSThierry Reding 			}
310bd0dda74SCharles Keepax 			match->of_node = of_node_get(child);
3111c8fa58fSThierry Reding 			count++;
3125260cd2bSLaxman Dewangan 			break;
3135260cd2bSLaxman Dewangan 		}
3141c8fa58fSThierry Reding 	}
3151c8fa58fSThierry Reding 
3161c8fa58fSThierry Reding 	return count;
3171c8fa58fSThierry Reding }
3181c8fa58fSThierry Reding EXPORT_SYMBOL_GPL(of_regulator_match);
319a0c7b164SMark Brown 
320a0c7b164SMark Brown struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
321a0c7b164SMark Brown 					    const struct regulator_desc *desc,
322bfa21a0dSKrzysztof Kozlowski 					    struct regulator_config *config,
323a0c7b164SMark Brown 					    struct device_node **node)
324a0c7b164SMark Brown {
325a0c7b164SMark Brown 	struct device_node *search, *child;
326a0c7b164SMark Brown 	struct regulator_init_data *init_data = NULL;
327a0c7b164SMark Brown 	const char *name;
328a0c7b164SMark Brown 
329a0c7b164SMark Brown 	if (!dev->of_node || !desc->of_match)
330a0c7b164SMark Brown 		return NULL;
331a0c7b164SMark Brown 
332a0c7b164SMark Brown 	if (desc->regulators_node)
333a0c7b164SMark Brown 		search = of_get_child_by_name(dev->of_node,
334a0c7b164SMark Brown 					      desc->regulators_node);
335a0c7b164SMark Brown 	else
336a0c7b164SMark Brown 		search = dev->of_node;
337a0c7b164SMark Brown 
338a0c7b164SMark Brown 	if (!search) {
3397de79a1dSMark Brown 		dev_dbg(dev, "Failed to find regulator container node '%s'\n",
3407de79a1dSMark Brown 			desc->regulators_node);
341a0c7b164SMark Brown 		return NULL;
342a0c7b164SMark Brown 	}
343a0c7b164SMark Brown 
344130daa3fSStephen Boyd 	for_each_available_child_of_node(search, child) {
345a0c7b164SMark Brown 		name = of_get_property(child, "regulator-compatible", NULL);
346a0c7b164SMark Brown 		if (!name)
347a0c7b164SMark Brown 			name = child->name;
348a0c7b164SMark Brown 
349a0c7b164SMark Brown 		if (strcmp(desc->of_match, name))
350a0c7b164SMark Brown 			continue;
351a0c7b164SMark Brown 
352072e78b1SJavier Martinez Canillas 		init_data = of_get_regulator_init_data(dev, child, desc);
353a0c7b164SMark Brown 		if (!init_data) {
354a0c7b164SMark Brown 			dev_err(dev,
355a0c7b164SMark Brown 				"failed to parse DT for regulator %s\n",
356a0c7b164SMark Brown 				child->name);
357a0c7b164SMark Brown 			break;
358a0c7b164SMark Brown 		}
359a0c7b164SMark Brown 
360bfa21a0dSKrzysztof Kozlowski 		if (desc->of_parse_cb) {
361bfa21a0dSKrzysztof Kozlowski 			if (desc->of_parse_cb(child, desc, config)) {
362bfa21a0dSKrzysztof Kozlowski 				dev_err(dev,
363bfa21a0dSKrzysztof Kozlowski 					"driver callback failed to parse DT for regulator %s\n",
364bfa21a0dSKrzysztof Kozlowski 					child->name);
365bfa21a0dSKrzysztof Kozlowski 				init_data = NULL;
366bfa21a0dSKrzysztof Kozlowski 				break;
367bfa21a0dSKrzysztof Kozlowski 			}
368bfa21a0dSKrzysztof Kozlowski 		}
369bfa21a0dSKrzysztof Kozlowski 
370a0c7b164SMark Brown 		of_node_get(child);
371a0c7b164SMark Brown 		*node = child;
372a0c7b164SMark Brown 		break;
373a0c7b164SMark Brown 	}
374a0c7b164SMark Brown 
375a0c7b164SMark Brown 	of_node_put(search);
376a0c7b164SMark Brown 
377a0c7b164SMark Brown 	return init_data;
378a0c7b164SMark Brown }
379