18f446e6fSRajendra Nayak /*
28f446e6fSRajendra Nayak  * OF helpers for regulator framework
38f446e6fSRajendra Nayak  *
48f446e6fSRajendra Nayak  * Copyright (C) 2011 Texas Instruments, Inc.
58f446e6fSRajendra Nayak  * Rajendra Nayak <rnayak@ti.com>
68f446e6fSRajendra Nayak  *
78f446e6fSRajendra Nayak  * This program is free software; you can redistribute it and/or modify
88f446e6fSRajendra Nayak  * it under the terms of the GNU General Public License as published by
98f446e6fSRajendra Nayak  * the Free Software Foundation; either version 2 of the License, or
108f446e6fSRajendra Nayak  * (at your option) any later version.
118f446e6fSRajendra Nayak  */
128f446e6fSRajendra Nayak 
13e69af5e9SAxel Lin #include <linux/module.h>
148f446e6fSRajendra Nayak #include <linux/slab.h>
158f446e6fSRajendra Nayak #include <linux/of.h>
168f446e6fSRajendra Nayak #include <linux/regulator/machine.h>
17a0c7b164SMark Brown #include <linux/regulator/driver.h>
181c8fa58fSThierry Reding #include <linux/regulator/of_regulator.h>
198f446e6fSRajendra Nayak 
20a0c7b164SMark Brown #include "internal.h"
21a0c7b164SMark Brown 
228f446e6fSRajendra Nayak static void of_get_regulation_constraints(struct device_node *np,
238f446e6fSRajendra Nayak 					struct regulator_init_data **init_data)
248f446e6fSRajendra Nayak {
251e050eabSSergei Shtylyov 	const __be32 *min_uV, *max_uV;
268f446e6fSRajendra Nayak 	struct regulation_constraints *constraints = &(*init_data)->constraints;
2700c877c6SLaxman Dewangan 	int ret;
2800c877c6SLaxman Dewangan 	u32 pval;
298f446e6fSRajendra Nayak 
308f446e6fSRajendra Nayak 	constraints->name = of_get_property(np, "regulator-name", NULL);
318f446e6fSRajendra Nayak 
328f446e6fSRajendra Nayak 	min_uV = of_get_property(np, "regulator-min-microvolt", NULL);
338f446e6fSRajendra Nayak 	if (min_uV)
348f446e6fSRajendra Nayak 		constraints->min_uV = be32_to_cpu(*min_uV);
358f446e6fSRajendra Nayak 	max_uV = of_get_property(np, "regulator-max-microvolt", NULL);
368f446e6fSRajendra Nayak 	if (max_uV)
378f446e6fSRajendra Nayak 		constraints->max_uV = be32_to_cpu(*max_uV);
388f446e6fSRajendra Nayak 
398f446e6fSRajendra Nayak 	/* Voltage change possible? */
408f446e6fSRajendra Nayak 	if (constraints->min_uV != constraints->max_uV)
418f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
42ab62aa93SMark Brown 	/* Only one voltage?  Then make sure it's set. */
438a093049SKarol Lewandowski 	if (min_uV && max_uV && constraints->min_uV == constraints->max_uV)
44ab62aa93SMark Brown 		constraints->apply_uV = true;
458f446e6fSRajendra Nayak 
461e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
471e050eabSSergei Shtylyov 		constraints->uV_offset = pval;
481e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
491e050eabSSergei Shtylyov 		constraints->min_uA = pval;
501e050eabSSergei Shtylyov 	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
511e050eabSSergei Shtylyov 		constraints->max_uA = pval;
528f446e6fSRajendra Nayak 
538f446e6fSRajendra Nayak 	/* Current change possible? */
548f446e6fSRajendra Nayak 	if (constraints->min_uA != constraints->max_uA)
558f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
568f446e6fSRajendra Nayak 
571e050eabSSergei Shtylyov 	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
581e050eabSSergei Shtylyov 	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
591e050eabSSergei Shtylyov 	if (!constraints->always_on) /* status change should be possible. */
608f446e6fSRajendra Nayak 		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
616f0b2c69SYadwinder Singh Brar 
6293134c7bSKishon Vijay Abraham I 	if (of_property_read_bool(np, "regulator-allow-bypass"))
6393134c7bSKishon Vijay Abraham I 		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
6493134c7bSKishon Vijay Abraham I 
651e050eabSSergei Shtylyov 	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
661e050eabSSergei Shtylyov 	if (!ret) {
671e050eabSSergei Shtylyov 		if (pval)
681e050eabSSergei Shtylyov 			constraints->ramp_delay = pval;
691653ccf4SYadwinder Singh Brar 		else
701653ccf4SYadwinder Singh Brar 			constraints->ramp_disable = true;
711653ccf4SYadwinder Singh Brar 	}
7200c877c6SLaxman Dewangan 
7300c877c6SLaxman Dewangan 	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
7400c877c6SLaxman Dewangan 	if (!ret)
7500c877c6SLaxman Dewangan 		constraints->enable_time = pval;
768f446e6fSRajendra Nayak }
778f446e6fSRajendra Nayak 
788f446e6fSRajendra Nayak /**
798f446e6fSRajendra Nayak  * of_get_regulator_init_data - extract regulator_init_data structure info
808f446e6fSRajendra Nayak  * @dev: device requesting for regulator_init_data
818f446e6fSRajendra Nayak  *
828f446e6fSRajendra Nayak  * Populates regulator_init_data structure by extracting data from device
838f446e6fSRajendra Nayak  * tree node, returns a pointer to the populated struture or NULL if memory
848f446e6fSRajendra Nayak  * alloc fails.
858f446e6fSRajendra Nayak  */
86d9a861ccSShawn Guo struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
87d9a861ccSShawn Guo 						struct device_node *node)
888f446e6fSRajendra Nayak {
898f446e6fSRajendra Nayak 	struct regulator_init_data *init_data;
908f446e6fSRajendra Nayak 
91d9a861ccSShawn Guo 	if (!node)
928f446e6fSRajendra Nayak 		return NULL;
938f446e6fSRajendra Nayak 
948f446e6fSRajendra Nayak 	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
958f446e6fSRajendra Nayak 	if (!init_data)
968f446e6fSRajendra Nayak 		return NULL; /* Out of memory? */
978f446e6fSRajendra Nayak 
98d9a861ccSShawn Guo 	of_get_regulation_constraints(node, &init_data);
998f446e6fSRajendra Nayak 	return init_data;
1008f446e6fSRajendra Nayak }
101e69af5e9SAxel Lin EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
1021c8fa58fSThierry Reding 
10313b3fde8SCharles Keepax struct devm_of_regulator_matches {
10413b3fde8SCharles Keepax 	struct of_regulator_match *matches;
10513b3fde8SCharles Keepax 	unsigned int num_matches;
10613b3fde8SCharles Keepax };
10713b3fde8SCharles Keepax 
10813b3fde8SCharles Keepax static void devm_of_regulator_put_matches(struct device *dev, void *res)
10913b3fde8SCharles Keepax {
11013b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches = res;
11113b3fde8SCharles Keepax 	int i;
11213b3fde8SCharles Keepax 
11313b3fde8SCharles Keepax 	for (i = 0; i < devm_matches->num_matches; i++)
11413b3fde8SCharles Keepax 		of_node_put(devm_matches->matches[i].of_node);
11513b3fde8SCharles Keepax }
11613b3fde8SCharles Keepax 
1171c8fa58fSThierry Reding /**
11813511defSStephen Warren  * of_regulator_match - extract multiple regulator init data from device tree.
1191c8fa58fSThierry Reding  * @dev: device requesting the data
1201c8fa58fSThierry Reding  * @node: parent device node of the regulators
1211c8fa58fSThierry Reding  * @matches: match table for the regulators
1221c8fa58fSThierry Reding  * @num_matches: number of entries in match table
1231c8fa58fSThierry Reding  *
12413511defSStephen Warren  * This function uses a match table specified by the regulator driver to
12513511defSStephen Warren  * parse regulator init data from the device tree. @node is expected to
12613511defSStephen Warren  * contain a set of child nodes, each providing the init data for one
12713511defSStephen Warren  * regulator. The data parsed from a child node will be matched to a regulator
12813511defSStephen Warren  * based on either the deprecated property regulator-compatible if present,
12913511defSStephen Warren  * or otherwise the child node's name. Note that the match table is modified
130bd0dda74SCharles Keepax  * in place and an additional of_node reference is taken for each matched
131bd0dda74SCharles Keepax  * regulator.
1321c8fa58fSThierry Reding  *
1331c8fa58fSThierry Reding  * Returns the number of matches found or a negative error code on failure.
1341c8fa58fSThierry Reding  */
1351c8fa58fSThierry Reding int of_regulator_match(struct device *dev, struct device_node *node,
1361c8fa58fSThierry Reding 		       struct of_regulator_match *matches,
1371c8fa58fSThierry Reding 		       unsigned int num_matches)
1381c8fa58fSThierry Reding {
1391c8fa58fSThierry Reding 	unsigned int count = 0;
1401c8fa58fSThierry Reding 	unsigned int i;
14113511defSStephen Warren 	const char *name;
1425260cd2bSLaxman Dewangan 	struct device_node *child;
14313b3fde8SCharles Keepax 	struct devm_of_regulator_matches *devm_matches;
1441c8fa58fSThierry Reding 
1451c8fa58fSThierry Reding 	if (!dev || !node)
1461c8fa58fSThierry Reding 		return -EINVAL;
1471c8fa58fSThierry Reding 
14813b3fde8SCharles Keepax 	devm_matches = devres_alloc(devm_of_regulator_put_matches,
14913b3fde8SCharles Keepax 				    sizeof(struct devm_of_regulator_matches),
15013b3fde8SCharles Keepax 				    GFP_KERNEL);
15113b3fde8SCharles Keepax 	if (!devm_matches)
15213b3fde8SCharles Keepax 		return -ENOMEM;
15313b3fde8SCharles Keepax 
15413b3fde8SCharles Keepax 	devm_matches->matches = matches;
15513b3fde8SCharles Keepax 	devm_matches->num_matches = num_matches;
15613b3fde8SCharles Keepax 
15713b3fde8SCharles Keepax 	devres_add(dev, devm_matches);
15813b3fde8SCharles Keepax 
159a2f95c36SStephen Warren 	for (i = 0; i < num_matches; i++) {
160a2f95c36SStephen Warren 		struct of_regulator_match *match = &matches[i];
161a2f95c36SStephen Warren 		match->init_data = NULL;
162a2f95c36SStephen Warren 		match->of_node = NULL;
163a2f95c36SStephen Warren 	}
164a2f95c36SStephen Warren 
1655260cd2bSLaxman Dewangan 	for_each_child_of_node(node, child) {
16613511defSStephen Warren 		name = of_get_property(child,
1675260cd2bSLaxman Dewangan 					"regulator-compatible", NULL);
16813511defSStephen Warren 		if (!name)
16913511defSStephen Warren 			name = child->name;
1701c8fa58fSThierry Reding 		for (i = 0; i < num_matches; i++) {
1711c8fa58fSThierry Reding 			struct of_regulator_match *match = &matches[i];
1725260cd2bSLaxman Dewangan 			if (match->of_node)
1731c8fa58fSThierry Reding 				continue;
1741c8fa58fSThierry Reding 
17513511defSStephen Warren 			if (strcmp(match->name, name))
1765260cd2bSLaxman Dewangan 				continue;
1775260cd2bSLaxman Dewangan 
1785260cd2bSLaxman Dewangan 			match->init_data =
1795260cd2bSLaxman Dewangan 				of_get_regulator_init_data(dev, child);
1801c8fa58fSThierry Reding 			if (!match->init_data) {
1815260cd2bSLaxman Dewangan 				dev_err(dev,
1825260cd2bSLaxman Dewangan 					"failed to parse DT for regulator %s\n",
1831c8fa58fSThierry Reding 					child->name);
1841c8fa58fSThierry Reding 				return -EINVAL;
1851c8fa58fSThierry Reding 			}
186bd0dda74SCharles Keepax 			match->of_node = of_node_get(child);
1871c8fa58fSThierry Reding 			count++;
1885260cd2bSLaxman Dewangan 			break;
1895260cd2bSLaxman Dewangan 		}
1901c8fa58fSThierry Reding 	}
1911c8fa58fSThierry Reding 
1921c8fa58fSThierry Reding 	return count;
1931c8fa58fSThierry Reding }
1941c8fa58fSThierry Reding EXPORT_SYMBOL_GPL(of_regulator_match);
195a0c7b164SMark Brown 
196a0c7b164SMark Brown struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
197a0c7b164SMark Brown 					    const struct regulator_desc *desc,
198a0c7b164SMark Brown 					    struct device_node **node)
199a0c7b164SMark Brown {
200a0c7b164SMark Brown 	struct device_node *search, *child;
201a0c7b164SMark Brown 	struct regulator_init_data *init_data = NULL;
202a0c7b164SMark Brown 	const char *name;
203a0c7b164SMark Brown 
204a0c7b164SMark Brown 	if (!dev->of_node || !desc->of_match)
205a0c7b164SMark Brown 		return NULL;
206a0c7b164SMark Brown 
207a0c7b164SMark Brown 	if (desc->regulators_node)
208a0c7b164SMark Brown 		search = of_get_child_by_name(dev->of_node,
209a0c7b164SMark Brown 					      desc->regulators_node);
210a0c7b164SMark Brown 	else
211a0c7b164SMark Brown 		search = dev->of_node;
212a0c7b164SMark Brown 
213a0c7b164SMark Brown 	if (!search) {
214a0c7b164SMark Brown 		dev_err(dev, "Failed to find regulator container node\n");
215a0c7b164SMark Brown 		return NULL;
216a0c7b164SMark Brown 	}
217a0c7b164SMark Brown 
218a0c7b164SMark Brown 	for_each_child_of_node(search, child) {
219a0c7b164SMark Brown 		name = of_get_property(child, "regulator-compatible", NULL);
220a0c7b164SMark Brown 		if (!name)
221a0c7b164SMark Brown 			name = child->name;
222a0c7b164SMark Brown 
223a0c7b164SMark Brown 		if (strcmp(desc->of_match, name))
224a0c7b164SMark Brown 			continue;
225a0c7b164SMark Brown 
226a0c7b164SMark Brown 		init_data = of_get_regulator_init_data(dev, child);
227a0c7b164SMark Brown 		if (!init_data) {
228a0c7b164SMark Brown 			dev_err(dev,
229a0c7b164SMark Brown 				"failed to parse DT for regulator %s\n",
230a0c7b164SMark Brown 				child->name);
231a0c7b164SMark Brown 			break;
232a0c7b164SMark Brown 		}
233a0c7b164SMark Brown 
234a0c7b164SMark Brown 		of_node_get(child);
235a0c7b164SMark Brown 		*node = child;
236a0c7b164SMark Brown 		break;
237a0c7b164SMark Brown 	}
238a0c7b164SMark Brown 
239a0c7b164SMark Brown 	of_node_put(search);
240a0c7b164SMark Brown 
241a0c7b164SMark Brown 	return init_data;
242a0c7b164SMark Brown }
243