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 
fill_limit(int * limit,int val)2489a6a5e5SMatti Vaittinen static void fill_limit(int *limit, int val)
2589a6a5e5SMatti Vaittinen {
2689a6a5e5SMatti Vaittinen 	if (val)
2789a6a5e5SMatti Vaittinen 		if (val == 1)
2889a6a5e5SMatti Vaittinen 			*limit = REGULATOR_NOTIF_LIMIT_ENABLE;
2989a6a5e5SMatti Vaittinen 		else
3089a6a5e5SMatti Vaittinen 			*limit = val;
3189a6a5e5SMatti Vaittinen 	else
3289a6a5e5SMatti Vaittinen 		*limit = REGULATOR_NOTIF_LIMIT_DISABLE;
3389a6a5e5SMatti Vaittinen }
3489a6a5e5SMatti Vaittinen 
of_get_regulator_prot_limits(struct device_node * np,struct regulation_constraints * constraints)3589a6a5e5SMatti Vaittinen static void of_get_regulator_prot_limits(struct device_node *np,
3689a6a5e5SMatti Vaittinen 				struct regulation_constraints *constraints)
3789a6a5e5SMatti Vaittinen {
3889a6a5e5SMatti Vaittinen 	u32 pval;
3989a6a5e5SMatti Vaittinen 	int i;
4089a6a5e5SMatti Vaittinen 	static const char *const props[] = {
4189a6a5e5SMatti Vaittinen 		"regulator-oc-%s-microamp",
4289a6a5e5SMatti Vaittinen 		"regulator-ov-%s-microvolt",
4389a6a5e5SMatti Vaittinen 		"regulator-temp-%s-kelvin",
4489a6a5e5SMatti Vaittinen 		"regulator-uv-%s-microvolt",
4589a6a5e5SMatti Vaittinen 	};
4689a6a5e5SMatti Vaittinen 	struct notification_limit *limits[] = {
4789a6a5e5SMatti Vaittinen 		&constraints->over_curr_limits,
4889a6a5e5SMatti Vaittinen 		&constraints->over_voltage_limits,
4989a6a5e5SMatti Vaittinen 		&constraints->temp_limits,
5089a6a5e5SMatti Vaittinen 		&constraints->under_voltage_limits,
5189a6a5e5SMatti Vaittinen 	};
5289a6a5e5SMatti Vaittinen 	bool set[4] = {0};
5389a6a5e5SMatti Vaittinen 
5489a6a5e5SMatti Vaittinen 	/* Protection limits: */
5589a6a5e5SMatti Vaittinen 	for (i = 0; i < ARRAY_SIZE(props); i++) {
5689a6a5e5SMatti Vaittinen 		char prop[255];
5789a6a5e5SMatti Vaittinen 		bool found;
5889a6a5e5SMatti Vaittinen 		int j;
5989a6a5e5SMatti Vaittinen 		static const char *const lvl[] = {
6089a6a5e5SMatti Vaittinen 			"protection", "error", "warn"
6189a6a5e5SMatti Vaittinen 		};
6289a6a5e5SMatti Vaittinen 		int *l[] = {
6389a6a5e5SMatti Vaittinen 			&limits[i]->prot, &limits[i]->err, &limits[i]->warn,
6489a6a5e5SMatti Vaittinen 		};
6589a6a5e5SMatti Vaittinen 
6689a6a5e5SMatti Vaittinen 		for (j = 0; j < ARRAY_SIZE(lvl); j++) {
6789a6a5e5SMatti Vaittinen 			snprintf(prop, 255, props[i], lvl[j]);
6889a6a5e5SMatti Vaittinen 			found = !of_property_read_u32(np, prop, &pval);
6989a6a5e5SMatti Vaittinen 			if (found)
7089a6a5e5SMatti Vaittinen 				fill_limit(l[j], pval);
7189a6a5e5SMatti Vaittinen 			set[i] |= found;
7289a6a5e5SMatti Vaittinen 		}
7389a6a5e5SMatti Vaittinen 	}
7489a6a5e5SMatti Vaittinen 	constraints->over_current_detection = set[0];
7589a6a5e5SMatti Vaittinen 	constraints->over_voltage_detection = set[1];
7689a6a5e5SMatti Vaittinen 	constraints->over_temp_detection = set[2];
7789a6a5e5SMatti Vaittinen 	constraints->under_voltage_detection = set[3];
7889a6a5e5SMatti Vaittinen }
7989a6a5e5SMatti Vaittinen 
of_get_regulation_constraints(struct device * dev,struct device_node * np,struct regulator_init_data ** init_data,const struct regulator_desc * desc)80d8ca7d18SDmitry Osipenko static int of_get_regulation_constraints(struct device *dev,
81d8ca7d18SDmitry Osipenko 					struct device_node *np,
825e5e3a42SJavier Martinez Canillas 					struct regulator_init_data **init_data,
835e5e3a42SJavier Martinez Canillas 					const struct regulator_desc *desc)
848f446e6fSRajendra Nayak {
858f446e6fSRajendra Nayak 	struct regulation_constraints *constraints = &(*init_data)->constraints;
8640e20d68SChanwoo Choi 	struct regulator_state *suspend_state;
8740e20d68SChanwoo Choi 	struct device_node *suspend_np;
8802f37039SDouglas Anderson 	unsigned int mode;
8954557ad9SDavid Collins 	int ret, i, len;
90d8ca7d18SDmitry Osipenko 	int n_phandles;
9100c877c6SLaxman Dewangan 	u32 pval;
928f446e6fSRajendra Nayak 
93d8ca7d18SDmitry Osipenko 	n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with",
94d8ca7d18SDmitry Osipenko 						NULL);
95d8ca7d18SDmitry Osipenko 	n_phandles = max(n_phandles, 0);
96d8ca7d18SDmitry Osipenko 
978f446e6fSRajendra Nayak 	constraints->name = of_get_property(np, "regulator-name", NULL);
988f446e6fSRajendra Nayak 
99a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
100a34785f1SLaxman Dewangan 		constraints->min_uV = pval;
101a34785f1SLaxman Dewangan 
102a34785f1SLaxman Dewangan 	if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
103a34785f1SLaxman Dewangan 		constraints->max_uV = pval;
1048f446e6fSRajendra Nayak 
1058f446e6fSRajendra Nayak 	/* Voltage change possible? */
10645fa2038SMark Brown 	if (constraints->min_uV != constraints->max_uV)
1078f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
10845fa2038SMark Brown 
10945fa2038SMark Brown 	/* Do we have a voltage range, if so try to apply it? */
11045fa2038SMark Brown 	if (constraints->min_uV && constraints->max_uV)
111ab62aa93SMark Brown 		constraints->apply_uV = true;
1128f446e6fSRajendra Nayak 
1131e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
1141e050eabSSergei Shtylyov 		constraints->uV_offset = pval;
1151e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
1161e050eabSSergei Shtylyov 		constraints->min_uA = pval;
1171e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
1181e050eabSSergei Shtylyov 		constraints->max_uA = pval;
1198f446e6fSRajendra Nayak 
12036e4f839SStephen Boyd 	if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
12136e4f839SStephen Boyd 				  &pval))
12236e4f839SStephen Boyd 		constraints->ilim_uA = pval;
12336e4f839SStephen Boyd 
1248f446e6fSRajendra Nayak 	/* Current change possible? */
1258f446e6fSRajendra Nayak 	if (constraints->min_uA != constraints->max_uA)
1268f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
1278f446e6fSRajendra Nayak 
1281e050eabSSergei Shtylyov 	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
1291e050eabSSergei Shtylyov 	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
1301e050eabSSergei Shtylyov 	if (!constraints->always_on) /* status change should be possible. */
1318f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
1326f0b2c69SYadwinder Singh Brar 
13323c779b9SStephen Boyd 	constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
13423c779b9SStephen Boyd 
13593134c7bSKishon Vijay Abraham I 	if (of_property_read_bool(np, "regulator-allow-bypass"))
13693134c7bSKishon Vijay Abraham I 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
13793134c7bSKishon Vijay Abraham I 
138b263d203SBjorn Andersson 	if (of_property_read_bool(np, "regulator-allow-set-load"))
139b263d203SBjorn Andersson 		constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
140b263d203SBjorn Andersson 
1411e050eabSSergei Shtylyov 	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
1421e050eabSSergei Shtylyov 	if (!ret) {
1431e050eabSSergei Shtylyov 		if (pval)
1441e050eabSSergei Shtylyov 			constraints->ramp_delay = pval;
1451653ccf4SYadwinder Singh Brar 		else
1461653ccf4SYadwinder Singh Brar 			constraints->ramp_disable = true;
1471653ccf4SYadwinder Singh Brar 	}
14800c877c6SLaxman Dewangan 
149d6c1dc3fSLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
150d6c1dc3fSLaxman Dewangan 	if (!ret)
151d6c1dc3fSLaxman Dewangan 		constraints->settling_time = pval;
152d6c1dc3fSLaxman Dewangan 
1533ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
1543ffad468SMatthias Kaehlcke 	if (!ret)
1553ffad468SMatthias Kaehlcke 		constraints->settling_time_up = pval;
1563ffad468SMatthias Kaehlcke 	if (constraints->settling_time_up && constraints->settling_time) {
1570c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n",
1580c9721a5SRob Herring 			np);
1593ffad468SMatthias Kaehlcke 		constraints->settling_time_up = 0;
1603ffad468SMatthias Kaehlcke 	}
1613ffad468SMatthias Kaehlcke 
1623ffad468SMatthias Kaehlcke 	ret = of_property_read_u32(np, "regulator-settling-time-down-us",
1633ffad468SMatthias Kaehlcke 				   &pval);
1643ffad468SMatthias Kaehlcke 	if (!ret)
1653ffad468SMatthias Kaehlcke 		constraints->settling_time_down = pval;
1663ffad468SMatthias Kaehlcke 	if (constraints->settling_time_down && constraints->settling_time) {
1670c9721a5SRob Herring 		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n",
1680c9721a5SRob Herring 			np);
1693ffad468SMatthias Kaehlcke 		constraints->settling_time_down = 0;
1703ffad468SMatthias Kaehlcke 	}
1713ffad468SMatthias Kaehlcke 
17200c877c6SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
17300c877c6SLaxman Dewangan 	if (!ret)
17400c877c6SLaxman Dewangan 		constraints->enable_time = pval;
17540e20d68SChanwoo Choi 
17657f66b78SStephen Boyd 	constraints->soft_start = of_property_read_bool(np,
17757f66b78SStephen Boyd 					"regulator-soft-start");
178670666b9SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
179670666b9SLaxman Dewangan 	if (!ret) {
180670666b9SLaxman Dewangan 		constraints->active_discharge =
181670666b9SLaxman Dewangan 				(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
182670666b9SLaxman Dewangan 					REGULATOR_ACTIVE_DISCHARGE_DISABLE;
183670666b9SLaxman Dewangan 	}
18457f66b78SStephen Boyd 
1855e5e3a42SJavier Martinez Canillas 	if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
1865e5e3a42SJavier Martinez Canillas 		if (desc && desc->of_map_mode) {
18702f37039SDouglas Anderson 			mode = desc->of_map_mode(pval);
18802f37039SDouglas Anderson 			if (mode == REGULATOR_MODE_INVALID)
1890c9721a5SRob Herring 				pr_err("%pOFn: invalid mode %u\n", np, pval);
1905e5e3a42SJavier Martinez Canillas 			else
19102f37039SDouglas Anderson 				constraints->initial_mode = mode;
1925e5e3a42SJavier Martinez Canillas 		} else {
1930c9721a5SRob Herring 			pr_warn("%pOFn: mapping for mode %d not defined\n",
1940c9721a5SRob Herring 				np, pval);
1955e5e3a42SJavier Martinez Canillas 		}
1965e5e3a42SJavier Martinez Canillas 	}
1975e5e3a42SJavier Martinez Canillas 
19854557ad9SDavid Collins 	len = of_property_count_elems_of_size(np, "regulator-allowed-modes",
19954557ad9SDavid Collins 						sizeof(u32));
20054557ad9SDavid Collins 	if (len > 0) {
20154557ad9SDavid Collins 		if (desc && desc->of_map_mode) {
20254557ad9SDavid Collins 			for (i = 0; i < len; i++) {
20354557ad9SDavid Collins 				ret = of_property_read_u32_index(np,
20454557ad9SDavid Collins 					"regulator-allowed-modes", i, &pval);
20554557ad9SDavid Collins 				if (ret) {
2060c9721a5SRob Herring 					pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n",
2070c9721a5SRob Herring 						np, i, ret);
20854557ad9SDavid Collins 					break;
20954557ad9SDavid Collins 				}
21054557ad9SDavid Collins 				mode = desc->of_map_mode(pval);
21154557ad9SDavid Collins 				if (mode == REGULATOR_MODE_INVALID)
2120c9721a5SRob Herring 					pr_err("%pOFn: invalid regulator-allowed-modes element %u\n",
2130c9721a5SRob Herring 						np, pval);
21454557ad9SDavid Collins 				else
21554557ad9SDavid Collins 					constraints->valid_modes_mask |= mode;
21654557ad9SDavid Collins 			}
21754557ad9SDavid Collins 			if (constraints->valid_modes_mask)
21854557ad9SDavid Collins 				constraints->valid_ops_mask
21954557ad9SDavid Collins 					|= REGULATOR_CHANGE_MODE;
22054557ad9SDavid Collins 		} else {
2210c9721a5SRob Herring 			pr_warn("%pOFn: mode mapping not defined\n", np);
22254557ad9SDavid Collins 		}
22354557ad9SDavid Collins 	}
22454557ad9SDavid Collins 
22522a10bcaSStephen Boyd 	if (!of_property_read_u32(np, "regulator-system-load", &pval))
22622a10bcaSStephen Boyd 		constraints->system_load = pval;
22722a10bcaSStephen Boyd 
228d8ca7d18SDmitry Osipenko 	if (n_phandles) {
229d8ca7d18SDmitry Osipenko 		constraints->max_spread = devm_kzalloc(dev,
230d8ca7d18SDmitry Osipenko 				sizeof(*constraints->max_spread) * n_phandles,
231d8ca7d18SDmitry Osipenko 				GFP_KERNEL);
232d8ca7d18SDmitry Osipenko 
233d8ca7d18SDmitry Osipenko 		if (!constraints->max_spread)
234d8ca7d18SDmitry Osipenko 			return -ENOMEM;
235d8ca7d18SDmitry Osipenko 
236d8ca7d18SDmitry Osipenko 		of_property_read_u32_array(np, "regulator-coupled-max-spread",
237d8ca7d18SDmitry Osipenko 					   constraints->max_spread, n_phandles);
238d8ca7d18SDmitry Osipenko 	}
239a085a31aSMaciej Purski 
24085254bcfSDmitry Osipenko 	if (!of_property_read_u32(np, "regulator-max-step-microvolt",
24185254bcfSDmitry Osipenko 				  &pval))
24285254bcfSDmitry Osipenko 		constraints->max_uV_step = pval;
24385254bcfSDmitry Osipenko 
2443a003baeSStephen Boyd 	constraints->over_current_protection = of_property_read_bool(np,
2453a003baeSStephen Boyd 					"regulator-over-current-protection");
2463a003baeSStephen Boyd 
24789a6a5e5SMatti Vaittinen 	of_get_regulator_prot_limits(np, constraints);
24889a6a5e5SMatti Vaittinen 
24940e20d68SChanwoo Choi 	for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
25040e20d68SChanwoo Choi 		switch (i) {
25140e20d68SChanwoo Choi 		case PM_SUSPEND_MEM:
25240e20d68SChanwoo Choi 			suspend_state = &constraints->state_mem;
25340e20d68SChanwoo Choi 			break;
25440e20d68SChanwoo Choi 		case PM_SUSPEND_MAX:
25540e20d68SChanwoo Choi 			suspend_state = &constraints->state_disk;
25640e20d68SChanwoo Choi 			break;
257f2b40769SAndrei.Stefanescu@microchip.com 		case PM_SUSPEND_STANDBY:
258f2b40769SAndrei.Stefanescu@microchip.com 			suspend_state = &constraints->state_standby;
259f2b40769SAndrei.Stefanescu@microchip.com 			break;
26040e20d68SChanwoo Choi 		case PM_SUSPEND_ON:
261690cbb90SRafael J. Wysocki 		case PM_SUSPEND_TO_IDLE:
26240e20d68SChanwoo Choi 		default:
26340e20d68SChanwoo Choi 			continue;
2647cf225b9SKrzysztof Kozlowski 		}
26540e20d68SChanwoo Choi 
26640e20d68SChanwoo Choi 		suspend_np = of_get_child_by_name(np, regulator_states[i]);
26766efb665SLiang He 		if (!suspend_np)
26840e20d68SChanwoo Choi 			continue;
26966efb665SLiang He 		if (!suspend_state) {
27066efb665SLiang He 			of_node_put(suspend_np);
27166efb665SLiang He 			continue;
27266efb665SLiang He 		}
27340e20d68SChanwoo Choi 
2745e5e3a42SJavier Martinez Canillas 		if (!of_property_read_u32(suspend_np, "regulator-mode",
2755e5e3a42SJavier Martinez Canillas 					  &pval)) {
2765e5e3a42SJavier Martinez Canillas 			if (desc && desc->of_map_mode) {
27702f37039SDouglas Anderson 				mode = desc->of_map_mode(pval);
27802f37039SDouglas Anderson 				if (mode == REGULATOR_MODE_INVALID)
2790c9721a5SRob Herring 					pr_err("%pOFn: invalid mode %u\n",
2800c9721a5SRob Herring 					       np, pval);
2815e5e3a42SJavier Martinez Canillas 				else
28202f37039SDouglas Anderson 					suspend_state->mode = mode;
2835e5e3a42SJavier Martinez Canillas 			} else {
2840c9721a5SRob Herring 				pr_warn("%pOFn: mapping for mode %d not defined\n",
2850c9721a5SRob Herring 					np, pval);
2865e5e3a42SJavier Martinez Canillas 			}
2875e5e3a42SJavier Martinez Canillas 		}
2885e5e3a42SJavier Martinez Canillas 
28940e20d68SChanwoo Choi 		if (of_property_read_bool(suspend_np,
29040e20d68SChanwoo Choi 					"regulator-on-in-suspend"))
29172069f99SChunyan Zhang 			suspend_state->enabled = ENABLE_IN_SUSPEND;
29240e20d68SChanwoo Choi 		else if (of_property_read_bool(suspend_np,
29340e20d68SChanwoo Choi 					"regulator-off-in-suspend"))
29472069f99SChunyan Zhang 			suspend_state->enabled = DISABLE_IN_SUSPEND;
29540e20d68SChanwoo Choi 
296131cb121SMarco Felsch 		if (!of_property_read_u32(suspend_np,
297131cb121SMarco Felsch 				"regulator-suspend-min-microvolt", &pval))
298f7efad10SChunyan Zhang 			suspend_state->min_uV = pval;
299f7efad10SChunyan Zhang 
300131cb121SMarco Felsch 		if (!of_property_read_u32(suspend_np,
301131cb121SMarco Felsch 				"regulator-suspend-max-microvolt", &pval))
302f7efad10SChunyan Zhang 			suspend_state->max_uV = pval;
30340e20d68SChanwoo Choi 
3048cbcaea8SDoug Anderson 		if (!of_property_read_u32(suspend_np,
3058cbcaea8SDoug Anderson 					"regulator-suspend-microvolt", &pval))
3068cbcaea8SDoug Anderson 			suspend_state->uV = pval;
307f7efad10SChunyan Zhang 		else /* otherwise use min_uV as default suspend voltage */
308f7efad10SChunyan Zhang 			suspend_state->uV = suspend_state->min_uV;
309f7efad10SChunyan Zhang 
310f7efad10SChunyan Zhang 		if (of_property_read_bool(suspend_np,
311f7efad10SChunyan Zhang 					"regulator-changeable-in-suspend"))
312f7efad10SChunyan Zhang 			suspend_state->changeable = true;
3138cbcaea8SDoug Anderson 
314a0f78bc8SKeerthy 		if (i == PM_SUSPEND_MEM)
315a0f78bc8SKeerthy 			constraints->initial_state = PM_SUSPEND_MEM;
316a0f78bc8SKeerthy 
3174eafec83SJavier Martinez Canillas 		of_node_put(suspend_np);
31840e20d68SChanwoo Choi 		suspend_state = NULL;
31940e20d68SChanwoo Choi 		suspend_np = NULL;
32040e20d68SChanwoo Choi 	}
321d8ca7d18SDmitry Osipenko 
322d8ca7d18SDmitry Osipenko 	return 0;
3238f446e6fSRajendra Nayak }
3248f446e6fSRajendra Nayak 
3258f446e6fSRajendra Nayak /**
3268f446e6fSRajendra Nayak  * of_get_regulator_init_data - extract regulator_init_data structure info
3278f446e6fSRajendra Nayak  * @dev: device requesting for regulator_init_data
328072e78b1SJavier Martinez Canillas  * @node: regulator device node
329072e78b1SJavier Martinez Canillas  * @desc: regulator description
3308f446e6fSRajendra Nayak  *
3318f446e6fSRajendra Nayak  * Populates regulator_init_data structure by extracting data from device
33248f1b4efSKrzysztof Kozlowski  * tree node, returns a pointer to the populated structure or NULL if memory
3338f446e6fSRajendra Nayak  * alloc fails.
3348f446e6fSRajendra Nayak  */
of_get_regulator_init_data(struct device * dev,struct device_node * node,const struct regulator_desc * desc)335d9a861ccSShawn Guo struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
336072e78b1SJavier Martinez Canillas 					  struct device_node *node,
337072e78b1SJavier Martinez Canillas 					  const struct regulator_desc *desc)
3388f446e6fSRajendra Nayak {
3398f446e6fSRajendra Nayak 	struct regulator_init_data *init_data;
3408f446e6fSRajendra Nayak 
341d9a861ccSShawn Guo 	if (!node)
3428f446e6fSRajendra Nayak 		return NULL;
3438f446e6fSRajendra Nayak 
3448f446e6fSRajendra Nayak 	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
3458f446e6fSRajendra Nayak 	if (!init_data)
3468f446e6fSRajendra Nayak 		return NULL; /* Out of memory? */
3478f446e6fSRajendra Nayak 
348d8ca7d18SDmitry Osipenko 	if (of_get_regulation_constraints(dev, node, &init_data, desc))
349d8ca7d18SDmitry Osipenko 		return NULL;
350d8ca7d18SDmitry Osipenko 
3518f446e6fSRajendra Nayak 	return init_data;
3528f446e6fSRajendra Nayak }
353e69af5e9SAxel Lin EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
3541c8fa58fSThierry Reding 
35513b3fde8SCharles Keepax struct devm_of_regulator_matches {
35613b3fde8SCharles Keepax 	struct of_regulator_match *matches;
35713b3fde8SCharles Keepax 	unsigned int num_matches;
35813b3fde8SCharles Keepax };
35913b3fde8SCharles Keepax 
devm_of_regulator_put_matches(struct device * dev,void * res)36013b3fde8SCharles Keepax static void devm_of_regulator_put_matches(struct device *dev, void *res)
36113b3fde8SCharles Keepax {
36213b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches = res;
36313b3fde8SCharles Keepax 	int i;
36413b3fde8SCharles Keepax 
36513b3fde8SCharles Keepax 	for (i = 0; i < devm_matches->num_matches; i++)
36613b3fde8SCharles Keepax 		of_node_put(devm_matches->matches[i].of_node);
36713b3fde8SCharles Keepax }
36813b3fde8SCharles Keepax 
3691c8fa58fSThierry Reding /**
37013511defSStephen Warren  * of_regulator_match - extract multiple regulator init data from device tree.
3711c8fa58fSThierry Reding  * @dev: device requesting the data
3721c8fa58fSThierry Reding  * @node: parent device node of the regulators
3731c8fa58fSThierry Reding  * @matches: match table for the regulators
3741c8fa58fSThierry Reding  * @num_matches: number of entries in match table
3751c8fa58fSThierry Reding  *
37613511defSStephen Warren  * This function uses a match table specified by the regulator driver to
37713511defSStephen Warren  * parse regulator init data from the device tree. @node is expected to
37813511defSStephen Warren  * contain a set of child nodes, each providing the init data for one
37913511defSStephen Warren  * regulator. The data parsed from a child node will be matched to a regulator
38013511defSStephen Warren  * based on either the deprecated property regulator-compatible if present,
38113511defSStephen Warren  * or otherwise the child node's name. Note that the match table is modified
382bd0dda74SCharles Keepax  * in place and an additional of_node reference is taken for each matched
383bd0dda74SCharles Keepax  * regulator.
3841c8fa58fSThierry Reding  *
3851c8fa58fSThierry Reding  * Returns the number of matches found or a negative error code on failure.
3861c8fa58fSThierry Reding  */
of_regulator_match(struct device * dev,struct device_node * node,struct of_regulator_match * matches,unsigned int num_matches)3871c8fa58fSThierry Reding int of_regulator_match(struct device *dev, struct device_node *node,
3881c8fa58fSThierry Reding 		       struct of_regulator_match *matches,
3891c8fa58fSThierry Reding 		       unsigned int num_matches)
3901c8fa58fSThierry Reding {
3911c8fa58fSThierry Reding 	unsigned int count = 0;
3921c8fa58fSThierry Reding 	unsigned int i;
39313511defSStephen Warren 	const char *name;
3945260cd2bSLaxman Dewangan 	struct device_node *child;
39513b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches;
3961c8fa58fSThierry Reding 
3971c8fa58fSThierry Reding 	if (!dev || !node)
3981c8fa58fSThierry Reding 		return -EINVAL;
3991c8fa58fSThierry Reding 
40013b3fde8SCharles Keepax 	devm_matches = devres_alloc(devm_of_regulator_put_matches,
40113b3fde8SCharles Keepax 				    sizeof(struct devm_of_regulator_matches),
40213b3fde8SCharles Keepax 				    GFP_KERNEL);
40313b3fde8SCharles Keepax 	if (!devm_matches)
40413b3fde8SCharles Keepax 		return -ENOMEM;
40513b3fde8SCharles Keepax 
40613b3fde8SCharles Keepax 	devm_matches->matches = matches;
40713b3fde8SCharles Keepax 	devm_matches->num_matches = num_matches;
40813b3fde8SCharles Keepax 
40913b3fde8SCharles Keepax 	devres_add(dev, devm_matches);
41013b3fde8SCharles Keepax 
411a2f95c36SStephen Warren 	for (i = 0; i < num_matches; i++) {
412a2f95c36SStephen Warren 		struct of_regulator_match *match = &matches[i];
413a2f95c36SStephen Warren 		match->init_data = NULL;
414a2f95c36SStephen Warren 		match->of_node = NULL;
415a2f95c36SStephen Warren 	}
416a2f95c36SStephen Warren 
4175260cd2bSLaxman Dewangan 	for_each_child_of_node(node, child) {
41813511defSStephen Warren 		name = of_get_property(child,
4195260cd2bSLaxman Dewangan 					"regulator-compatible", NULL);
42013511defSStephen Warren 		if (!name)
42113511defSStephen Warren 			name = child->name;
4221c8fa58fSThierry Reding 		for (i = 0; i < num_matches; i++) {
4231c8fa58fSThierry Reding 			struct of_regulator_match *match = &matches[i];
4245260cd2bSLaxman Dewangan 			if (match->of_node)
4251c8fa58fSThierry Reding 				continue;
4261c8fa58fSThierry Reding 
42713511defSStephen Warren 			if (strcmp(match->name, name))
4285260cd2bSLaxman Dewangan 				continue;
4295260cd2bSLaxman Dewangan 
4305260cd2bSLaxman Dewangan 			match->init_data =
43175d6b2faSJavier Martinez Canillas 				of_get_regulator_init_data(dev, child,
43275d6b2faSJavier Martinez Canillas 							   match->desc);
4331c8fa58fSThierry Reding 			if (!match->init_data) {
4345260cd2bSLaxman Dewangan 				dev_err(dev,
4350c9721a5SRob Herring 					"failed to parse DT for regulator %pOFn\n",
4360c9721a5SRob Herring 					child);
43730966861SChristophe JAILLET 				of_node_put(child);
4381c8fa58fSThierry Reding 				return -EINVAL;
4391c8fa58fSThierry Reding 			}
440bd0dda74SCharles Keepax 			match->of_node = of_node_get(child);
4411c8fa58fSThierry Reding 			count++;
4425260cd2bSLaxman Dewangan 			break;
4435260cd2bSLaxman Dewangan 		}
4441c8fa58fSThierry Reding 	}
4451c8fa58fSThierry Reding 
4461c8fa58fSThierry Reding 	return count;
4471c8fa58fSThierry Reding }
4481c8fa58fSThierry Reding EXPORT_SYMBOL_GPL(of_regulator_match);
449a0c7b164SMark Brown 
4507a67eb1dSYueHaibing static struct
regulator_of_get_init_node(struct device * dev,const struct regulator_desc * desc)4517a67eb1dSYueHaibing device_node *regulator_of_get_init_node(struct device *dev,
452925c85e2SCharles Keepax 					const struct regulator_desc *desc)
453a0c7b164SMark Brown {
454a0c7b164SMark Brown 	struct device_node *search, *child;
455a0c7b164SMark Brown 	const char *name;
456a0c7b164SMark Brown 
457a0c7b164SMark Brown 	if (!dev->of_node || !desc->of_match)
458a0c7b164SMark Brown 		return NULL;
459a0c7b164SMark Brown 
460eba9473fSCharles Keepax 	if (desc->regulators_node) {
461a0c7b164SMark Brown 		search = of_get_child_by_name(dev->of_node,
462a0c7b164SMark Brown 					      desc->regulators_node);
463eba9473fSCharles Keepax 	} else {
464423a1164SFrank Rowand 		search = of_node_get(dev->of_node);
465a0c7b164SMark Brown 
466eba9473fSCharles Keepax 		if (!strcmp(desc->of_match, search->name))
467eba9473fSCharles Keepax 			return search;
468eba9473fSCharles Keepax 	}
469eba9473fSCharles Keepax 
470a0c7b164SMark Brown 	if (!search) {
4717de79a1dSMark Brown 		dev_dbg(dev, "Failed to find regulator container node '%s'\n",
4727de79a1dSMark Brown 			desc->regulators_node);
473a0c7b164SMark Brown 		return NULL;
474a0c7b164SMark Brown 	}
475a0c7b164SMark Brown 
476130daa3fSStephen Boyd 	for_each_available_child_of_node(search, child) {
477a0c7b164SMark Brown 		name = of_get_property(child, "regulator-compatible", NULL);
478e7095c35SCristian Marussi 		if (!name) {
479e7095c35SCristian Marussi 			if (!desc->of_match_full_name)
480a0c7b164SMark Brown 				name = child->name;
481e7095c35SCristian Marussi 			else
482e7095c35SCristian Marussi 				name = child->full_name;
483e7095c35SCristian Marussi 		}
484a0c7b164SMark Brown 
485811ba489SNishka Dasgupta 		if (!strcmp(desc->of_match, name)) {
486811ba489SNishka Dasgupta 			of_node_put(search);
4878a065ce9SChristophe JAILLET 			/*
4888a065ce9SChristophe JAILLET 			 * 'of_node_get(child)' is already performed by the
4898a065ce9SChristophe JAILLET 			 * for_each loop.
4908a065ce9SChristophe JAILLET 			 */
4918a065ce9SChristophe JAILLET 			return child;
492a0c7b164SMark Brown 		}
493811ba489SNishka Dasgupta 	}
494a0c7b164SMark Brown 
495a0c7b164SMark Brown 	of_node_put(search);
496a0c7b164SMark Brown 
497925c85e2SCharles Keepax 	return NULL;
498925c85e2SCharles Keepax }
499925c85e2SCharles Keepax 
regulator_of_get_init_data(struct device * dev,const struct regulator_desc * desc,struct regulator_config * config,struct device_node ** node)500925c85e2SCharles Keepax struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
501925c85e2SCharles Keepax 					    const struct regulator_desc *desc,
502925c85e2SCharles Keepax 					    struct regulator_config *config,
503925c85e2SCharles Keepax 					    struct device_node **node)
504925c85e2SCharles Keepax {
505925c85e2SCharles Keepax 	struct device_node *child;
506925c85e2SCharles Keepax 	struct regulator_init_data *init_data = NULL;
507925c85e2SCharles Keepax 
508*8f3cbcd6SChiYuan Huang 	child = regulator_of_get_init_node(config->dev, desc);
509925c85e2SCharles Keepax 	if (!child)
510925c85e2SCharles Keepax 		return NULL;
511925c85e2SCharles Keepax 
512925c85e2SCharles Keepax 	init_data = of_get_regulator_init_data(dev, child, desc);
513925c85e2SCharles Keepax 	if (!init_data) {
514925c85e2SCharles Keepax 		dev_err(dev, "failed to parse DT for regulator %pOFn\n", child);
515925c85e2SCharles Keepax 		goto error;
516925c85e2SCharles Keepax 	}
517925c85e2SCharles Keepax 
518f8970d34SMarco Felsch 	if (desc->of_parse_cb) {
519f8970d34SMarco Felsch 		int ret;
520f8970d34SMarco Felsch 
521f8970d34SMarco Felsch 		ret = desc->of_parse_cb(child, desc, config);
522f8970d34SMarco Felsch 		if (ret) {
523f8970d34SMarco Felsch 			if (ret == -EPROBE_DEFER) {
524f8970d34SMarco Felsch 				of_node_put(child);
525f8970d34SMarco Felsch 				return ERR_PTR(-EPROBE_DEFER);
526f8970d34SMarco Felsch 			}
527925c85e2SCharles Keepax 			dev_err(dev,
528925c85e2SCharles Keepax 				"driver callback failed to parse DT for regulator %pOFn\n",
529925c85e2SCharles Keepax 				child);
530925c85e2SCharles Keepax 			goto error;
531925c85e2SCharles Keepax 		}
532f8970d34SMarco Felsch 	}
533925c85e2SCharles Keepax 
534925c85e2SCharles Keepax 	*node = child;
535925c85e2SCharles Keepax 
536a0c7b164SMark Brown 	return init_data;
537925c85e2SCharles Keepax 
538925c85e2SCharles Keepax error:
539925c85e2SCharles Keepax 	of_node_put(child);
540925c85e2SCharles Keepax 
541925c85e2SCharles Keepax 	return NULL;
542a0c7b164SMark Brown }
543148096afSMaciej Purski 
of_find_regulator_by_node(struct device_node * np)544148096afSMaciej Purski struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
545148096afSMaciej Purski {
546148096afSMaciej Purski 	struct device *dev;
547148096afSMaciej Purski 
548cfba5de9SSuzuki K Poulose 	dev = class_find_device_by_of_node(&regulator_class, np);
549148096afSMaciej Purski 
550148096afSMaciej Purski 	return dev ? dev_to_rdev(dev) : NULL;
551148096afSMaciej Purski }
552a085a31aSMaciej Purski 
553a085a31aSMaciej Purski /*
554a085a31aSMaciej Purski  * Returns number of regulators coupled with rdev.
555a085a31aSMaciej Purski  */
of_get_n_coupled(struct regulator_dev * rdev)556a085a31aSMaciej Purski int of_get_n_coupled(struct regulator_dev *rdev)
557a085a31aSMaciej Purski {
558a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
559a085a31aSMaciej Purski 	int n_phandles;
560a085a31aSMaciej Purski 
561a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(node,
562a085a31aSMaciej Purski 						"regulator-coupled-with",
563a085a31aSMaciej Purski 						NULL);
564a085a31aSMaciej Purski 
565a085a31aSMaciej Purski 	return (n_phandles > 0) ? n_phandles : 0;
566a085a31aSMaciej Purski }
567a085a31aSMaciej Purski 
568a085a31aSMaciej Purski /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
of_coupling_find_node(struct device_node * src,struct device_node * to_find,int * index)569a085a31aSMaciej Purski static bool of_coupling_find_node(struct device_node *src,
570d8ca7d18SDmitry Osipenko 				  struct device_node *to_find,
571d8ca7d18SDmitry Osipenko 				  int *index)
572a085a31aSMaciej Purski {
573a085a31aSMaciej Purski 	int n_phandles, i;
574a085a31aSMaciej Purski 	bool found = false;
575a085a31aSMaciej Purski 
576a085a31aSMaciej Purski 	n_phandles = of_count_phandle_with_args(src,
577a085a31aSMaciej Purski 						"regulator-coupled-with",
578a085a31aSMaciej Purski 						NULL);
579a085a31aSMaciej Purski 
580a085a31aSMaciej Purski 	for (i = 0; i < n_phandles; i++) {
581a085a31aSMaciej Purski 		struct device_node *tmp = of_parse_phandle(src,
582a085a31aSMaciej Purski 					   "regulator-coupled-with", i);
583a085a31aSMaciej Purski 
584a085a31aSMaciej Purski 		if (!tmp)
585a085a31aSMaciej Purski 			break;
586a085a31aSMaciej Purski 
587a085a31aSMaciej Purski 		/* found */
588a085a31aSMaciej Purski 		if (tmp == to_find)
589a085a31aSMaciej Purski 			found = true;
590a085a31aSMaciej Purski 
591a085a31aSMaciej Purski 		of_node_put(tmp);
592a085a31aSMaciej Purski 
593d8ca7d18SDmitry Osipenko 		if (found) {
594d8ca7d18SDmitry Osipenko 			*index = i;
595a085a31aSMaciej Purski 			break;
596a085a31aSMaciej Purski 		}
597d8ca7d18SDmitry Osipenko 	}
598a085a31aSMaciej Purski 
599a085a31aSMaciej Purski 	return found;
600a085a31aSMaciej Purski }
601a085a31aSMaciej Purski 
602a085a31aSMaciej Purski /**
603a085a31aSMaciej Purski  * of_check_coupling_data - Parse rdev's coupling properties and check data
604a085a31aSMaciej Purski  *			    consistency
60545e8446eSLee Jones  * @rdev: pointer to regulator_dev whose data is checked
606a085a31aSMaciej Purski  *
607a085a31aSMaciej Purski  * Function checks if all the following conditions are met:
608a085a31aSMaciej Purski  * - rdev's max_spread is greater than 0
609a085a31aSMaciej Purski  * - all coupled regulators have the same max_spread
610a085a31aSMaciej Purski  * - all coupled regulators have the same number of regulator_dev phandles
611a085a31aSMaciej Purski  * - all regulators are linked to each other
612a085a31aSMaciej Purski  *
613a085a31aSMaciej Purski  * Returns true if all conditions are met.
614a085a31aSMaciej Purski  */
of_check_coupling_data(struct regulator_dev * rdev)615a085a31aSMaciej Purski bool of_check_coupling_data(struct regulator_dev *rdev)
616a085a31aSMaciej Purski {
617a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
618a085a31aSMaciej Purski 	int n_phandles = of_get_n_coupled(rdev);
619a085a31aSMaciej Purski 	struct device_node *c_node;
620d8ca7d18SDmitry Osipenko 	int index;
621a085a31aSMaciej Purski 	int i;
622a085a31aSMaciej Purski 	bool ret = true;
623a085a31aSMaciej Purski 
624d8ca7d18SDmitry Osipenko 	/* iterate over rdev's phandles */
625d8ca7d18SDmitry Osipenko 	for (i = 0; i < n_phandles; i++) {
626d8ca7d18SDmitry Osipenko 		int max_spread = rdev->constraints->max_spread[i];
627d8ca7d18SDmitry Osipenko 		int c_max_spread, c_n_phandles;
628d8ca7d18SDmitry Osipenko 
629a085a31aSMaciej Purski 		if (max_spread <= 0) {
630a085a31aSMaciej Purski 			dev_err(&rdev->dev, "max_spread value invalid\n");
631a085a31aSMaciej Purski 			return false;
632a085a31aSMaciej Purski 		}
633a085a31aSMaciej Purski 
634a085a31aSMaciej Purski 		c_node = of_parse_phandle(node,
635a085a31aSMaciej Purski 					  "regulator-coupled-with", i);
636a085a31aSMaciej Purski 
637a085a31aSMaciej Purski 		if (!c_node)
638a085a31aSMaciej Purski 			ret = false;
639a085a31aSMaciej Purski 
640a085a31aSMaciej Purski 		c_n_phandles = of_count_phandle_with_args(c_node,
641a085a31aSMaciej Purski 							  "regulator-coupled-with",
642a085a31aSMaciej Purski 							  NULL);
643a085a31aSMaciej Purski 
644a085a31aSMaciej Purski 		if (c_n_phandles != n_phandles) {
64548f1b4efSKrzysztof Kozlowski 			dev_err(&rdev->dev, "number of coupled reg phandles mismatch\n");
646a085a31aSMaciej Purski 			ret = false;
647a085a31aSMaciej Purski 			goto clean;
648a085a31aSMaciej Purski 		}
649a085a31aSMaciej Purski 
650d8ca7d18SDmitry Osipenko 		if (!of_coupling_find_node(c_node, node, &index)) {
651d8ca7d18SDmitry Osipenko 			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
652d8ca7d18SDmitry Osipenko 			ret = false;
653d8ca7d18SDmitry Osipenko 			goto clean;
654d8ca7d18SDmitry Osipenko 		}
655d8ca7d18SDmitry Osipenko 
656d8ca7d18SDmitry Osipenko 		if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread",
657d8ca7d18SDmitry Osipenko 					       index, &c_max_spread)) {
658a085a31aSMaciej Purski 			ret = false;
659a085a31aSMaciej Purski 			goto clean;
660a085a31aSMaciej Purski 		}
661a085a31aSMaciej Purski 
662a085a31aSMaciej Purski 		if (c_max_spread != max_spread) {
663a085a31aSMaciej Purski 			dev_err(&rdev->dev,
664a085a31aSMaciej Purski 				"coupled regulators max_spread mismatch\n");
665a085a31aSMaciej Purski 			ret = false;
666a085a31aSMaciej Purski 			goto clean;
667a085a31aSMaciej Purski 		}
668a085a31aSMaciej Purski 
669a085a31aSMaciej Purski clean:
670a085a31aSMaciej Purski 		of_node_put(c_node);
671a085a31aSMaciej Purski 		if (!ret)
672a085a31aSMaciej Purski 			break;
673a085a31aSMaciej Purski 	}
674a085a31aSMaciej Purski 
675a085a31aSMaciej Purski 	return ret;
676a085a31aSMaciej Purski }
677a085a31aSMaciej Purski 
678a085a31aSMaciej Purski /**
679a8c31d35SJiapeng Chong  * of_parse_coupled_regulator() - Get regulator_dev pointer from rdev's property
680a085a31aSMaciej Purski  * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse
681a085a31aSMaciej Purski  *	  "regulator-coupled-with" property
682a085a31aSMaciej Purski  * @index: Index in phandles array
683a085a31aSMaciej Purski  *
684a085a31aSMaciej Purski  * Returns the regulator_dev pointer parsed from DTS. If it has not been yet
685a085a31aSMaciej Purski  * registered, returns NULL
686a085a31aSMaciej Purski  */
of_parse_coupled_regulator(struct regulator_dev * rdev,int index)687a085a31aSMaciej Purski struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev,
688a085a31aSMaciej Purski 						 int index)
689a085a31aSMaciej Purski {
690a085a31aSMaciej Purski 	struct device_node *node = rdev->dev.of_node;
691a085a31aSMaciej Purski 	struct device_node *c_node;
692a085a31aSMaciej Purski 	struct regulator_dev *c_rdev;
693a085a31aSMaciej Purski 
694a085a31aSMaciej Purski 	c_node = of_parse_phandle(node, "regulator-coupled-with", index);
695a085a31aSMaciej Purski 	if (!c_node)
696a085a31aSMaciej Purski 		return NULL;
697a085a31aSMaciej Purski 
698a085a31aSMaciej Purski 	c_rdev = of_find_regulator_by_node(c_node);
699a085a31aSMaciej Purski 
700a085a31aSMaciej Purski 	of_node_put(c_node);
701a085a31aSMaciej Purski 
702a085a31aSMaciej Purski 	return c_rdev;
703a085a31aSMaciej Purski }
70427b9ecc7SCorentin Labbe 
70527b9ecc7SCorentin Labbe /*
70627b9ecc7SCorentin Labbe  * Check if name is a supply name according to the '*-supply' pattern
70727b9ecc7SCorentin Labbe  * return 0 if false
70827b9ecc7SCorentin Labbe  * return length of supply name without the -supply
70927b9ecc7SCorentin Labbe  */
is_supply_name(const char * name)71027b9ecc7SCorentin Labbe static int is_supply_name(const char *name)
71127b9ecc7SCorentin Labbe {
71227b9ecc7SCorentin Labbe 	int strs, i;
71327b9ecc7SCorentin Labbe 
71427b9ecc7SCorentin Labbe 	strs = strlen(name);
71527b9ecc7SCorentin Labbe 	/* string need to be at minimum len(x-supply) */
71627b9ecc7SCorentin Labbe 	if (strs < 8)
71727b9ecc7SCorentin Labbe 		return 0;
71827b9ecc7SCorentin Labbe 	for (i = strs - 6; i > 0; i--) {
71927b9ecc7SCorentin Labbe 		/* find first '-' and check if right part is supply */
72027b9ecc7SCorentin Labbe 		if (name[i] != '-')
72127b9ecc7SCorentin Labbe 			continue;
72227b9ecc7SCorentin Labbe 		if (strcmp(name + i + 1, "supply") != 0)
72327b9ecc7SCorentin Labbe 			return 0;
72427b9ecc7SCorentin Labbe 		return i;
72527b9ecc7SCorentin Labbe 	}
72627b9ecc7SCorentin Labbe 	return 0;
72727b9ecc7SCorentin Labbe }
72827b9ecc7SCorentin Labbe 
72927b9ecc7SCorentin Labbe /*
73027b9ecc7SCorentin Labbe  * of_regulator_bulk_get_all - get multiple regulator consumers
73127b9ecc7SCorentin Labbe  *
73227b9ecc7SCorentin Labbe  * @dev:	Device to supply
73327b9ecc7SCorentin Labbe  * @np:		device node to search for consumers
73427b9ecc7SCorentin Labbe  * @consumers:  Configuration of consumers; clients are stored here.
73527b9ecc7SCorentin Labbe  *
73627b9ecc7SCorentin Labbe  * @return number of regulators on success, an errno on failure.
73727b9ecc7SCorentin Labbe  *
73827b9ecc7SCorentin Labbe  * This helper function allows drivers to get several regulator
73927b9ecc7SCorentin Labbe  * consumers in one operation.  If any of the regulators cannot be
74027b9ecc7SCorentin Labbe  * acquired then any regulators that were allocated will be freed
74127b9ecc7SCorentin Labbe  * before returning to the caller.
74227b9ecc7SCorentin Labbe  */
of_regulator_bulk_get_all(struct device * dev,struct device_node * np,struct regulator_bulk_data ** consumers)74327b9ecc7SCorentin Labbe int of_regulator_bulk_get_all(struct device *dev, struct device_node *np,
74427b9ecc7SCorentin Labbe 			      struct regulator_bulk_data **consumers)
74527b9ecc7SCorentin Labbe {
74627b9ecc7SCorentin Labbe 	int num_consumers = 0;
74727b9ecc7SCorentin Labbe 	struct regulator *tmp;
74827b9ecc7SCorentin Labbe 	struct property *prop;
74927b9ecc7SCorentin Labbe 	int i, n = 0, ret;
75027b9ecc7SCorentin Labbe 	char name[64];
75127b9ecc7SCorentin Labbe 
75227b9ecc7SCorentin Labbe 	*consumers = NULL;
75327b9ecc7SCorentin Labbe 
75427b9ecc7SCorentin Labbe 	/*
75527b9ecc7SCorentin Labbe 	 * first pass: get numbers of xxx-supply
75627b9ecc7SCorentin Labbe 	 * second pass: fill consumers
75727b9ecc7SCorentin Labbe 	 */
75827b9ecc7SCorentin Labbe restart:
75927b9ecc7SCorentin Labbe 	for_each_property_of_node(np, prop) {
76027b9ecc7SCorentin Labbe 		i = is_supply_name(prop->name);
76127b9ecc7SCorentin Labbe 		if (i == 0)
76227b9ecc7SCorentin Labbe 			continue;
76327b9ecc7SCorentin Labbe 		if (!*consumers) {
76427b9ecc7SCorentin Labbe 			num_consumers++;
76527b9ecc7SCorentin Labbe 			continue;
76627b9ecc7SCorentin Labbe 		} else {
76727b9ecc7SCorentin Labbe 			memcpy(name, prop->name, i);
76827b9ecc7SCorentin Labbe 			name[i] = '\0';
76927b9ecc7SCorentin Labbe 			tmp = regulator_get(dev, name);
770c957387cSPeng Wu 			if (IS_ERR(tmp)) {
77127b9ecc7SCorentin Labbe 				ret = -EINVAL;
77227b9ecc7SCorentin Labbe 				goto error;
77327b9ecc7SCorentin Labbe 			}
77427b9ecc7SCorentin Labbe 			(*consumers)[n].consumer = tmp;
77527b9ecc7SCorentin Labbe 			n++;
77627b9ecc7SCorentin Labbe 			continue;
77727b9ecc7SCorentin Labbe 		}
77827b9ecc7SCorentin Labbe 	}
77927b9ecc7SCorentin Labbe 	if (*consumers)
78027b9ecc7SCorentin Labbe 		return num_consumers;
78127b9ecc7SCorentin Labbe 	if (num_consumers == 0)
78227b9ecc7SCorentin Labbe 		return 0;
78327b9ecc7SCorentin Labbe 	*consumers = kmalloc_array(num_consumers,
78427b9ecc7SCorentin Labbe 				   sizeof(struct regulator_bulk_data),
78527b9ecc7SCorentin Labbe 				   GFP_KERNEL);
78627b9ecc7SCorentin Labbe 	if (!*consumers)
78727b9ecc7SCorentin Labbe 		return -ENOMEM;
78827b9ecc7SCorentin Labbe 	goto restart;
78927b9ecc7SCorentin Labbe 
79027b9ecc7SCorentin Labbe error:
79127b9ecc7SCorentin Labbe 	while (--n >= 0)
79227b9ecc7SCorentin Labbe 		regulator_put(consumers[n]->consumer);
79327b9ecc7SCorentin Labbe 	return ret;
79427b9ecc7SCorentin Labbe }
79527b9ecc7SCorentin Labbe EXPORT_SYMBOL_GPL(of_regulator_bulk_get_all);
796