12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28f446e6fSRajendra Nayak /*
38f446e6fSRajendra Nayak  * OF helpers for regulator framework
48f446e6fSRajendra Nayak  *
58f446e6fSRajendra Nayak  * Copyright (C) 2011 Texas Instruments, Inc.
68f446e6fSRajendra Nayak  * Rajendra Nayak <rnayak@ti.com>
78f446e6fSRajendra Nayak  */
88f446e6fSRajendra Nayak 
9e69af5e9SAxel Lin #include <linux/module.h>
108f446e6fSRajendra Nayak #include <linux/slab.h>
118f446e6fSRajendra Nayak #include <linux/of.h>
128f446e6fSRajendra Nayak #include <linux/regulator/machine.h>
13a0c7b164SMark Brown #include <linux/regulator/driver.h>
141c8fa58fSThierry Reding #include <linux/regulator/of_regulator.h>
158f446e6fSRajendra Nayak 
16a0c7b164SMark Brown #include "internal.h"
17a0c7b164SMark Brown 
18f32fa89cSKrzysztof Kozlowski static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
19f2b40769SAndrei.Stefanescu@microchip.com 	[PM_SUSPEND_STANDBY]	= "regulator-state-standby",
2040e20d68SChanwoo Choi 	[PM_SUSPEND_MEM]	= "regulator-state-mem",
2140e20d68SChanwoo Choi 	[PM_SUSPEND_MAX]	= "regulator-state-disk",
2240e20d68SChanwoo Choi };
2340e20d68SChanwoo Choi 
248f446e6fSRajendra Nayak static void of_get_regulation_constraints(struct device_node *np,
255e5e3a42SJavier Martinez Canillas 					struct regulator_init_data **init_data,
265e5e3a42SJavier Martinez Canillas 					const struct regulator_desc *desc)
278f446e6fSRajendra Nayak {
288f446e6fSRajendra Nayak 	struct regulation_constraints *constraints = &(*init_data)->constraints;
2940e20d68SChanwoo Choi 	struct regulator_state *suspend_state;
3040e20d68SChanwoo Choi 	struct device_node *suspend_np;
3102f37039SDouglas Anderson 	unsigned int mode;
3254557ad9SDavid Collins 	int ret, i, len;
3300c877c6SLaxman Dewangan 	u32 pval;
348f446e6fSRajendra Nayak 
358f446e6fSRajendra Nayak 	constraints->name = of_get_property(np, "regulator-name", NULL);
368f446e6fSRajendra Nayak 
37a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
38a34785f1SLaxman Dewangan 		constraints->min_uV = pval;
39a34785f1SLaxman Dewangan 
40a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
41a34785f1SLaxman Dewangan 		constraints->max_uV = pval;
428f446e6fSRajendra Nayak 
438f446e6fSRajendra Nayak 	/* Voltage change possible? */
4445fa2038SMark Brown 	if (constraints->min_uV != constraints->max_uV)
458f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
4645fa2038SMark Brown 
4745fa2038SMark Brown 	/* Do we have a voltage range, if so try to apply it? */
4845fa2038SMark Brown 	if (constraints->min_uV && constraints->max_uV)
49ab62aa93SMark Brown 		constraints->apply_uV = true;
508f446e6fSRajendra Nayak 
511e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
521e050eabSSergei Shtylyov 		constraints->uV_offset = pval;
531e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
541e050eabSSergei Shtylyov 		constraints->min_uA = pval;
551e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
561e050eabSSergei Shtylyov 		constraints->max_uA = pval;
578f446e6fSRajendra Nayak 
5836e4f839SStephen Boyd 	if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
5936e4f839SStephen Boyd 				  &pval))
6036e4f839SStephen Boyd 		constraints->ilim_uA = pval;
6136e4f839SStephen Boyd 
628f446e6fSRajendra Nayak 	/* Current change possible? */
638f446e6fSRajendra Nayak 	if (constraints->min_uA != constraints->max_uA)
648f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
658f446e6fSRajendra Nayak 
661e050eabSSergei Shtylyov 	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
671e050eabSSergei Shtylyov 	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
681e050eabSSergei Shtylyov 	if (!constraints->always_on) /* status change should be possible. */
698f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
706f0b2c69SYadwinder Singh Brar 
7123c779b9SStephen Boyd 	constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
7223c779b9SStephen Boyd 
7393134c7bSKishon Vijay Abraham I 	if (of_property_read_bool(np, "regulator-allow-bypass"))
7493134c7bSKishon Vijay Abraham I 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
7593134c7bSKishon Vijay Abraham I 
76b263d203SBjorn Andersson 	if (of_property_read_bool(np, "regulator-allow-set-load"))
77b263d203SBjorn Andersson 		constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
78b263d203SBjorn Andersson 
791e050eabSSergei Shtylyov 	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
801e050eabSSergei Shtylyov 	if (!ret) {
811e050eabSSergei Shtylyov 		if (pval)
821e050eabSSergei Shtylyov 			constraints->ramp_delay = pval;
831653ccf4SYadwinder Singh Brar 		else
841653ccf4SYadwinder Singh Brar 			constraints->ramp_disable = true;
851653ccf4SYadwinder Singh Brar 	}
8600c877c6SLaxman Dewangan 
87d6c1dc3fSLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
88d6c1dc3fSLaxman Dewangan 	if (!ret)
89d6c1dc3fSLaxman Dewangan 		constraints->settling_time = pval;
90d6c1dc3fSLaxman Dewangan 
913ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
923ffad468SMatthias Kaehlcke 	if (!ret)
933ffad468SMatthias Kaehlcke 		constraints->settling_time_up = pval;
943ffad468SMatthias Kaehlcke 	if (constraints->settling_time_up && constraints->settling_time) {
950c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
960c9721a5SRob Herring 			np);
973ffad468SMatthias Kaehlcke 		constraints->settling_time_up = 0;
983ffad468SMatthias Kaehlcke 	}
993ffad468SMatthias Kaehlcke 
1003ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-down-us",
1013ffad468SMatthias Kaehlcke 				   &pval);
1023ffad468SMatthias Kaehlcke 	if (!ret)
1033ffad468SMatthias Kaehlcke 		constraints->settling_time_down = pval;
1043ffad468SMatthias Kaehlcke 	if (constraints->settling_time_down && constraints->settling_time) {
1050c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
1060c9721a5SRob Herring 			np);
1073ffad468SMatthias Kaehlcke 		constraints->settling_time_down = 0;
1083ffad468SMatthias Kaehlcke 	}
1093ffad468SMatthias Kaehlcke 
11000c877c6SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
11100c877c6SLaxman Dewangan 	if (!ret)
11200c877c6SLaxman Dewangan 		constraints->enable_time = pval;
11340e20d68SChanwoo Choi 
11457f66b78SStephen Boyd 	constraints->soft_start = of_property_read_bool(np,
11557f66b78SStephen Boyd 					"regulator-soft-start");
116670666b9SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
117670666b9SLaxman Dewangan 	if (!ret) {
118670666b9SLaxman Dewangan 		constraints->active_discharge =
119670666b9SLaxman Dewangan 				(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
120670666b9SLaxman Dewangan 					REGULATOR_ACTIVE_DISCHARGE_DISABLE;
121670666b9SLaxman Dewangan 	}
12257f66b78SStephen Boyd 
1235e5e3a42SJavier Martinez Canillas 	if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
1245e5e3a42SJavier Martinez Canillas 		if (desc && desc->of_map_mode) {
12502f37039SDouglas Anderson 			mode = desc->of_map_mode(pval);
12602f37039SDouglas Anderson 			if (mode == REGULATOR_MODE_INVALID)
1270c9721a5SRob Herring 				pr_err("%pOFn: invalid mode %u\n", np, pval);
1285e5e3a42SJavier Martinez Canillas 			else
12902f37039SDouglas Anderson 				constraints->initial_mode = mode;
1305e5e3a42SJavier Martinez Canillas 		} else {
1310c9721a5SRob Herring 			pr_warn("%pOFn: mapping for mode %d not defined\n",
1320c9721a5SRob Herring 				np, pval);
1335e5e3a42SJavier Martinez Canillas 		}
1345e5e3a42SJavier Martinez Canillas 	}
1355e5e3a42SJavier Martinez Canillas 
13654557ad9SDavid Collins 	len = of_property_count_elems_of_size(np, "regulator-allowed-modes",
13754557ad9SDavid Collins 						sizeof(u32));
13854557ad9SDavid Collins 	if (len > 0) {
13954557ad9SDavid Collins 		if (desc && desc->of_map_mode) {
14054557ad9SDavid Collins 			for (i = 0; i < len; i++) {
14154557ad9SDavid Collins 				ret = of_property_read_u32_index(np,
14254557ad9SDavid Collins 					"regulator-allowed-modes", i, &pval);
14354557ad9SDavid Collins 				if (ret) {
1440c9721a5SRob Herring 					pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
1450c9721a5SRob Herring 						np, i, ret);
14654557ad9SDavid Collins 					break;
14754557ad9SDavid Collins 				}
14854557ad9SDavid Collins 				mode = desc->of_map_mode(pval);
14954557ad9SDavid Collins 				if (mode == REGULATOR_MODE_INVALID)
1500c9721a5SRob Herring 					pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
1510c9721a5SRob Herring 						np, pval);
15254557ad9SDavid Collins 				else
15354557ad9SDavid Collins 					constraints->valid_modes_mask |= mode;
15454557ad9SDavid Collins 			}
15554557ad9SDavid Collins 			if (constraints->valid_modes_mask)
15654557ad9SDavid Collins 				constraints->valid_ops_mask
15754557ad9SDavid Collins 					|= REGULATOR_CHANGE_MODE;
15854557ad9SDavid Collins 		} else {
1590c9721a5SRob Herring 			pr_warn("%pOFn: mode mapping not defined\n", np);
16054557ad9SDavid Collins 		}
16154557ad9SDavid Collins 	}
16254557ad9SDavid Collins 
16322a10bcaSStephen Boyd 	if (!of_property_read_u32(np, "regulator-system-load", &pval))
16422a10bcaSStephen Boyd 		constraints->system_load = pval;
16522a10bcaSStephen Boyd 
166a085a31aSMaciej Purski 	if (!of_property_read_u32(np, "regulator-coupled-max-spread",
167a085a31aSMaciej Purski 				  &pval))
168a085a31aSMaciej Purski 		constraints->max_spread = pval;
169a085a31aSMaciej Purski 
17085254bcfSDmitry Osipenko 	if (!of_property_read_u32(np, "regulator-max-step-microvolt",
17185254bcfSDmitry Osipenko 				  &pval))
17285254bcfSDmitry Osipenko 		constraints->max_uV_step = pval;
17385254bcfSDmitry Osipenko 
1743a003baeSStephen Boyd 	constraints->over_current_protection = of_property_read_bool(np,
1753a003baeSStephen Boyd 					"regulator-over-current-protection");
1763a003baeSStephen Boyd 
17740e20d68SChanwoo Choi 	for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
17840e20d68SChanwoo Choi 		switch (i) {
17940e20d68SChanwoo Choi 		case PM_SUSPEND_MEM:
18040e20d68SChanwoo Choi 			suspend_state = &constraints->state_mem;
18140e20d68SChanwoo Choi 			break;
18240e20d68SChanwoo Choi 		case PM_SUSPEND_MAX:
18340e20d68SChanwoo Choi 			suspend_state = &constraints->state_disk;
18440e20d68SChanwoo Choi 			break;
185f2b40769SAndrei.Stefanescu@microchip.com 		case PM_SUSPEND_STANDBY:
186f2b40769SAndrei.Stefanescu@microchip.com 			suspend_state = &constraints->state_standby;
187f2b40769SAndrei.Stefanescu@microchip.com 			break;
18840e20d68SChanwoo Choi 		case PM_SUSPEND_ON:
189690cbb90SRafael J. Wysocki 		case PM_SUSPEND_TO_IDLE:
19040e20d68SChanwoo Choi 		default:
19140e20d68SChanwoo Choi 			continue;
1927cf225b9SKrzysztof Kozlowski 		}
19340e20d68SChanwoo Choi 
19440e20d68SChanwoo Choi 		suspend_np = of_get_child_by_name(np, regulator_states[i]);
19540e20d68SChanwoo Choi 		if (!suspend_np || !suspend_state)
19640e20d68SChanwoo Choi 			continue;
19740e20d68SChanwoo Choi 
1985e5e3a42SJavier Martinez Canillas 		if (!of_property_read_u32(suspend_np, "regulator-mode",
1995e5e3a42SJavier Martinez Canillas 					  &pval)) {
2005e5e3a42SJavier Martinez Canillas 			if (desc && desc->of_map_mode) {
20102f37039SDouglas Anderson 				mode = desc->of_map_mode(pval);
20202f37039SDouglas Anderson 				if (mode == REGULATOR_MODE_INVALID)
2030c9721a5SRob Herring 					pr_err("%pOFn: invalid mode %u\n",
2040c9721a5SRob Herring 					       np, pval);
2055e5e3a42SJavier Martinez Canillas 				else
20602f37039SDouglas Anderson 					suspend_state->mode = mode;
2075e5e3a42SJavier Martinez Canillas 			} else {
2080c9721a5SRob Herring 				pr_warn("%pOFn: mapping for mode %d not defined\n",
2090c9721a5SRob Herring 					np, pval);
2105e5e3a42SJavier Martinez Canillas 			}
2115e5e3a42SJavier Martinez Canillas 		}
2125e5e3a42SJavier Martinez Canillas 
21340e20d68SChanwoo Choi 		if (of_property_read_bool(suspend_np,
21440e20d68SChanwoo Choi 					"regulator-on-in-suspend"))
21572069f99SChunyan Zhang 			suspend_state->enabled = ENABLE_IN_SUSPEND;
21640e20d68SChanwoo Choi 		else if (of_property_read_bool(suspend_np,
21740e20d68SChanwoo Choi 					"regulator-off-in-suspend"))
21872069f99SChunyan Zhang 			suspend_state->enabled = DISABLE_IN_SUSPEND;
21940e20d68SChanwoo Choi 
220f7efad10SChunyan Zhang 		if (!of_property_read_u32(np, "regulator-suspend-min-microvolt",
221f7efad10SChunyan Zhang 					  &pval))
222f7efad10SChunyan Zhang 			suspend_state->min_uV = pval;
223f7efad10SChunyan Zhang 
224f7efad10SChunyan Zhang 		if (!of_property_read_u32(np, "regulator-suspend-max-microvolt",
225f7efad10SChunyan Zhang 					  &pval))
226f7efad10SChunyan Zhang 			suspend_state->max_uV = pval;
22740e20d68SChanwoo Choi 
2288cbcaea8SDoug Anderson 		if (!of_property_read_u32(suspend_np,
2298cbcaea8SDoug Anderson 					"regulator-suspend-microvolt", &pval))
2308cbcaea8SDoug Anderson 			suspend_state->uV = pval;
231f7efad10SChunyan Zhang 		else /* otherwise use min_uV as default suspend voltage */
232f7efad10SChunyan Zhang 			suspend_state->uV = suspend_state->min_uV;
233f7efad10SChunyan Zhang 
234f7efad10SChunyan Zhang 		if (of_property_read_bool(suspend_np,
235f7efad10SChunyan Zhang 					"regulator-changeable-in-suspend"))
236f7efad10SChunyan Zhang 			suspend_state->changeable = true;
2378cbcaea8SDoug Anderson 
238a0f78bc8SKeerthy 		if (i == PM_SUSPEND_MEM)
239a0f78bc8SKeerthy 			constraints->initial_state = PM_SUSPEND_MEM;
240a0f78bc8SKeerthy 
2414eafec83SJavier Martinez Canillas 		of_node_put(suspend_np);
24240e20d68SChanwoo Choi 		suspend_state = NULL;
24340e20d68SChanwoo Choi 		suspend_np = NULL;
24440e20d68SChanwoo Choi 	}
2458f446e6fSRajendra Nayak }
2468f446e6fSRajendra Nayak 
2478f446e6fSRajendra Nayak /**
2488f446e6fSRajendra Nayak  * of_get_regulator_init_data - extract regulator_init_data structure info
2498f446e6fSRajendra Nayak  * @dev: device requesting for regulator_init_data
250072e78b1SJavier Martinez Canillas  * @node: regulator device node
251072e78b1SJavier Martinez Canillas  * @desc: regulator description
2528f446e6fSRajendra Nayak  *
2538f446e6fSRajendra Nayak  * Populates regulator_init_data structure by extracting data from device
25448f1b4efSKrzysztof Kozlowski  * tree node, returns a pointer to the populated structure or NULL if memory
2558f446e6fSRajendra Nayak  * alloc fails.
2568f446e6fSRajendra Nayak  */
257d9a861ccSShawn Guo struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
258072e78b1SJavier Martinez Canillas 					  struct device_node *node,
259072e78b1SJavier Martinez Canillas 					  const struct regulator_desc *desc)
2608f446e6fSRajendra Nayak {
2618f446e6fSRajendra Nayak 	struct regulator_init_data *init_data;
2628f446e6fSRajendra Nayak 
263d9a861ccSShawn Guo 	if (!node)
2648f446e6fSRajendra Nayak 		return NULL;
2658f446e6fSRajendra Nayak 
2668f446e6fSRajendra Nayak 	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
2678f446e6fSRajendra Nayak 	if (!init_data)
2688f446e6fSRajendra Nayak 		return NULL; /* Out of memory? */
2698f446e6fSRajendra Nayak 
2705e5e3a42SJavier Martinez Canillas 	of_get_regulation_constraints(node, &init_data, desc);
2718f446e6fSRajendra Nayak 	return init_data;
2728f446e6fSRajendra Nayak }
273e69af5e9SAxel Lin EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
2741c8fa58fSThierry Reding 
27513b3fde8SCharles Keepax struct devm_of_regulator_matches {
27613b3fde8SCharles Keepax 	struct of_regulator_match *matches;
27713b3fde8SCharles Keepax 	unsigned int num_matches;
27813b3fde8SCharles Keepax };
27913b3fde8SCharles Keepax 
28013b3fde8SCharles Keepax static void devm_of_regulator_put_matches(struct device *dev, void *res)
28113b3fde8SCharles Keepax {
28213b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches = res;
28313b3fde8SCharles Keepax 	int i;
28413b3fde8SCharles Keepax 
28513b3fde8SCharles Keepax 	for (i = 0; i < devm_matches->num_matches; i++)
28613b3fde8SCharles Keepax 		of_node_put(devm_matches->matches[i].of_node);
28713b3fde8SCharles Keepax }
28813b3fde8SCharles Keepax 
2891c8fa58fSThierry Reding /**
29013511defSStephen Warren  * of_regulator_match - extract multiple regulator init data from device tree.
2911c8fa58fSThierry Reding  * @dev: device requesting the data
2921c8fa58fSThierry Reding  * @node: parent device node of the regulators
2931c8fa58fSThierry Reding  * @matches: match table for the regulators
2941c8fa58fSThierry Reding  * @num_matches: number of entries in match table
2951c8fa58fSThierry Reding  *
29613511defSStephen Warren  * This function uses a match table specified by the regulator driver to
29713511defSStephen Warren  * parse regulator init data from the device tree. @node is expected to
29813511defSStephen Warren  * contain a set of child nodes, each providing the init data for one
29913511defSStephen Warren  * regulator. The data parsed from a child node will be matched to a regulator
30013511defSStephen Warren  * based on either the deprecated property regulator-compatible if present,
30113511defSStephen Warren  * or otherwise the child node's name. Note that the match table is modified
302bd0dda74SCharles Keepax  * in place and an additional of_node reference is taken for each matched
303bd0dda74SCharles Keepax  * regulator.
3041c8fa58fSThierry Reding  *
3051c8fa58fSThierry Reding  * Returns the number of matches found or a negative error code on failure.
3061c8fa58fSThierry Reding  */
3071c8fa58fSThierry Reding int of_regulator_match(struct device *dev, struct device_node *node,
3081c8fa58fSThierry Reding 		       struct of_regulator_match *matches,
3091c8fa58fSThierry Reding 		       unsigned int num_matches)
3101c8fa58fSThierry Reding {
3111c8fa58fSThierry Reding 	unsigned int count = 0;
3121c8fa58fSThierry Reding 	unsigned int i;
31313511defSStephen Warren 	const char *name;
3145260cd2bSLaxman Dewangan 	struct device_node *child;
31513b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches;
3161c8fa58fSThierry Reding 
3171c8fa58fSThierry Reding 	if (!dev || !node)
3181c8fa58fSThierry Reding 		return -EINVAL;
3191c8fa58fSThierry Reding 
32013b3fde8SCharles Keepax 	devm_matches = devres_alloc(devm_of_regulator_put_matches,
32113b3fde8SCharles Keepax 				    sizeof(struct devm_of_regulator_matches),
32213b3fde8SCharles Keepax 				    GFP_KERNEL);
32313b3fde8SCharles Keepax 	if (!devm_matches)
32413b3fde8SCharles Keepax 		return -ENOMEM;
32513b3fde8SCharles Keepax 
32613b3fde8SCharles Keepax 	devm_matches->matches = matches;
32713b3fde8SCharles Keepax 	devm_matches->num_matches = num_matches;
32813b3fde8SCharles Keepax 
32913b3fde8SCharles Keepax 	devres_add(dev, devm_matches);
33013b3fde8SCharles Keepax 
331a2f95c36SStephen Warren 	for (i = 0; i < num_matches; i++) {
332a2f95c36SStephen Warren 		struct of_regulator_match *match = &matches[i];
333a2f95c36SStephen Warren 		match->init_data = NULL;
334a2f95c36SStephen Warren 		match->of_node = NULL;
335a2f95c36SStephen Warren 	}
336a2f95c36SStephen Warren 
3375260cd2bSLaxman Dewangan 	for_each_child_of_node(node, child) {
33813511defSStephen Warren 		name = of_get_property(child,
3395260cd2bSLaxman Dewangan 					"regulator-compatible", NULL);
34013511defSStephen Warren 		if (!name)
34113511defSStephen Warren 			name = child->name;
3421c8fa58fSThierry Reding 		for (i = 0; i < num_matches; i++) {
3431c8fa58fSThierry Reding 			struct of_regulator_match *match = &matches[i];
3445260cd2bSLaxman Dewangan 			if (match->of_node)
3451c8fa58fSThierry Reding 				continue;
3461c8fa58fSThierry Reding 
34713511defSStephen Warren 			if (strcmp(match->name, name))
3485260cd2bSLaxman Dewangan 				continue;
3495260cd2bSLaxman Dewangan 
3505260cd2bSLaxman Dewangan 			match->init_data =
35175d6b2faSJavier Martinez Canillas 				of_get_regulator_init_data(dev, child,
35275d6b2faSJavier Martinez Canillas 							   match->desc);
3531c8fa58fSThierry Reding 			if (!match->init_data) {
3545260cd2bSLaxman Dewangan 				dev_err(dev,
3550c9721a5SRob Herring 					"failed to parse DT for regulator %pOFn\n",
3560c9721a5SRob Herring 					child);
35730966861SChristophe JAILLET 				of_node_put(child);
3581c8fa58fSThierry Reding 				return -EINVAL;
3591c8fa58fSThierry Reding 			}
360bd0dda74SCharles Keepax 			match->of_node = of_node_get(child);
3611c8fa58fSThierry Reding 			count++;
3625260cd2bSLaxman Dewangan 			break;
3635260cd2bSLaxman Dewangan 		}
3641c8fa58fSThierry Reding 	}
3651c8fa58fSThierry Reding 
3661c8fa58fSThierry Reding 	return count;
3671c8fa58fSThierry Reding }
3681c8fa58fSThierry Reding EXPORT_SYMBOL_GPL(of_regulator_match);
369a0c7b164SMark Brown 
3707a67eb1dSYueHaibing static struct
3717a67eb1dSYueHaibing device_node *regulator_of_get_init_node(struct device *dev,
372925c85e2SCharles Keepax 					const struct regulator_desc *desc)
373a0c7b164SMark Brown {
374a0c7b164SMark Brown 	struct device_node *search, *child;
375a0c7b164SMark Brown 	const char *name;
376a0c7b164SMark Brown 
377a0c7b164SMark Brown 	if (!dev->of_node || !desc->of_match)
378a0c7b164SMark Brown 		return NULL;
379a0c7b164SMark Brown 
380eba9473fSCharles Keepax 	if (desc->regulators_node) {
381a0c7b164SMark Brown 		search = of_get_child_by_name(dev->of_node,
382a0c7b164SMark Brown 					      desc->regulators_node);
383eba9473fSCharles Keepax 	} else {
384423a1164SFrank Rowand 		search = of_node_get(dev->of_node);
385a0c7b164SMark Brown 
386eba9473fSCharles Keepax 		if (!strcmp(desc->of_match, search->name))
387eba9473fSCharles Keepax 			return search;
388eba9473fSCharles Keepax 	}
389eba9473fSCharles Keepax 
390a0c7b164SMark Brown 	if (!search) {
3917de79a1dSMark Brown 		dev_dbg(dev, "Failed to find regulator container node '%s'\n",
3927de79a1dSMark Brown 			desc->regulators_node);
393a0c7b164SMark Brown 		return NULL;
394a0c7b164SMark Brown 	}
395a0c7b164SMark Brown 
396130daa3fSStephen Boyd 	for_each_available_child_of_node(search, child) {
397a0c7b164SMark Brown 		name = of_get_property(child, "regulator-compatible", NULL);
398a0c7b164SMark Brown 		if (!name)
399a0c7b164SMark Brown 			name = child->name;
400a0c7b164SMark Brown 
401925c85e2SCharles Keepax 		if (!strcmp(desc->of_match, name))
402925c85e2SCharles Keepax 			return of_node_get(child);
403a0c7b164SMark Brown 	}
404a0c7b164SMark Brown 
405a0c7b164SMark Brown 	of_node_put(search);
406a0c7b164SMark Brown 
407925c85e2SCharles Keepax 	return NULL;
408925c85e2SCharles Keepax }
409925c85e2SCharles Keepax 
410925c85e2SCharles Keepax struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
411925c85e2SCharles Keepax 					    const struct regulator_desc *desc,
412925c85e2SCharles Keepax 					    struct regulator_config *config,
413925c85e2SCharles Keepax 					    struct device_node **node)
414925c85e2SCharles Keepax {
415925c85e2SCharles Keepax 	struct device_node *child;
416925c85e2SCharles Keepax 	struct regulator_init_data *init_data = NULL;
417925c85e2SCharles Keepax 
418925c85e2SCharles Keepax 	child = regulator_of_get_init_node(dev, desc);
419925c85e2SCharles Keepax 	if (!child)
420925c85e2SCharles Keepax 		return NULL;
421925c85e2SCharles Keepax 
422925c85e2SCharles Keepax 	init_data = of_get_regulator_init_data(dev, child, desc);
423925c85e2SCharles Keepax 	if (!init_data) {
424925c85e2SCharles Keepax 		dev_err(dev, "failed to parse DT for regulator %pOFn\n", child);
425925c85e2SCharles Keepax 		goto error;
426925c85e2SCharles Keepax 	}
427925c85e2SCharles Keepax 
428925c85e2SCharles Keepax 	if (desc->of_parse_cb && desc->of_parse_cb(child, desc, config)) {
429925c85e2SCharles Keepax 		dev_err(dev,
430925c85e2SCharles Keepax 			"driver callback failed to parse DT for regulator %pOFn\n",
431925c85e2SCharles Keepax 			child);
432925c85e2SCharles Keepax 		goto error;
433925c85e2SCharles Keepax 	}
434925c85e2SCharles Keepax 
435925c85e2SCharles Keepax 	*node = child;
436925c85e2SCharles Keepax 
437a0c7b164SMark Brown 	return init_data;
438925c85e2SCharles Keepax 
439925c85e2SCharles Keepax error:
440925c85e2SCharles Keepax 	of_node_put(child);
441925c85e2SCharles Keepax 
442925c85e2SCharles Keepax 	return NULL;
443a0c7b164SMark Brown }
444148096afSMaciej Purski 
445148096afSMaciej Purski static int of_node_match(struct device *dev, const void *data)
446148096afSMaciej Purski {
447148096afSMaciej Purski 	return dev->of_node == data;
448148096afSMaciej Purski }
449148096afSMaciej Purski 
450148096afSMaciej Purski struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
451148096afSMaciej Purski {
452148096afSMaciej Purski 	struct device *dev;
453148096afSMaciej Purski 
454148096afSMaciej Purski 	dev = class_find_device(&regulator_class, NULL, np, of_node_match);
455148096afSMaciej Purski 
456148096afSMaciej Purski 	return dev ? dev_to_rdev(dev) : NULL;
457148096afSMaciej Purski }
458a085a31aSMaciej Purski 
459a085a31aSMaciej Purski /*
460a085a31aSMaciej Purski  * Returns number of regulators coupled with rdev.
461a085a31aSMaciej Purski  */
462a085a31aSMaciej Purski int of_get_n_coupled(struct regulator_dev *rdev)
463a085a31aSMaciej Purski {
464a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
465a085a31aSMaciej Purski 	int n_phandles;
466a085a31aSMaciej Purski 
467a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(node,
468a085a31aSMaciej Purski 						"regulator-coupled-with",
469a085a31aSMaciej Purski 						NULL);
470a085a31aSMaciej Purski 
471a085a31aSMaciej Purski 	return (n_phandles > 0) ? n_phandles : 0;
472a085a31aSMaciej Purski }
473a085a31aSMaciej Purski 
474a085a31aSMaciej Purski /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
475a085a31aSMaciej Purski static bool of_coupling_find_node(struct device_node *src,
476a085a31aSMaciej Purski 				  struct device_node *to_find)
477a085a31aSMaciej Purski {
478a085a31aSMaciej Purski 	int n_phandles, i;
479a085a31aSMaciej Purski 	bool found = false;
480a085a31aSMaciej Purski 
481a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(src,
482a085a31aSMaciej Purski 						"regulator-coupled-with",
483a085a31aSMaciej Purski 						NULL);
484a085a31aSMaciej Purski 
485a085a31aSMaciej Purski 	for (i = 0; i < n_phandles; i++) {
486a085a31aSMaciej Purski 		struct device_node *tmp = of_parse_phandle(src,
487a085a31aSMaciej Purski 					   "regulator-coupled-with", i);
488a085a31aSMaciej Purski 
489a085a31aSMaciej Purski 		if (!tmp)
490a085a31aSMaciej Purski 			break;
491a085a31aSMaciej Purski 
492a085a31aSMaciej Purski 		/* found */
493a085a31aSMaciej Purski 		if (tmp == to_find)
494a085a31aSMaciej Purski 			found = true;
495a085a31aSMaciej Purski 
496a085a31aSMaciej Purski 		of_node_put(tmp);
497a085a31aSMaciej Purski 
498a085a31aSMaciej Purski 		if (found)
499a085a31aSMaciej Purski 			break;
500a085a31aSMaciej Purski 	}
501a085a31aSMaciej Purski 
502a085a31aSMaciej Purski 	return found;
503a085a31aSMaciej Purski }
504a085a31aSMaciej Purski 
505a085a31aSMaciej Purski /**
506a085a31aSMaciej Purski  * of_check_coupling_data - Parse rdev's coupling properties and check data
507a085a31aSMaciej Purski  *			    consistency
508a085a31aSMaciej Purski  * @rdev - pointer to regulator_dev whose data is checked
509a085a31aSMaciej Purski  *
510a085a31aSMaciej Purski  * Function checks if all the following conditions are met:
511a085a31aSMaciej Purski  * - rdev's max_spread is greater than 0
512a085a31aSMaciej Purski  * - all coupled regulators have the same max_spread
513a085a31aSMaciej Purski  * - all coupled regulators have the same number of regulator_dev phandles
514a085a31aSMaciej Purski  * - all regulators are linked to each other
515a085a31aSMaciej Purski  *
516a085a31aSMaciej Purski  * Returns true if all conditions are met.
517a085a31aSMaciej Purski  */
518a085a31aSMaciej Purski bool of_check_coupling_data(struct regulator_dev *rdev)
519a085a31aSMaciej Purski {
520a085a31aSMaciej Purski 	int max_spread = rdev->constraints->max_spread;
521a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
522a085a31aSMaciej Purski 	int n_phandles = of_get_n_coupled(rdev);
523a085a31aSMaciej Purski 	struct device_node *c_node;
524a085a31aSMaciej Purski 	int i;
525a085a31aSMaciej Purski 	bool ret = true;
526a085a31aSMaciej Purski 
527a085a31aSMaciej Purski 	if (max_spread <= 0) {
528a085a31aSMaciej Purski 		dev_err(&rdev->dev, "max_spread value invalid\n");
529a085a31aSMaciej Purski 		return false;
530a085a31aSMaciej Purski 	}
531a085a31aSMaciej Purski 
532a085a31aSMaciej Purski 	/* iterate over rdev's phandles */
533a085a31aSMaciej Purski 	for (i = 0; i < n_phandles; i++) {
534a085a31aSMaciej Purski 		int c_max_spread, c_n_phandles;
535a085a31aSMaciej Purski 
536a085a31aSMaciej Purski 		c_node = of_parse_phandle(node,
537a085a31aSMaciej Purski 					  "regulator-coupled-with", i);
538a085a31aSMaciej Purski 
539a085a31aSMaciej Purski 		if (!c_node)
540a085a31aSMaciej Purski 			ret = false;
541a085a31aSMaciej Purski 
542a085a31aSMaciej Purski 		c_n_phandles = of_count_phandle_with_args(c_node,
543a085a31aSMaciej Purski 							  "regulator-coupled-with",
544a085a31aSMaciej Purski 							  NULL);
545a085a31aSMaciej Purski 
546a085a31aSMaciej Purski 		if (c_n_phandles != n_phandles) {
54748f1b4efSKrzysztof Kozlowski 			dev_err(&rdev->dev, "number of coupled reg phandles mismatch\n");
548a085a31aSMaciej Purski 			ret = false;
549a085a31aSMaciej Purski 			goto clean;
550a085a31aSMaciej Purski 		}
551a085a31aSMaciej Purski 
552a085a31aSMaciej Purski 		if (of_property_read_u32(c_node, "regulator-coupled-max-spread",
553a085a31aSMaciej Purski 					 &c_max_spread)) {
554a085a31aSMaciej Purski 			ret = false;
555a085a31aSMaciej Purski 			goto clean;
556a085a31aSMaciej Purski 		}
557a085a31aSMaciej Purski 
558a085a31aSMaciej Purski 		if (c_max_spread != max_spread) {
559a085a31aSMaciej Purski 			dev_err(&rdev->dev,
560a085a31aSMaciej Purski 				"coupled regulators max_spread mismatch\n");
561a085a31aSMaciej Purski 			ret = false;
562a085a31aSMaciej Purski 			goto clean;
563a085a31aSMaciej Purski 		}
564a085a31aSMaciej Purski 
565a085a31aSMaciej Purski 		if (!of_coupling_find_node(c_node, node)) {
566a085a31aSMaciej Purski 			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
567a085a31aSMaciej Purski 			ret = false;
568a085a31aSMaciej Purski 		}
569a085a31aSMaciej Purski 
570a085a31aSMaciej Purski clean:
571a085a31aSMaciej Purski 		of_node_put(c_node);
572a085a31aSMaciej Purski 		if (!ret)
573a085a31aSMaciej Purski 			break;
574a085a31aSMaciej Purski 	}
575a085a31aSMaciej Purski 
576a085a31aSMaciej Purski 	return ret;
577a085a31aSMaciej Purski }
578a085a31aSMaciej Purski 
579a085a31aSMaciej Purski /**
580a085a31aSMaciej Purski  * of_parse_coupled regulator - Get regulator_dev pointer from rdev's property
581a085a31aSMaciej Purski  * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse
582a085a31aSMaciej Purski  *	  "regulator-coupled-with" property
583a085a31aSMaciej Purski  * @index: Index in phandles array
584a085a31aSMaciej Purski  *
585a085a31aSMaciej Purski  * Returns the regulator_dev pointer parsed from DTS. If it has not been yet
586a085a31aSMaciej Purski  * registered, returns NULL
587a085a31aSMaciej Purski  */
588a085a31aSMaciej Purski struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev,
589a085a31aSMaciej Purski 						 int index)
590a085a31aSMaciej Purski {
591a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
592a085a31aSMaciej Purski 	struct device_node *c_node;
593a085a31aSMaciej Purski 	struct regulator_dev *c_rdev;
594a085a31aSMaciej Purski 
595a085a31aSMaciej Purski 	c_node = of_parse_phandle(node, "regulator-coupled-with", index);
596a085a31aSMaciej Purski 	if (!c_node)
597a085a31aSMaciej Purski 		return NULL;
598a085a31aSMaciej Purski 
599a085a31aSMaciej Purski 	c_rdev = of_find_regulator_by_node(c_node);
600a085a31aSMaciej Purski 
601a085a31aSMaciej Purski 	of_node_put(c_node);
602a085a31aSMaciej Purski 
603a085a31aSMaciej Purski 	return c_rdev;
604a085a31aSMaciej Purski }
605