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] = {
23f2b40769SAndrei.Stefanescu@microchip.com 	[PM_SUSPEND_STANDBY]	= "regulator-state-standby",
2440e20d68SChanwoo Choi 	[PM_SUSPEND_MEM]	= "regulator-state-mem",
2540e20d68SChanwoo Choi 	[PM_SUSPEND_MAX]	= "regulator-state-disk",
2640e20d68SChanwoo Choi };
2740e20d68SChanwoo Choi 
288f446e6fSRajendra Nayak static void of_get_regulation_constraints(struct device_node *np,
295e5e3a42SJavier Martinez Canillas 					struct regulator_init_data **init_data,
305e5e3a42SJavier Martinez Canillas 					const struct regulator_desc *desc)
318f446e6fSRajendra Nayak {
328f446e6fSRajendra Nayak 	struct regulation_constraints *constraints = &(*init_data)->constraints;
3340e20d68SChanwoo Choi 	struct regulator_state *suspend_state;
3440e20d68SChanwoo Choi 	struct device_node *suspend_np;
3502f37039SDouglas Anderson 	unsigned int mode;
3654557ad9SDavid Collins 	int ret, i, len;
3700c877c6SLaxman Dewangan 	u32 pval;
388f446e6fSRajendra Nayak 
398f446e6fSRajendra Nayak 	constraints->name = of_get_property(np, "regulator-name", NULL);
408f446e6fSRajendra Nayak 
41a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
42a34785f1SLaxman Dewangan 		constraints->min_uV = pval;
43a34785f1SLaxman Dewangan 
44a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
45a34785f1SLaxman Dewangan 		constraints->max_uV = pval;
468f446e6fSRajendra Nayak 
478f446e6fSRajendra Nayak 	/* Voltage change possible? */
4845fa2038SMark Brown 	if (constraints->min_uV != constraints->max_uV)
498f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
5045fa2038SMark Brown 
5145fa2038SMark Brown 	/* Do we have a voltage range, if so try to apply it? */
5245fa2038SMark Brown 	if (constraints->min_uV && constraints->max_uV)
53ab62aa93SMark Brown 		constraints->apply_uV = true;
548f446e6fSRajendra Nayak 
551e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
561e050eabSSergei Shtylyov 		constraints->uV_offset = pval;
571e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
581e050eabSSergei Shtylyov 		constraints->min_uA = pval;
591e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
601e050eabSSergei Shtylyov 		constraints->max_uA = pval;
618f446e6fSRajendra Nayak 
6236e4f839SStephen Boyd 	if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
6336e4f839SStephen Boyd 				  &pval))
6436e4f839SStephen Boyd 		constraints->ilim_uA = pval;
6536e4f839SStephen Boyd 
668f446e6fSRajendra Nayak 	/* Current change possible? */
678f446e6fSRajendra Nayak 	if (constraints->min_uA != constraints->max_uA)
688f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
698f446e6fSRajendra Nayak 
701e050eabSSergei Shtylyov 	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
711e050eabSSergei Shtylyov 	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
721e050eabSSergei Shtylyov 	if (!constraints->always_on) /* status change should be possible. */
738f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
746f0b2c69SYadwinder Singh Brar 
7523c779b9SStephen Boyd 	constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
7623c779b9SStephen Boyd 
7793134c7bSKishon Vijay Abraham I 	if (of_property_read_bool(np, "regulator-allow-bypass"))
7893134c7bSKishon Vijay Abraham I 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
7993134c7bSKishon Vijay Abraham I 
80b263d203SBjorn Andersson 	if (of_property_read_bool(np, "regulator-allow-set-load"))
81b263d203SBjorn Andersson 		constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
82b263d203SBjorn Andersson 
831e050eabSSergei Shtylyov 	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
841e050eabSSergei Shtylyov 	if (!ret) {
851e050eabSSergei Shtylyov 		if (pval)
861e050eabSSergei Shtylyov 			constraints->ramp_delay = pval;
871653ccf4SYadwinder Singh Brar 		else
881653ccf4SYadwinder Singh Brar 			constraints->ramp_disable = true;
891653ccf4SYadwinder Singh Brar 	}
9000c877c6SLaxman Dewangan 
91d6c1dc3fSLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
92d6c1dc3fSLaxman Dewangan 	if (!ret)
93d6c1dc3fSLaxman Dewangan 		constraints->settling_time = pval;
94d6c1dc3fSLaxman Dewangan 
953ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
963ffad468SMatthias Kaehlcke 	if (!ret)
973ffad468SMatthias Kaehlcke 		constraints->settling_time_up = pval;
983ffad468SMatthias Kaehlcke 	if (constraints->settling_time_up && constraints->settling_time) {
990c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
1000c9721a5SRob Herring 			np);
1013ffad468SMatthias Kaehlcke 		constraints->settling_time_up = 0;
1023ffad468SMatthias Kaehlcke 	}
1033ffad468SMatthias Kaehlcke 
1043ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-down-us",
1053ffad468SMatthias Kaehlcke 				   &pval);
1063ffad468SMatthias Kaehlcke 	if (!ret)
1073ffad468SMatthias Kaehlcke 		constraints->settling_time_down = pval;
1083ffad468SMatthias Kaehlcke 	if (constraints->settling_time_down && constraints->settling_time) {
1090c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
1100c9721a5SRob Herring 			np);
1113ffad468SMatthias Kaehlcke 		constraints->settling_time_down = 0;
1123ffad468SMatthias Kaehlcke 	}
1133ffad468SMatthias Kaehlcke 
11400c877c6SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
11500c877c6SLaxman Dewangan 	if (!ret)
11600c877c6SLaxman Dewangan 		constraints->enable_time = pval;
11740e20d68SChanwoo Choi 
11857f66b78SStephen Boyd 	constraints->soft_start = of_property_read_bool(np,
11957f66b78SStephen Boyd 					"regulator-soft-start");
120670666b9SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
121670666b9SLaxman Dewangan 	if (!ret) {
122670666b9SLaxman Dewangan 		constraints->active_discharge =
123670666b9SLaxman Dewangan 				(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
124670666b9SLaxman Dewangan 					REGULATOR_ACTIVE_DISCHARGE_DISABLE;
125670666b9SLaxman Dewangan 	}
12657f66b78SStephen Boyd 
1275e5e3a42SJavier Martinez Canillas 	if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
1285e5e3a42SJavier Martinez Canillas 		if (desc && desc->of_map_mode) {
12902f37039SDouglas Anderson 			mode = desc->of_map_mode(pval);
13002f37039SDouglas Anderson 			if (mode == REGULATOR_MODE_INVALID)
1310c9721a5SRob Herring 				pr_err("%pOFn: invalid mode %u\n", np, pval);
1325e5e3a42SJavier Martinez Canillas 			else
13302f37039SDouglas Anderson 				constraints->initial_mode = mode;
1345e5e3a42SJavier Martinez Canillas 		} else {
1350c9721a5SRob Herring 			pr_warn("%pOFn: mapping for mode %d not defined\n",
1360c9721a5SRob Herring 				np, pval);
1375e5e3a42SJavier Martinez Canillas 		}
1385e5e3a42SJavier Martinez Canillas 	}
1395e5e3a42SJavier Martinez Canillas 
14054557ad9SDavid Collins 	len = of_property_count_elems_of_size(np, "regulator-allowed-modes",
14154557ad9SDavid Collins 						sizeof(u32));
14254557ad9SDavid Collins 	if (len > 0) {
14354557ad9SDavid Collins 		if (desc && desc->of_map_mode) {
14454557ad9SDavid Collins 			for (i = 0; i < len; i++) {
14554557ad9SDavid Collins 				ret = of_property_read_u32_index(np,
14654557ad9SDavid Collins 					"regulator-allowed-modes", i, &pval);
14754557ad9SDavid Collins 				if (ret) {
1480c9721a5SRob Herring 					pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
1490c9721a5SRob Herring 						np, i, ret);
15054557ad9SDavid Collins 					break;
15154557ad9SDavid Collins 				}
15254557ad9SDavid Collins 				mode = desc->of_map_mode(pval);
15354557ad9SDavid Collins 				if (mode == REGULATOR_MODE_INVALID)
1540c9721a5SRob Herring 					pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
1550c9721a5SRob Herring 						np, pval);
15654557ad9SDavid Collins 				else
15754557ad9SDavid Collins 					constraints->valid_modes_mask |= mode;
15854557ad9SDavid Collins 			}
15954557ad9SDavid Collins 			if (constraints->valid_modes_mask)
16054557ad9SDavid Collins 				constraints->valid_ops_mask
16154557ad9SDavid Collins 					|= REGULATOR_CHANGE_MODE;
16254557ad9SDavid Collins 		} else {
1630c9721a5SRob Herring 			pr_warn("%pOFn: mode mapping not defined\n", np);
16454557ad9SDavid Collins 		}
16554557ad9SDavid Collins 	}
16654557ad9SDavid Collins 
16722a10bcaSStephen Boyd 	if (!of_property_read_u32(np, "regulator-system-load", &pval))
16822a10bcaSStephen Boyd 		constraints->system_load = pval;
16922a10bcaSStephen Boyd 
170a085a31aSMaciej Purski 	if (!of_property_read_u32(np, "regulator-coupled-max-spread",
171a085a31aSMaciej Purski 				  &pval))
172a085a31aSMaciej Purski 		constraints->max_spread = pval;
173a085a31aSMaciej Purski 
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
2548f446e6fSRajendra Nayak  * tree node, returns a pointer to the populated struture 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 
370a0c7b164SMark Brown struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
371a0c7b164SMark Brown 					    const struct regulator_desc *desc,
372bfa21a0dSKrzysztof Kozlowski 					    struct regulator_config *config,
373a0c7b164SMark Brown 					    struct device_node **node)
374a0c7b164SMark Brown {
375a0c7b164SMark Brown 	struct device_node *search, *child;
376a0c7b164SMark Brown 	struct regulator_init_data *init_data = NULL;
377a0c7b164SMark Brown 	const char *name;
378a0c7b164SMark Brown 
379a0c7b164SMark Brown 	if (!dev->of_node || !desc->of_match)
380a0c7b164SMark Brown 		return NULL;
381a0c7b164SMark Brown 
382a0c7b164SMark Brown 	if (desc->regulators_node)
383a0c7b164SMark Brown 		search = of_get_child_by_name(dev->of_node,
384a0c7b164SMark Brown 					      desc->regulators_node);
385a0c7b164SMark Brown 	else
386423a1164SFrank Rowand 		search = of_node_get(dev->of_node);
387a0c7b164SMark Brown 
388a0c7b164SMark Brown 	if (!search) {
3897de79a1dSMark Brown 		dev_dbg(dev, "Failed to find regulator container node '%s'\n",
3907de79a1dSMark Brown 			desc->regulators_node);
391a0c7b164SMark Brown 		return NULL;
392a0c7b164SMark Brown 	}
393a0c7b164SMark Brown 
394130daa3fSStephen Boyd 	for_each_available_child_of_node(search, child) {
395a0c7b164SMark Brown 		name = of_get_property(child, "regulator-compatible", NULL);
396a0c7b164SMark Brown 		if (!name)
397a0c7b164SMark Brown 			name = child->name;
398a0c7b164SMark Brown 
399a0c7b164SMark Brown 		if (strcmp(desc->of_match, name))
400a0c7b164SMark Brown 			continue;
401a0c7b164SMark Brown 
402072e78b1SJavier Martinez Canillas 		init_data = of_get_regulator_init_data(dev, child, desc);
403a0c7b164SMark Brown 		if (!init_data) {
404a0c7b164SMark Brown 			dev_err(dev,
4050c9721a5SRob Herring 				"failed to parse DT for regulator %pOFn\n",
4060c9721a5SRob Herring 				child);
407a0c7b164SMark Brown 			break;
408a0c7b164SMark Brown 		}
409a0c7b164SMark Brown 
410bfa21a0dSKrzysztof Kozlowski 		if (desc->of_parse_cb) {
411bfa21a0dSKrzysztof Kozlowski 			if (desc->of_parse_cb(child, desc, config)) {
412bfa21a0dSKrzysztof Kozlowski 				dev_err(dev,
4130c9721a5SRob Herring 					"driver callback failed to parse DT for regulator %pOFn\n",
4140c9721a5SRob Herring 					child);
415bfa21a0dSKrzysztof Kozlowski 				init_data = NULL;
416bfa21a0dSKrzysztof Kozlowski 				break;
417bfa21a0dSKrzysztof Kozlowski 			}
418bfa21a0dSKrzysztof Kozlowski 		}
419bfa21a0dSKrzysztof Kozlowski 
420a0c7b164SMark Brown 		of_node_get(child);
421a0c7b164SMark Brown 		*node = child;
422a0c7b164SMark Brown 		break;
423a0c7b164SMark Brown 	}
424a0c7b164SMark Brown 
425a0c7b164SMark Brown 	of_node_put(search);
426a0c7b164SMark Brown 
427a0c7b164SMark Brown 	return init_data;
428a0c7b164SMark Brown }
429148096afSMaciej Purski 
430148096afSMaciej Purski static int of_node_match(struct device *dev, const void *data)
431148096afSMaciej Purski {
432148096afSMaciej Purski 	return dev->of_node == data;
433148096afSMaciej Purski }
434148096afSMaciej Purski 
435148096afSMaciej Purski struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
436148096afSMaciej Purski {
437148096afSMaciej Purski 	struct device *dev;
438148096afSMaciej Purski 
439148096afSMaciej Purski 	dev = class_find_device(&regulator_class, NULL, np, of_node_match);
440148096afSMaciej Purski 
441148096afSMaciej Purski 	return dev ? dev_to_rdev(dev) : NULL;
442148096afSMaciej Purski }
443a085a31aSMaciej Purski 
444a085a31aSMaciej Purski /*
445a085a31aSMaciej Purski  * Returns number of regulators coupled with rdev.
446a085a31aSMaciej Purski  */
447a085a31aSMaciej Purski int of_get_n_coupled(struct regulator_dev *rdev)
448a085a31aSMaciej Purski {
449a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
450a085a31aSMaciej Purski 	int n_phandles;
451a085a31aSMaciej Purski 
452a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(node,
453a085a31aSMaciej Purski 						"regulator-coupled-with",
454a085a31aSMaciej Purski 						NULL);
455a085a31aSMaciej Purski 
456a085a31aSMaciej Purski 	return (n_phandles > 0) ? n_phandles : 0;
457a085a31aSMaciej Purski }
458a085a31aSMaciej Purski 
459a085a31aSMaciej Purski /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
460a085a31aSMaciej Purski static bool of_coupling_find_node(struct device_node *src,
461a085a31aSMaciej Purski 				  struct device_node *to_find)
462a085a31aSMaciej Purski {
463a085a31aSMaciej Purski 	int n_phandles, i;
464a085a31aSMaciej Purski 	bool found = false;
465a085a31aSMaciej Purski 
466a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(src,
467a085a31aSMaciej Purski 						"regulator-coupled-with",
468a085a31aSMaciej Purski 						NULL);
469a085a31aSMaciej Purski 
470a085a31aSMaciej Purski 	for (i = 0; i < n_phandles; i++) {
471a085a31aSMaciej Purski 		struct device_node *tmp = of_parse_phandle(src,
472a085a31aSMaciej Purski 					   "regulator-coupled-with", i);
473a085a31aSMaciej Purski 
474a085a31aSMaciej Purski 		if (!tmp)
475a085a31aSMaciej Purski 			break;
476a085a31aSMaciej Purski 
477a085a31aSMaciej Purski 		/* found */
478a085a31aSMaciej Purski 		if (tmp == to_find)
479a085a31aSMaciej Purski 			found = true;
480a085a31aSMaciej Purski 
481a085a31aSMaciej Purski 		of_node_put(tmp);
482a085a31aSMaciej Purski 
483a085a31aSMaciej Purski 		if (found)
484a085a31aSMaciej Purski 			break;
485a085a31aSMaciej Purski 	}
486a085a31aSMaciej Purski 
487a085a31aSMaciej Purski 	return found;
488a085a31aSMaciej Purski }
489a085a31aSMaciej Purski 
490a085a31aSMaciej Purski /**
491a085a31aSMaciej Purski  * of_check_coupling_data - Parse rdev's coupling properties and check data
492a085a31aSMaciej Purski  *			    consistency
493a085a31aSMaciej Purski  * @rdev - pointer to regulator_dev whose data is checked
494a085a31aSMaciej Purski  *
495a085a31aSMaciej Purski  * Function checks if all the following conditions are met:
496a085a31aSMaciej Purski  * - rdev's max_spread is greater than 0
497a085a31aSMaciej Purski  * - all coupled regulators have the same max_spread
498a085a31aSMaciej Purski  * - all coupled regulators have the same number of regulator_dev phandles
499a085a31aSMaciej Purski  * - all regulators are linked to each other
500a085a31aSMaciej Purski  *
501a085a31aSMaciej Purski  * Returns true if all conditions are met.
502a085a31aSMaciej Purski  */
503a085a31aSMaciej Purski bool of_check_coupling_data(struct regulator_dev *rdev)
504a085a31aSMaciej Purski {
505a085a31aSMaciej Purski 	int max_spread = rdev->constraints->max_spread;
506a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
507a085a31aSMaciej Purski 	int n_phandles = of_get_n_coupled(rdev);
508a085a31aSMaciej Purski 	struct device_node *c_node;
509a085a31aSMaciej Purski 	int i;
510a085a31aSMaciej Purski 	bool ret = true;
511a085a31aSMaciej Purski 
512a085a31aSMaciej Purski 	if (max_spread <= 0) {
513a085a31aSMaciej Purski 		dev_err(&rdev->dev, "max_spread value invalid\n");
514a085a31aSMaciej Purski 		return false;
515a085a31aSMaciej Purski 	}
516a085a31aSMaciej Purski 
517a085a31aSMaciej Purski 	/* iterate over rdev's phandles */
518a085a31aSMaciej Purski 	for (i = 0; i < n_phandles; i++) {
519a085a31aSMaciej Purski 		int c_max_spread, c_n_phandles;
520a085a31aSMaciej Purski 
521a085a31aSMaciej Purski 		c_node = of_parse_phandle(node,
522a085a31aSMaciej Purski 					  "regulator-coupled-with", i);
523a085a31aSMaciej Purski 
524a085a31aSMaciej Purski 		if (!c_node)
525a085a31aSMaciej Purski 			ret = false;
526a085a31aSMaciej Purski 
527a085a31aSMaciej Purski 		c_n_phandles = of_count_phandle_with_args(c_node,
528a085a31aSMaciej Purski 							  "regulator-coupled-with",
529a085a31aSMaciej Purski 							  NULL);
530a085a31aSMaciej Purski 
531a085a31aSMaciej Purski 		if (c_n_phandles != n_phandles) {
532a085a31aSMaciej Purski 			dev_err(&rdev->dev, "number of couped reg phandles mismatch\n");
533a085a31aSMaciej Purski 			ret = false;
534a085a31aSMaciej Purski 			goto clean;
535a085a31aSMaciej Purski 		}
536a085a31aSMaciej Purski 
537a085a31aSMaciej Purski 		if (of_property_read_u32(c_node, "regulator-coupled-max-spread",
538a085a31aSMaciej Purski 					 &c_max_spread)) {
539a085a31aSMaciej Purski 			ret = false;
540a085a31aSMaciej Purski 			goto clean;
541a085a31aSMaciej Purski 		}
542a085a31aSMaciej Purski 
543a085a31aSMaciej Purski 		if (c_max_spread != max_spread) {
544a085a31aSMaciej Purski 			dev_err(&rdev->dev,
545a085a31aSMaciej Purski 				"coupled regulators max_spread mismatch\n");
546a085a31aSMaciej Purski 			ret = false;
547a085a31aSMaciej Purski 			goto clean;
548a085a31aSMaciej Purski 		}
549a085a31aSMaciej Purski 
550a085a31aSMaciej Purski 		if (!of_coupling_find_node(c_node, node)) {
551a085a31aSMaciej Purski 			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
552a085a31aSMaciej Purski 			ret = false;
553a085a31aSMaciej Purski 		}
554a085a31aSMaciej Purski 
555a085a31aSMaciej Purski clean:
556a085a31aSMaciej Purski 		of_node_put(c_node);
557a085a31aSMaciej Purski 		if (!ret)
558a085a31aSMaciej Purski 			break;
559a085a31aSMaciej Purski 	}
560a085a31aSMaciej Purski 
561a085a31aSMaciej Purski 	return ret;
562a085a31aSMaciej Purski }
563a085a31aSMaciej Purski 
564a085a31aSMaciej Purski /**
565a085a31aSMaciej Purski  * of_parse_coupled regulator - Get regulator_dev pointer from rdev's property
566a085a31aSMaciej Purski  * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse
567a085a31aSMaciej Purski  *	  "regulator-coupled-with" property
568a085a31aSMaciej Purski  * @index: Index in phandles array
569a085a31aSMaciej Purski  *
570a085a31aSMaciej Purski  * Returns the regulator_dev pointer parsed from DTS. If it has not been yet
571a085a31aSMaciej Purski  * registered, returns NULL
572a085a31aSMaciej Purski  */
573a085a31aSMaciej Purski struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev,
574a085a31aSMaciej Purski 						 int index)
575a085a31aSMaciej Purski {
576a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
577a085a31aSMaciej Purski 	struct device_node *c_node;
578a085a31aSMaciej Purski 	struct regulator_dev *c_rdev;
579a085a31aSMaciej Purski 
580a085a31aSMaciej Purski 	c_node = of_parse_phandle(node, "regulator-coupled-with", index);
581a085a31aSMaciej Purski 	if (!c_node)
582a085a31aSMaciej Purski 		return NULL;
583a085a31aSMaciej Purski 
584a085a31aSMaciej Purski 	c_rdev = of_find_regulator_by_node(c_node);
585a085a31aSMaciej Purski 
586a085a31aSMaciej Purski 	of_node_put(c_node);
587a085a31aSMaciej Purski 
588a085a31aSMaciej Purski 	return c_rdev;
589a085a31aSMaciej Purski }
590