diff options
| author | Charles Keepax <ckeepax@gmail.com> | 2015-03-05 10:39:20 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2015-03-05 11:42:14 -0500 |
| commit | 046db763aaaeb987ea01ea8c7e6d618e0ad1e6b8 (patch) | |
| tree | f894b2901d8b27144479af9a722696092d934340 | |
| parent | c517d838eb7d07bbe9507871fab3931deccff539 (diff) | |
regulator: core: Add devres versions of notifier registration
Add devm_regulator_register_notifier, this adds the resource against the
device for the consumer supply we are registering the notifier for. There
seem to be few use-cases where this wouldn't be the users intention and
this ensures the notifiers will always be removed at the correct time.
Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
| -rw-r--r-- | drivers/regulator/devres.c | 85 | ||||
| -rw-r--r-- | include/linux/regulator/consumer.h | 16 |
2 files changed, 101 insertions, 0 deletions
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 8f785bc9e510..6ec1d400adae 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c | |||
| @@ -413,3 +413,88 @@ void devm_regulator_bulk_unregister_supply_alias(struct device *dev, | |||
| 413 | devm_regulator_unregister_supply_alias(dev, id[i]); | 413 | devm_regulator_unregister_supply_alias(dev, id[i]); |
| 414 | } | 414 | } |
| 415 | EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); | 415 | EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); |
| 416 | |||
| 417 | struct regulator_notifier_match { | ||
| 418 | struct regulator *regulator; | ||
| 419 | struct notifier_block *nb; | ||
| 420 | }; | ||
| 421 | |||
| 422 | static int devm_regulator_match_notifier(struct device *dev, void *res, | ||
| 423 | void *data) | ||
| 424 | { | ||
| 425 | struct regulator_notifier_match *match = res; | ||
| 426 | struct regulator_notifier_match *target = data; | ||
| 427 | |||
| 428 | return match->regulator == target->regulator && match->nb == target->nb; | ||
| 429 | } | ||
| 430 | |||
| 431 | static void devm_regulator_destroy_notifier(struct device *dev, void *res) | ||
| 432 | { | ||
| 433 | struct regulator_notifier_match *match = res; | ||
| 434 | |||
| 435 | regulator_unregister_notifier(match->regulator, match->nb); | ||
| 436 | } | ||
| 437 | |||
| 438 | /** | ||
| 439 | * devm_regulator_register_notifier - Resource managed | ||
| 440 | * regulator_register_notifier | ||
| 441 | * | ||
| 442 | * @regulator: regulator source | ||
| 443 | * @nb: notifier block | ||
| 444 | * | ||
| 445 | * The notifier will be registers under the consumer device and be | ||
| 446 | * automatically be unregistered when the source device is unbound. | ||
| 447 | */ | ||
| 448 | int devm_regulator_register_notifier(struct regulator *regulator, | ||
| 449 | struct notifier_block *nb) | ||
| 450 | { | ||
| 451 | struct regulator_notifier_match *match; | ||
| 452 | int ret; | ||
| 453 | |||
| 454 | match = devres_alloc(devm_regulator_destroy_notifier, | ||
| 455 | sizeof(struct regulator_notifier_match), | ||
| 456 | GFP_KERNEL); | ||
| 457 | if (!match) | ||
| 458 | return -ENOMEM; | ||
| 459 | |||
| 460 | match->regulator = regulator; | ||
| 461 | match->nb = nb; | ||
| 462 | |||
| 463 | ret = regulator_register_notifier(regulator, nb); | ||
| 464 | if (ret < 0) { | ||
| 465 | devres_free(match); | ||
| 466 | return ret; | ||
| 467 | } | ||
| 468 | |||
| 469 | devres_add(regulator->dev, match); | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | EXPORT_SYMBOL_GPL(devm_regulator_register_notifier); | ||
| 474 | |||
| 475 | /** | ||
| 476 | * devm_regulator_unregister_notifier - Resource managed | ||
| 477 | * regulator_unregister_notifier() | ||
| 478 | * | ||
| 479 | * @regulator: regulator source | ||
| 480 | * @nb: notifier block | ||
| 481 | * | ||
| 482 | * Unregister a notifier registered with devm_regulator_register_notifier(). | ||
| 483 | * Normally this function will not need to be called and the resource | ||
| 484 | * management code will ensure that the resource is freed. | ||
| 485 | */ | ||
| 486 | void devm_regulator_unregister_notifier(struct regulator *regulator, | ||
| 487 | struct notifier_block *nb) | ||
| 488 | { | ||
| 489 | struct regulator_notifier_match match; | ||
| 490 | int rc; | ||
| 491 | |||
| 492 | match.regulator = regulator; | ||
| 493 | match.nb = nb; | ||
| 494 | |||
| 495 | rc = devres_release(regulator->dev, devm_regulator_destroy_notifier, | ||
| 496 | devm_regulator_match_notifier, &match); | ||
| 497 | if (rc != 0) | ||
| 498 | WARN_ON(rc); | ||
| 499 | } | ||
| 500 | EXPORT_SYMBOL_GPL(devm_regulator_unregister_notifier); | ||
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index d17e1ff7ad01..bd631ee5f1da 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h | |||
| @@ -252,8 +252,12 @@ int regulator_list_hardware_vsel(struct regulator *regulator, | |||
| 252 | /* regulator notifier block */ | 252 | /* regulator notifier block */ |
| 253 | int regulator_register_notifier(struct regulator *regulator, | 253 | int regulator_register_notifier(struct regulator *regulator, |
| 254 | struct notifier_block *nb); | 254 | struct notifier_block *nb); |
| 255 | int devm_regulator_register_notifier(struct regulator *regulator, | ||
| 256 | struct notifier_block *nb); | ||
| 255 | int regulator_unregister_notifier(struct regulator *regulator, | 257 | int regulator_unregister_notifier(struct regulator *regulator, |
| 256 | struct notifier_block *nb); | 258 | struct notifier_block *nb); |
| 259 | void devm_regulator_unregister_notifier(struct regulator *regulator, | ||
| 260 | struct notifier_block *nb); | ||
| 257 | 261 | ||
| 258 | /* driver data - core doesn't touch */ | 262 | /* driver data - core doesn't touch */ |
| 259 | void *regulator_get_drvdata(struct regulator *regulator); | 263 | void *regulator_get_drvdata(struct regulator *regulator); |
| @@ -515,12 +519,24 @@ static inline int regulator_register_notifier(struct regulator *regulator, | |||
| 515 | return 0; | 519 | return 0; |
| 516 | } | 520 | } |
| 517 | 521 | ||
| 522 | static inline int devm_regulator_register_notifier(struct regulator *regulator, | ||
| 523 | struct notifier_block *nb) | ||
| 524 | { | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 518 | static inline int regulator_unregister_notifier(struct regulator *regulator, | 528 | static inline int regulator_unregister_notifier(struct regulator *regulator, |
| 519 | struct notifier_block *nb) | 529 | struct notifier_block *nb) |
| 520 | { | 530 | { |
| 521 | return 0; | 531 | return 0; |
| 522 | } | 532 | } |
| 523 | 533 | ||
| 534 | static inline int devm_regulator_unregister_notifier(struct regulator *regulator, | ||
| 535 | struct notifier_block *nb) | ||
| 536 | { | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 524 | static inline void *regulator_get_drvdata(struct regulator *regulator) | 540 | static inline void *regulator_get_drvdata(struct regulator *regulator) |
| 525 | { | 541 | { |
| 526 | return NULL; | 542 | return NULL; |
