162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OF helpers for regulator framework 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 662306a36Sopenharmony_ci * Rajendra Nayak <rnayak@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/of.h> 1262306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1362306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1462306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "internal.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic const char *const regulator_states[PM_SUSPEND_MAX + 1] = { 1962306a36Sopenharmony_ci [PM_SUSPEND_STANDBY] = "regulator-state-standby", 2062306a36Sopenharmony_ci [PM_SUSPEND_MEM] = "regulator-state-mem", 2162306a36Sopenharmony_ci [PM_SUSPEND_MAX] = "regulator-state-disk", 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void fill_limit(int *limit, int val) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci if (val) 2762306a36Sopenharmony_ci if (val == 1) 2862306a36Sopenharmony_ci *limit = REGULATOR_NOTIF_LIMIT_ENABLE; 2962306a36Sopenharmony_ci else 3062306a36Sopenharmony_ci *limit = val; 3162306a36Sopenharmony_ci else 3262306a36Sopenharmony_ci *limit = REGULATOR_NOTIF_LIMIT_DISABLE; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void of_get_regulator_prot_limits(struct device_node *np, 3662306a36Sopenharmony_ci struct regulation_constraints *constraints) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci u32 pval; 3962306a36Sopenharmony_ci int i; 4062306a36Sopenharmony_ci static const char *const props[] = { 4162306a36Sopenharmony_ci "regulator-oc-%s-microamp", 4262306a36Sopenharmony_ci "regulator-ov-%s-microvolt", 4362306a36Sopenharmony_ci "regulator-temp-%s-kelvin", 4462306a36Sopenharmony_ci "regulator-uv-%s-microvolt", 4562306a36Sopenharmony_ci }; 4662306a36Sopenharmony_ci struct notification_limit *limits[] = { 4762306a36Sopenharmony_ci &constraints->over_curr_limits, 4862306a36Sopenharmony_ci &constraints->over_voltage_limits, 4962306a36Sopenharmony_ci &constraints->temp_limits, 5062306a36Sopenharmony_ci &constraints->under_voltage_limits, 5162306a36Sopenharmony_ci }; 5262306a36Sopenharmony_ci bool set[4] = {0}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci /* Protection limits: */ 5562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(props); i++) { 5662306a36Sopenharmony_ci char prop[255]; 5762306a36Sopenharmony_ci bool found; 5862306a36Sopenharmony_ci int j; 5962306a36Sopenharmony_ci static const char *const lvl[] = { 6062306a36Sopenharmony_ci "protection", "error", "warn" 6162306a36Sopenharmony_ci }; 6262306a36Sopenharmony_ci int *l[] = { 6362306a36Sopenharmony_ci &limits[i]->prot, &limits[i]->err, &limits[i]->warn, 6462306a36Sopenharmony_ci }; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(lvl); j++) { 6762306a36Sopenharmony_ci snprintf(prop, 255, props[i], lvl[j]); 6862306a36Sopenharmony_ci found = !of_property_read_u32(np, prop, &pval); 6962306a36Sopenharmony_ci if (found) 7062306a36Sopenharmony_ci fill_limit(l[j], pval); 7162306a36Sopenharmony_ci set[i] |= found; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci constraints->over_current_detection = set[0]; 7562306a36Sopenharmony_ci constraints->over_voltage_detection = set[1]; 7662306a36Sopenharmony_ci constraints->over_temp_detection = set[2]; 7762306a36Sopenharmony_ci constraints->under_voltage_detection = set[3]; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int of_get_regulation_constraints(struct device *dev, 8162306a36Sopenharmony_ci struct device_node *np, 8262306a36Sopenharmony_ci struct regulator_init_data **init_data, 8362306a36Sopenharmony_ci const struct regulator_desc *desc) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct regulation_constraints *constraints = &(*init_data)->constraints; 8662306a36Sopenharmony_ci struct regulator_state *suspend_state; 8762306a36Sopenharmony_ci struct device_node *suspend_np; 8862306a36Sopenharmony_ci unsigned int mode; 8962306a36Sopenharmony_ci int ret, i, len; 9062306a36Sopenharmony_ci int n_phandles; 9162306a36Sopenharmony_ci u32 pval; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with", 9462306a36Sopenharmony_ci NULL); 9562306a36Sopenharmony_ci n_phandles = max(n_phandles, 0); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci constraints->name = of_get_property(np, "regulator-name", NULL); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-min-microvolt", &pval)) 10062306a36Sopenharmony_ci constraints->min_uV = pval; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-max-microvolt", &pval)) 10362306a36Sopenharmony_ci constraints->max_uV = pval; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Voltage change possible? */ 10662306a36Sopenharmony_ci if (constraints->min_uV != constraints->max_uV) 10762306a36Sopenharmony_ci constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Do we have a voltage range, if so try to apply it? */ 11062306a36Sopenharmony_ci if (constraints->min_uV && constraints->max_uV) 11162306a36Sopenharmony_ci constraints->apply_uV = true; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval)) 11462306a36Sopenharmony_ci constraints->uV_offset = pval; 11562306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-min-microamp", &pval)) 11662306a36Sopenharmony_ci constraints->min_uA = pval; 11762306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-max-microamp", &pval)) 11862306a36Sopenharmony_ci constraints->max_uA = pval; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-input-current-limit-microamp", 12162306a36Sopenharmony_ci &pval)) 12262306a36Sopenharmony_ci constraints->ilim_uA = pval; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Current change possible? */ 12562306a36Sopenharmony_ci if (constraints->min_uA != constraints->max_uA) 12662306a36Sopenharmony_ci constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci constraints->boot_on = of_property_read_bool(np, "regulator-boot-on"); 12962306a36Sopenharmony_ci constraints->always_on = of_property_read_bool(np, "regulator-always-on"); 13062306a36Sopenharmony_ci if (!constraints->always_on) /* status change should be possible. */ 13162306a36Sopenharmony_ci constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci constraints->pull_down = of_property_read_bool(np, "regulator-pull-down"); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (of_property_read_bool(np, "regulator-allow-bypass")) 13662306a36Sopenharmony_ci constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (of_property_read_bool(np, "regulator-allow-set-load")) 13962306a36Sopenharmony_ci constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-ramp-delay", &pval); 14262306a36Sopenharmony_ci if (!ret) { 14362306a36Sopenharmony_ci if (pval) 14462306a36Sopenharmony_ci constraints->ramp_delay = pval; 14562306a36Sopenharmony_ci else 14662306a36Sopenharmony_ci constraints->ramp_disable = true; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-settling-time-us", &pval); 15062306a36Sopenharmony_ci if (!ret) 15162306a36Sopenharmony_ci constraints->settling_time = pval; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval); 15462306a36Sopenharmony_ci if (!ret) 15562306a36Sopenharmony_ci constraints->settling_time_up = pval; 15662306a36Sopenharmony_ci if (constraints->settling_time_up && constraints->settling_time) { 15762306a36Sopenharmony_ci pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'\n", 15862306a36Sopenharmony_ci np); 15962306a36Sopenharmony_ci constraints->settling_time_up = 0; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-settling-time-down-us", 16362306a36Sopenharmony_ci &pval); 16462306a36Sopenharmony_ci if (!ret) 16562306a36Sopenharmony_ci constraints->settling_time_down = pval; 16662306a36Sopenharmony_ci if (constraints->settling_time_down && constraints->settling_time) { 16762306a36Sopenharmony_ci pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'\n", 16862306a36Sopenharmony_ci np); 16962306a36Sopenharmony_ci constraints->settling_time_down = 0; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval); 17362306a36Sopenharmony_ci if (!ret) 17462306a36Sopenharmony_ci constraints->enable_time = pval; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci constraints->soft_start = of_property_read_bool(np, 17762306a36Sopenharmony_ci "regulator-soft-start"); 17862306a36Sopenharmony_ci ret = of_property_read_u32(np, "regulator-active-discharge", &pval); 17962306a36Sopenharmony_ci if (!ret) { 18062306a36Sopenharmony_ci constraints->active_discharge = 18162306a36Sopenharmony_ci (pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE : 18262306a36Sopenharmony_ci REGULATOR_ACTIVE_DISCHARGE_DISABLE; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) { 18662306a36Sopenharmony_ci if (desc && desc->of_map_mode) { 18762306a36Sopenharmony_ci mode = desc->of_map_mode(pval); 18862306a36Sopenharmony_ci if (mode == REGULATOR_MODE_INVALID) 18962306a36Sopenharmony_ci pr_err("%pOFn: invalid mode %u\n", np, pval); 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci constraints->initial_mode = mode; 19262306a36Sopenharmony_ci } else { 19362306a36Sopenharmony_ci pr_warn("%pOFn: mapping for mode %d not defined\n", 19462306a36Sopenharmony_ci np, pval); 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci len = of_property_count_elems_of_size(np, "regulator-allowed-modes", 19962306a36Sopenharmony_ci sizeof(u32)); 20062306a36Sopenharmony_ci if (len > 0) { 20162306a36Sopenharmony_ci if (desc && desc->of_map_mode) { 20262306a36Sopenharmony_ci for (i = 0; i < len; i++) { 20362306a36Sopenharmony_ci ret = of_property_read_u32_index(np, 20462306a36Sopenharmony_ci "regulator-allowed-modes", i, &pval); 20562306a36Sopenharmony_ci if (ret) { 20662306a36Sopenharmony_ci pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d\n", 20762306a36Sopenharmony_ci np, i, ret); 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci mode = desc->of_map_mode(pval); 21162306a36Sopenharmony_ci if (mode == REGULATOR_MODE_INVALID) 21262306a36Sopenharmony_ci pr_err("%pOFn: invalid regulator-allowed-modes element %u\n", 21362306a36Sopenharmony_ci np, pval); 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci constraints->valid_modes_mask |= mode; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci if (constraints->valid_modes_mask) 21862306a36Sopenharmony_ci constraints->valid_ops_mask 21962306a36Sopenharmony_ci |= REGULATOR_CHANGE_MODE; 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci pr_warn("%pOFn: mode mapping not defined\n", np); 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-system-load", &pval)) 22662306a36Sopenharmony_ci constraints->system_load = pval; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (n_phandles) { 22962306a36Sopenharmony_ci constraints->max_spread = devm_kzalloc(dev, 23062306a36Sopenharmony_ci sizeof(*constraints->max_spread) * n_phandles, 23162306a36Sopenharmony_ci GFP_KERNEL); 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (!constraints->max_spread) 23462306a36Sopenharmony_ci return -ENOMEM; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci of_property_read_u32_array(np, "regulator-coupled-max-spread", 23762306a36Sopenharmony_ci constraints->max_spread, n_phandles); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!of_property_read_u32(np, "regulator-max-step-microvolt", 24162306a36Sopenharmony_ci &pval)) 24262306a36Sopenharmony_ci constraints->max_uV_step = pval; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci constraints->over_current_protection = of_property_read_bool(np, 24562306a36Sopenharmony_ci "regulator-over-current-protection"); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci of_get_regulator_prot_limits(np, constraints); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { 25062306a36Sopenharmony_ci switch (i) { 25162306a36Sopenharmony_ci case PM_SUSPEND_MEM: 25262306a36Sopenharmony_ci suspend_state = &constraints->state_mem; 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case PM_SUSPEND_MAX: 25562306a36Sopenharmony_ci suspend_state = &constraints->state_disk; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case PM_SUSPEND_STANDBY: 25862306a36Sopenharmony_ci suspend_state = &constraints->state_standby; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case PM_SUSPEND_ON: 26162306a36Sopenharmony_ci case PM_SUSPEND_TO_IDLE: 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci continue; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci suspend_np = of_get_child_by_name(np, regulator_states[i]); 26762306a36Sopenharmony_ci if (!suspend_np) 26862306a36Sopenharmony_ci continue; 26962306a36Sopenharmony_ci if (!suspend_state) { 27062306a36Sopenharmony_ci of_node_put(suspend_np); 27162306a36Sopenharmony_ci continue; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci if (!of_property_read_u32(suspend_np, "regulator-mode", 27562306a36Sopenharmony_ci &pval)) { 27662306a36Sopenharmony_ci if (desc && desc->of_map_mode) { 27762306a36Sopenharmony_ci mode = desc->of_map_mode(pval); 27862306a36Sopenharmony_ci if (mode == REGULATOR_MODE_INVALID) 27962306a36Sopenharmony_ci pr_err("%pOFn: invalid mode %u\n", 28062306a36Sopenharmony_ci np, pval); 28162306a36Sopenharmony_ci else 28262306a36Sopenharmony_ci suspend_state->mode = mode; 28362306a36Sopenharmony_ci } else { 28462306a36Sopenharmony_ci pr_warn("%pOFn: mapping for mode %d not defined\n", 28562306a36Sopenharmony_ci np, pval); 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (of_property_read_bool(suspend_np, 29062306a36Sopenharmony_ci "regulator-on-in-suspend")) 29162306a36Sopenharmony_ci suspend_state->enabled = ENABLE_IN_SUSPEND; 29262306a36Sopenharmony_ci else if (of_property_read_bool(suspend_np, 29362306a36Sopenharmony_ci "regulator-off-in-suspend")) 29462306a36Sopenharmony_ci suspend_state->enabled = DISABLE_IN_SUSPEND; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (!of_property_read_u32(suspend_np, 29762306a36Sopenharmony_ci "regulator-suspend-min-microvolt", &pval)) 29862306a36Sopenharmony_ci suspend_state->min_uV = pval; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!of_property_read_u32(suspend_np, 30162306a36Sopenharmony_ci "regulator-suspend-max-microvolt", &pval)) 30262306a36Sopenharmony_ci suspend_state->max_uV = pval; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!of_property_read_u32(suspend_np, 30562306a36Sopenharmony_ci "regulator-suspend-microvolt", &pval)) 30662306a36Sopenharmony_ci suspend_state->uV = pval; 30762306a36Sopenharmony_ci else /* otherwise use min_uV as default suspend voltage */ 30862306a36Sopenharmony_ci suspend_state->uV = suspend_state->min_uV; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (of_property_read_bool(suspend_np, 31162306a36Sopenharmony_ci "regulator-changeable-in-suspend")) 31262306a36Sopenharmony_ci suspend_state->changeable = true; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (i == PM_SUSPEND_MEM) 31562306a36Sopenharmony_ci constraints->initial_state = PM_SUSPEND_MEM; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci of_node_put(suspend_np); 31862306a36Sopenharmony_ci suspend_state = NULL; 31962306a36Sopenharmony_ci suspend_np = NULL; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/** 32662306a36Sopenharmony_ci * of_get_regulator_init_data - extract regulator_init_data structure info 32762306a36Sopenharmony_ci * @dev: device requesting for regulator_init_data 32862306a36Sopenharmony_ci * @node: regulator device node 32962306a36Sopenharmony_ci * @desc: regulator description 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * Populates regulator_init_data structure by extracting data from device 33262306a36Sopenharmony_ci * tree node, returns a pointer to the populated structure or NULL if memory 33362306a36Sopenharmony_ci * alloc fails. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_cistruct regulator_init_data *of_get_regulator_init_data(struct device *dev, 33662306a36Sopenharmony_ci struct device_node *node, 33762306a36Sopenharmony_ci const struct regulator_desc *desc) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct regulator_init_data *init_data; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (!node) 34262306a36Sopenharmony_ci return NULL; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL); 34562306a36Sopenharmony_ci if (!init_data) 34662306a36Sopenharmony_ci return NULL; /* Out of memory? */ 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (of_get_regulation_constraints(dev, node, &init_data, desc)) 34962306a36Sopenharmony_ci return NULL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return init_data; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_get_regulator_init_data); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistruct devm_of_regulator_matches { 35662306a36Sopenharmony_ci struct of_regulator_match *matches; 35762306a36Sopenharmony_ci unsigned int num_matches; 35862306a36Sopenharmony_ci}; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic void devm_of_regulator_put_matches(struct device *dev, void *res) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci struct devm_of_regulator_matches *devm_matches = res; 36362306a36Sopenharmony_ci int i; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci for (i = 0; i < devm_matches->num_matches; i++) 36662306a36Sopenharmony_ci of_node_put(devm_matches->matches[i].of_node); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/** 37062306a36Sopenharmony_ci * of_regulator_match - extract multiple regulator init data from device tree. 37162306a36Sopenharmony_ci * @dev: device requesting the data 37262306a36Sopenharmony_ci * @node: parent device node of the regulators 37362306a36Sopenharmony_ci * @matches: match table for the regulators 37462306a36Sopenharmony_ci * @num_matches: number of entries in match table 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * This function uses a match table specified by the regulator driver to 37762306a36Sopenharmony_ci * parse regulator init data from the device tree. @node is expected to 37862306a36Sopenharmony_ci * contain a set of child nodes, each providing the init data for one 37962306a36Sopenharmony_ci * regulator. The data parsed from a child node will be matched to a regulator 38062306a36Sopenharmony_ci * based on either the deprecated property regulator-compatible if present, 38162306a36Sopenharmony_ci * or otherwise the child node's name. Note that the match table is modified 38262306a36Sopenharmony_ci * in place and an additional of_node reference is taken for each matched 38362306a36Sopenharmony_ci * regulator. 38462306a36Sopenharmony_ci * 38562306a36Sopenharmony_ci * Returns the number of matches found or a negative error code on failure. 38662306a36Sopenharmony_ci */ 38762306a36Sopenharmony_ciint of_regulator_match(struct device *dev, struct device_node *node, 38862306a36Sopenharmony_ci struct of_regulator_match *matches, 38962306a36Sopenharmony_ci unsigned int num_matches) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci unsigned int count = 0; 39262306a36Sopenharmony_ci unsigned int i; 39362306a36Sopenharmony_ci const char *name; 39462306a36Sopenharmony_ci struct device_node *child; 39562306a36Sopenharmony_ci struct devm_of_regulator_matches *devm_matches; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (!dev || !node) 39862306a36Sopenharmony_ci return -EINVAL; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci devm_matches = devres_alloc(devm_of_regulator_put_matches, 40162306a36Sopenharmony_ci sizeof(struct devm_of_regulator_matches), 40262306a36Sopenharmony_ci GFP_KERNEL); 40362306a36Sopenharmony_ci if (!devm_matches) 40462306a36Sopenharmony_ci return -ENOMEM; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci devm_matches->matches = matches; 40762306a36Sopenharmony_ci devm_matches->num_matches = num_matches; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci devres_add(dev, devm_matches); 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci for (i = 0; i < num_matches; i++) { 41262306a36Sopenharmony_ci struct of_regulator_match *match = &matches[i]; 41362306a36Sopenharmony_ci match->init_data = NULL; 41462306a36Sopenharmony_ci match->of_node = NULL; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci for_each_child_of_node(node, child) { 41862306a36Sopenharmony_ci name = of_get_property(child, 41962306a36Sopenharmony_ci "regulator-compatible", NULL); 42062306a36Sopenharmony_ci if (!name) 42162306a36Sopenharmony_ci name = child->name; 42262306a36Sopenharmony_ci for (i = 0; i < num_matches; i++) { 42362306a36Sopenharmony_ci struct of_regulator_match *match = &matches[i]; 42462306a36Sopenharmony_ci if (match->of_node) 42562306a36Sopenharmony_ci continue; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (strcmp(match->name, name)) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci match->init_data = 43162306a36Sopenharmony_ci of_get_regulator_init_data(dev, child, 43262306a36Sopenharmony_ci match->desc); 43362306a36Sopenharmony_ci if (!match->init_data) { 43462306a36Sopenharmony_ci dev_err(dev, 43562306a36Sopenharmony_ci "failed to parse DT for regulator %pOFn\n", 43662306a36Sopenharmony_ci child); 43762306a36Sopenharmony_ci of_node_put(child); 43862306a36Sopenharmony_ci return -EINVAL; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci match->of_node = of_node_get(child); 44162306a36Sopenharmony_ci count++; 44262306a36Sopenharmony_ci break; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return count; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_regulator_match); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic struct 45162306a36Sopenharmony_cidevice_node *regulator_of_get_init_node(struct device *dev, 45262306a36Sopenharmony_ci const struct regulator_desc *desc) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct device_node *search, *child; 45562306a36Sopenharmony_ci const char *name; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!dev->of_node || !desc->of_match) 45862306a36Sopenharmony_ci return NULL; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (desc->regulators_node) { 46162306a36Sopenharmony_ci search = of_get_child_by_name(dev->of_node, 46262306a36Sopenharmony_ci desc->regulators_node); 46362306a36Sopenharmony_ci } else { 46462306a36Sopenharmony_ci search = of_node_get(dev->of_node); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (!strcmp(desc->of_match, search->name)) 46762306a36Sopenharmony_ci return search; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!search) { 47162306a36Sopenharmony_ci dev_dbg(dev, "Failed to find regulator container node '%s'\n", 47262306a36Sopenharmony_ci desc->regulators_node); 47362306a36Sopenharmony_ci return NULL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci for_each_available_child_of_node(search, child) { 47762306a36Sopenharmony_ci name = of_get_property(child, "regulator-compatible", NULL); 47862306a36Sopenharmony_ci if (!name) { 47962306a36Sopenharmony_ci if (!desc->of_match_full_name) 48062306a36Sopenharmony_ci name = child->name; 48162306a36Sopenharmony_ci else 48262306a36Sopenharmony_ci name = child->full_name; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (!strcmp(desc->of_match, name)) { 48662306a36Sopenharmony_ci of_node_put(search); 48762306a36Sopenharmony_ci /* 48862306a36Sopenharmony_ci * 'of_node_get(child)' is already performed by the 48962306a36Sopenharmony_ci * for_each loop. 49062306a36Sopenharmony_ci */ 49162306a36Sopenharmony_ci return child; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci of_node_put(search); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return NULL; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistruct regulator_init_data *regulator_of_get_init_data(struct device *dev, 50162306a36Sopenharmony_ci const struct regulator_desc *desc, 50262306a36Sopenharmony_ci struct regulator_config *config, 50362306a36Sopenharmony_ci struct device_node **node) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct device_node *child; 50662306a36Sopenharmony_ci struct regulator_init_data *init_data = NULL; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci child = regulator_of_get_init_node(config->dev, desc); 50962306a36Sopenharmony_ci if (!child) 51062306a36Sopenharmony_ci return NULL; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci init_data = of_get_regulator_init_data(dev, child, desc); 51362306a36Sopenharmony_ci if (!init_data) { 51462306a36Sopenharmony_ci dev_err(dev, "failed to parse DT for regulator %pOFn\n", child); 51562306a36Sopenharmony_ci goto error; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (desc->of_parse_cb) { 51962306a36Sopenharmony_ci int ret; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ret = desc->of_parse_cb(child, desc, config); 52262306a36Sopenharmony_ci if (ret) { 52362306a36Sopenharmony_ci if (ret == -EPROBE_DEFER) { 52462306a36Sopenharmony_ci of_node_put(child); 52562306a36Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci dev_err(dev, 52862306a36Sopenharmony_ci "driver callback failed to parse DT for regulator %pOFn\n", 52962306a36Sopenharmony_ci child); 53062306a36Sopenharmony_ci goto error; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci *node = child; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return init_data; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cierror: 53962306a36Sopenharmony_ci of_node_put(child); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci return NULL; 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistruct regulator_dev *of_find_regulator_by_node(struct device_node *np) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci struct device *dev; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci dev = class_find_device_by_of_node(®ulator_class, np); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci return dev ? dev_to_rdev(dev) : NULL; 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci/* 55462306a36Sopenharmony_ci * Returns number of regulators coupled with rdev. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ciint of_get_n_coupled(struct regulator_dev *rdev) 55762306a36Sopenharmony_ci{ 55862306a36Sopenharmony_ci struct device_node *node = rdev->dev.of_node; 55962306a36Sopenharmony_ci int n_phandles; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci n_phandles = of_count_phandle_with_args(node, 56262306a36Sopenharmony_ci "regulator-coupled-with", 56362306a36Sopenharmony_ci NULL); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci return (n_phandles > 0) ? n_phandles : 0; 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* Looks for "to_find" device_node in src's "regulator-coupled-with" property */ 56962306a36Sopenharmony_cistatic bool of_coupling_find_node(struct device_node *src, 57062306a36Sopenharmony_ci struct device_node *to_find, 57162306a36Sopenharmony_ci int *index) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci int n_phandles, i; 57462306a36Sopenharmony_ci bool found = false; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci n_phandles = of_count_phandle_with_args(src, 57762306a36Sopenharmony_ci "regulator-coupled-with", 57862306a36Sopenharmony_ci NULL); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci for (i = 0; i < n_phandles; i++) { 58162306a36Sopenharmony_ci struct device_node *tmp = of_parse_phandle(src, 58262306a36Sopenharmony_ci "regulator-coupled-with", i); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (!tmp) 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* found */ 58862306a36Sopenharmony_ci if (tmp == to_find) 58962306a36Sopenharmony_ci found = true; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci of_node_put(tmp); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci if (found) { 59462306a36Sopenharmony_ci *index = i; 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return found; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/** 60362306a36Sopenharmony_ci * of_check_coupling_data - Parse rdev's coupling properties and check data 60462306a36Sopenharmony_ci * consistency 60562306a36Sopenharmony_ci * @rdev: pointer to regulator_dev whose data is checked 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * Function checks if all the following conditions are met: 60862306a36Sopenharmony_ci * - rdev's max_spread is greater than 0 60962306a36Sopenharmony_ci * - all coupled regulators have the same max_spread 61062306a36Sopenharmony_ci * - all coupled regulators have the same number of regulator_dev phandles 61162306a36Sopenharmony_ci * - all regulators are linked to each other 61262306a36Sopenharmony_ci * 61362306a36Sopenharmony_ci * Returns true if all conditions are met. 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cibool of_check_coupling_data(struct regulator_dev *rdev) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct device_node *node = rdev->dev.of_node; 61862306a36Sopenharmony_ci int n_phandles = of_get_n_coupled(rdev); 61962306a36Sopenharmony_ci struct device_node *c_node; 62062306a36Sopenharmony_ci int index; 62162306a36Sopenharmony_ci int i; 62262306a36Sopenharmony_ci bool ret = true; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci /* iterate over rdev's phandles */ 62562306a36Sopenharmony_ci for (i = 0; i < n_phandles; i++) { 62662306a36Sopenharmony_ci int max_spread = rdev->constraints->max_spread[i]; 62762306a36Sopenharmony_ci int c_max_spread, c_n_phandles; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (max_spread <= 0) { 63062306a36Sopenharmony_ci dev_err(&rdev->dev, "max_spread value invalid\n"); 63162306a36Sopenharmony_ci return false; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci c_node = of_parse_phandle(node, 63562306a36Sopenharmony_ci "regulator-coupled-with", i); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (!c_node) 63862306a36Sopenharmony_ci ret = false; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci c_n_phandles = of_count_phandle_with_args(c_node, 64162306a36Sopenharmony_ci "regulator-coupled-with", 64262306a36Sopenharmony_ci NULL); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (c_n_phandles != n_phandles) { 64562306a36Sopenharmony_ci dev_err(&rdev->dev, "number of coupled reg phandles mismatch\n"); 64662306a36Sopenharmony_ci ret = false; 64762306a36Sopenharmony_ci goto clean; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if (!of_coupling_find_node(c_node, node, &index)) { 65162306a36Sopenharmony_ci dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n"); 65262306a36Sopenharmony_ci ret = false; 65362306a36Sopenharmony_ci goto clean; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread", 65762306a36Sopenharmony_ci index, &c_max_spread)) { 65862306a36Sopenharmony_ci ret = false; 65962306a36Sopenharmony_ci goto clean; 66062306a36Sopenharmony_ci } 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci if (c_max_spread != max_spread) { 66362306a36Sopenharmony_ci dev_err(&rdev->dev, 66462306a36Sopenharmony_ci "coupled regulators max_spread mismatch\n"); 66562306a36Sopenharmony_ci ret = false; 66662306a36Sopenharmony_ci goto clean; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ciclean: 67062306a36Sopenharmony_ci of_node_put(c_node); 67162306a36Sopenharmony_ci if (!ret) 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return ret; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/** 67962306a36Sopenharmony_ci * of_parse_coupled_regulator() - Get regulator_dev pointer from rdev's property 68062306a36Sopenharmony_ci * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse 68162306a36Sopenharmony_ci * "regulator-coupled-with" property 68262306a36Sopenharmony_ci * @index: Index in phandles array 68362306a36Sopenharmony_ci * 68462306a36Sopenharmony_ci * Returns the regulator_dev pointer parsed from DTS. If it has not been yet 68562306a36Sopenharmony_ci * registered, returns NULL 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_cistruct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev, 68862306a36Sopenharmony_ci int index) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci struct device_node *node = rdev->dev.of_node; 69162306a36Sopenharmony_ci struct device_node *c_node; 69262306a36Sopenharmony_ci struct regulator_dev *c_rdev; 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci c_node = of_parse_phandle(node, "regulator-coupled-with", index); 69562306a36Sopenharmony_ci if (!c_node) 69662306a36Sopenharmony_ci return NULL; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci c_rdev = of_find_regulator_by_node(c_node); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci of_node_put(c_node); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return c_rdev; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/* 70662306a36Sopenharmony_ci * Check if name is a supply name according to the '*-supply' pattern 70762306a36Sopenharmony_ci * return 0 if false 70862306a36Sopenharmony_ci * return length of supply name without the -supply 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_cistatic int is_supply_name(const char *name) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci int strs, i; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci strs = strlen(name); 71562306a36Sopenharmony_ci /* string need to be at minimum len(x-supply) */ 71662306a36Sopenharmony_ci if (strs < 8) 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci for (i = strs - 6; i > 0; i--) { 71962306a36Sopenharmony_ci /* find first '-' and check if right part is supply */ 72062306a36Sopenharmony_ci if (name[i] != '-') 72162306a36Sopenharmony_ci continue; 72262306a36Sopenharmony_ci if (strcmp(name + i + 1, "supply") != 0) 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci return i; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci return 0; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci/* 73062306a36Sopenharmony_ci * of_regulator_bulk_get_all - get multiple regulator consumers 73162306a36Sopenharmony_ci * 73262306a36Sopenharmony_ci * @dev: Device to supply 73362306a36Sopenharmony_ci * @np: device node to search for consumers 73462306a36Sopenharmony_ci * @consumers: Configuration of consumers; clients are stored here. 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * @return number of regulators on success, an errno on failure. 73762306a36Sopenharmony_ci * 73862306a36Sopenharmony_ci * This helper function allows drivers to get several regulator 73962306a36Sopenharmony_ci * consumers in one operation. If any of the regulators cannot be 74062306a36Sopenharmony_ci * acquired then any regulators that were allocated will be freed 74162306a36Sopenharmony_ci * before returning to the caller. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_ciint of_regulator_bulk_get_all(struct device *dev, struct device_node *np, 74462306a36Sopenharmony_ci struct regulator_bulk_data **consumers) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci int num_consumers = 0; 74762306a36Sopenharmony_ci struct regulator *tmp; 74862306a36Sopenharmony_ci struct property *prop; 74962306a36Sopenharmony_ci int i, n = 0, ret; 75062306a36Sopenharmony_ci char name[64]; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci *consumers = NULL; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * first pass: get numbers of xxx-supply 75662306a36Sopenharmony_ci * second pass: fill consumers 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_cirestart: 75962306a36Sopenharmony_ci for_each_property_of_node(np, prop) { 76062306a36Sopenharmony_ci i = is_supply_name(prop->name); 76162306a36Sopenharmony_ci if (i == 0) 76262306a36Sopenharmony_ci continue; 76362306a36Sopenharmony_ci if (!*consumers) { 76462306a36Sopenharmony_ci num_consumers++; 76562306a36Sopenharmony_ci continue; 76662306a36Sopenharmony_ci } else { 76762306a36Sopenharmony_ci memcpy(name, prop->name, i); 76862306a36Sopenharmony_ci name[i] = '\0'; 76962306a36Sopenharmony_ci tmp = regulator_get(dev, name); 77062306a36Sopenharmony_ci if (IS_ERR(tmp)) { 77162306a36Sopenharmony_ci ret = -EINVAL; 77262306a36Sopenharmony_ci goto error; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci (*consumers)[n].consumer = tmp; 77562306a36Sopenharmony_ci n++; 77662306a36Sopenharmony_ci continue; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci } 77962306a36Sopenharmony_ci if (*consumers) 78062306a36Sopenharmony_ci return num_consumers; 78162306a36Sopenharmony_ci if (num_consumers == 0) 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci *consumers = kmalloc_array(num_consumers, 78462306a36Sopenharmony_ci sizeof(struct regulator_bulk_data), 78562306a36Sopenharmony_ci GFP_KERNEL); 78662306a36Sopenharmony_ci if (!*consumers) 78762306a36Sopenharmony_ci return -ENOMEM; 78862306a36Sopenharmony_ci goto restart; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_cierror: 79162306a36Sopenharmony_ci while (--n >= 0) 79262306a36Sopenharmony_ci regulator_put(consumers[n]->consumer); 79362306a36Sopenharmony_ci return ret; 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_regulator_bulk_get_all); 796