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(®ulator_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