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