aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMatt Sealey <matt@genesi-usa.com>2013-01-21 13:25:45 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-01-26 22:22:30 -0500
commit2c8a5dcaa4143dfedf956a5349216ded3c3ad085 (patch)
treebedae85801df52e0509f82cfe636bc8113648c3a /drivers/regulator
parentccf3ed782a6e65e0355b36424e88d2d8b5f46e89 (diff)
regulator: mc13892: sanity check num_regulators parsed vs. registered
Imagine a situation where a device tree has a few regulators in an appropriate node: regulators { sw1 { .. }; vvideo { .. }; : vfake { .. }; vtypo { .. }; }; In the above example, the node name "vfake" is an attempt to match a regulator name inside the driver which just so happens to not exist. The node name "vtypo" represents an accidental typographical error in a regulator name which may have been introduced to a device tree. In these cases, the number of regulators the mc13892 driver thinks it has does not match the number of regulators it parsed and registered. Since it will go over this array based on this number, it will actually re-register regulator "0" (which happens to be SW1) over and over again until it reaches the number, resulting in messages on the kernel log such as these: SW1: at 1100 mV VVIDEO: at 2775mV : SW1: at 1100 mV SW1: at 1100 mV .. up to that number of "mismatched" regulators. Nobody using DT can/will consume these regulators, so it should not be possible for it to cause any real regulator problems or driver breakages, but it is an easy thing to miss in a kernel log and is an immediate indication of a problem with the device tree authoring. This patch effectively sanity checks the number of counted children of the regulators node vs. the number that actually matched driver names, and sets the appropriate num_regulators value. It also gives a little warning for device tree authors that they MAY have screwed something up, such that this patch does not hide the device tree authoring problem. Signed-off-by: Matt Sealey <matt@genesi-usa.com> Tested-by: Steev Klimaszewski <steev@genesi-usa.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/mc13892-regulator.c39
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c10
-rw-r--r--drivers/regulator/mc13xxx.h4
3 files changed, 47 insertions, 6 deletions
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 5dd8aaa5cfb8..9891aec47b57 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -535,15 +535,18 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
535 struct mc13xxx_regulator_init_data *mc13xxx_data; 535 struct mc13xxx_regulator_init_data *mc13xxx_data;
536 struct regulator_config config = { }; 536 struct regulator_config config = { };
537 int i, ret; 537 int i, ret;
538 int num_regulators = 0; 538 int num_regulators = 0, num_parsed;
539 u32 val; 539 u32 val;
540 540
541 num_regulators = mc13xxx_get_num_regulators_dt(pdev); 541 num_regulators = mc13xxx_get_num_regulators_dt(pdev);
542
542 if (num_regulators <= 0 && pdata) 543 if (num_regulators <= 0 && pdata)
543 num_regulators = pdata->num_regulators; 544 num_regulators = pdata->num_regulators;
544 if (num_regulators <= 0) 545 if (num_regulators <= 0)
545 return -EINVAL; 546 return -EINVAL;
546 547
548 num_parsed = num_regulators;
549
547 priv = devm_kzalloc(&pdev->dev, sizeof(*priv) + 550 priv = devm_kzalloc(&pdev->dev, sizeof(*priv) +
548 num_regulators * sizeof(priv->regulators[0]), 551 num_regulators * sizeof(priv->regulators[0]),
549 GFP_KERNEL); 552 GFP_KERNEL);
@@ -586,7 +589,39 @@ static int mc13892_regulator_probe(struct platform_device *pdev)
586 = mc13892_vcam_get_mode; 589 = mc13892_vcam_get_mode;
587 590
588 mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators, 591 mc13xxx_data = mc13xxx_parse_regulators_dt(pdev, mc13892_regulators,
589 ARRAY_SIZE(mc13892_regulators)); 592 ARRAY_SIZE(mc13892_regulators),
593 &num_parsed);
594
595 /*
596 * Perform a little sanity check on the regulator tree - if we found
597 * a number of regulators from mc13xxx_get_num_regulators_dt and
598 * then parsed a smaller number in mc13xxx_parse_regulators_dt then
599 * there is a regulator defined in the regulators node which has
600 * not matched any usable regulator in the driver. In this case,
601 * there is one missing and what will happen is the first regulator
602 * will get registered again.
603 *
604 * Fix this by basically making our number of registerable regulators
605 * equal to the number of regulators we parsed. We are allocating
606 * too much memory for priv, but this is unavoidable at this point.
607 *
608 * As an example of how this can happen, try making a typo in your
609 * regulators node (vviohi {} instead of viohi {}) so that the name
610 * does not match..
611 *
612 * The check will basically pass for platform data (non-DT) because
613 * mc13xxx_parse_regulators_dt for !CONFIG_OF will not touch num_parsed.
614 *
615 */
616 if (num_parsed != num_regulators) {
617 dev_warn(&pdev->dev,
618 "parsed %d != regulators %d - check your device tree!\n",
619 num_parsed, num_regulators);
620
621 num_regulators = num_parsed;
622 priv->num_regulators = num_regulators;
623 }
624
590 for (i = 0; i < num_regulators; i++) { 625 for (i = 0; i < num_regulators; i++) {
591 struct regulator_init_data *init_data; 626 struct regulator_init_data *init_data;
592 struct regulator_desc *desc; 627 struct regulator_desc *desc;
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 4ed89c654110..2ecf1d8b6a94 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -181,12 +181,14 @@ EXPORT_SYMBOL_GPL(mc13xxx_get_num_regulators_dt);
181 181
182struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( 182struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
183 struct platform_device *pdev, struct mc13xxx_regulator *regulators, 183 struct platform_device *pdev, struct mc13xxx_regulator *regulators,
184 int num_regulators) 184 int num_regulators, int *num_parsed)
185{ 185{
186 struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); 186 struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
187 struct mc13xxx_regulator_init_data *data, *p; 187 struct mc13xxx_regulator_init_data *data, *p;
188 struct device_node *parent, *child; 188 struct device_node *parent, *child;
189 int i; 189 int i, parsed = 0;
190
191 *num_parsed = 0;
190 192
191 of_node_get(pdev->dev.parent->of_node); 193 of_node_get(pdev->dev.parent->of_node);
192 parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators"); 194 parent = of_find_node_by_name(pdev->dev.parent->of_node, "regulators");
@@ -203,16 +205,20 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
203 for (i = 0; i < num_regulators; i++) { 205 for (i = 0; i < num_regulators; i++) {
204 if (!of_node_cmp(child->name, 206 if (!of_node_cmp(child->name,
205 regulators[i].desc.name)) { 207 regulators[i].desc.name)) {
208
206 p->id = i; 209 p->id = i;
207 p->init_data = of_get_regulator_init_data( 210 p->init_data = of_get_regulator_init_data(
208 &pdev->dev, child); 211 &pdev->dev, child);
209 p->node = child; 212 p->node = child;
210 p++; 213 p++;
214
215 parsed++;
211 break; 216 break;
212 } 217 }
213 } 218 }
214 } 219 }
215 220
221 *num_parsed = parsed;
216 return data; 222 return data;
217} 223}
218EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt); 224EXPORT_SYMBOL_GPL(mc13xxx_parse_regulators_dt);
diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h
index 06c8903f182a..007f83387fd6 100644
--- a/drivers/regulator/mc13xxx.h
+++ b/drivers/regulator/mc13xxx.h
@@ -39,7 +39,7 @@ extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
39extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev); 39extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
40extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( 40extern struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
41 struct platform_device *pdev, struct mc13xxx_regulator *regulators, 41 struct platform_device *pdev, struct mc13xxx_regulator *regulators,
42 int num_regulators); 42 int num_regulators, int *num_parsed);
43#else 43#else
44static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev) 44static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
45{ 45{
@@ -48,7 +48,7 @@ static inline int mc13xxx_get_num_regulators_dt(struct platform_device *pdev)
48 48
49static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt( 49static inline struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
50 struct platform_device *pdev, struct mc13xxx_regulator *regulators, 50 struct platform_device *pdev, struct mc13xxx_regulator *regulators,
51 int num_regulators) 51 int num_regulators, int *num_parsed)
52{ 52{
53 return NULL; 53 return NULL;
54} 54}