diff options
author | Mark Brown <broonie@kernel.org> | 2015-02-07 22:16:21 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-02-07 22:16:21 -0500 |
commit | a9877b606ceb40e5b7e08b62d5f10c65b761dcff (patch) | |
tree | 790fe9a40eec5e3962feb30f0e0779186c089292 | |
parent | 36818b821bde4f81a174010a529833df2a7f9087 (diff) | |
parent | 39f802d6b6d9a922f2c7a9165f0a7a5b819a1e3f (diff) |
Merge remote-tracking branch 'regulator/topic/core' into regulator-next
-rw-r--r-- | drivers/regulator/core.c | 241 |
1 files changed, 111 insertions, 130 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9c48fb32f660..43644ba52aae 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -632,30 +632,6 @@ static ssize_t regulator_bypass_show(struct device *dev, | |||
632 | static DEVICE_ATTR(bypass, 0444, | 632 | static DEVICE_ATTR(bypass, 0444, |
633 | regulator_bypass_show, NULL); | 633 | regulator_bypass_show, NULL); |
634 | 634 | ||
635 | /* | ||
636 | * These are the only attributes are present for all regulators. | ||
637 | * Other attributes are a function of regulator functionality. | ||
638 | */ | ||
639 | static struct attribute *regulator_dev_attrs[] = { | ||
640 | &dev_attr_name.attr, | ||
641 | &dev_attr_num_users.attr, | ||
642 | &dev_attr_type.attr, | ||
643 | NULL, | ||
644 | }; | ||
645 | ATTRIBUTE_GROUPS(regulator_dev); | ||
646 | |||
647 | static void regulator_dev_release(struct device *dev) | ||
648 | { | ||
649 | struct regulator_dev *rdev = dev_get_drvdata(dev); | ||
650 | kfree(rdev); | ||
651 | } | ||
652 | |||
653 | static struct class regulator_class = { | ||
654 | .name = "regulator", | ||
655 | .dev_release = regulator_dev_release, | ||
656 | .dev_groups = regulator_dev_groups, | ||
657 | }; | ||
658 | |||
659 | /* Calculate the new optimum regulator operating mode based on the new total | 635 | /* Calculate the new optimum regulator operating mode based on the new total |
660 | * consumer load. All locks held by caller */ | 636 | * consumer load. All locks held by caller */ |
661 | static void drms_uA_update(struct regulator_dev *rdev) | 637 | static void drms_uA_update(struct regulator_dev *rdev) |
@@ -3436,126 +3412,136 @@ int regulator_mode_to_status(unsigned int mode) | |||
3436 | } | 3412 | } |
3437 | EXPORT_SYMBOL_GPL(regulator_mode_to_status); | 3413 | EXPORT_SYMBOL_GPL(regulator_mode_to_status); |
3438 | 3414 | ||
3415 | static struct attribute *regulator_dev_attrs[] = { | ||
3416 | &dev_attr_name.attr, | ||
3417 | &dev_attr_num_users.attr, | ||
3418 | &dev_attr_type.attr, | ||
3419 | &dev_attr_microvolts.attr, | ||
3420 | &dev_attr_microamps.attr, | ||
3421 | &dev_attr_opmode.attr, | ||
3422 | &dev_attr_state.attr, | ||
3423 | &dev_attr_status.attr, | ||
3424 | &dev_attr_bypass.attr, | ||
3425 | &dev_attr_requested_microamps.attr, | ||
3426 | &dev_attr_min_microvolts.attr, | ||
3427 | &dev_attr_max_microvolts.attr, | ||
3428 | &dev_attr_min_microamps.attr, | ||
3429 | &dev_attr_max_microamps.attr, | ||
3430 | &dev_attr_suspend_standby_state.attr, | ||
3431 | &dev_attr_suspend_mem_state.attr, | ||
3432 | &dev_attr_suspend_disk_state.attr, | ||
3433 | &dev_attr_suspend_standby_microvolts.attr, | ||
3434 | &dev_attr_suspend_mem_microvolts.attr, | ||
3435 | &dev_attr_suspend_disk_microvolts.attr, | ||
3436 | &dev_attr_suspend_standby_mode.attr, | ||
3437 | &dev_attr_suspend_mem_mode.attr, | ||
3438 | &dev_attr_suspend_disk_mode.attr, | ||
3439 | NULL | ||
3440 | }; | ||
3441 | |||
3439 | /* | 3442 | /* |
3440 | * To avoid cluttering sysfs (and memory) with useless state, only | 3443 | * To avoid cluttering sysfs (and memory) with useless state, only |
3441 | * create attributes that can be meaningfully displayed. | 3444 | * create attributes that can be meaningfully displayed. |
3442 | */ | 3445 | */ |
3443 | static int add_regulator_attributes(struct regulator_dev *rdev) | 3446 | static umode_t regulator_attr_is_visible(struct kobject *kobj, |
3447 | struct attribute *attr, int idx) | ||
3444 | { | 3448 | { |
3445 | struct device *dev = &rdev->dev; | 3449 | struct device *dev = kobj_to_dev(kobj); |
3450 | struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev); | ||
3446 | const struct regulator_ops *ops = rdev->desc->ops; | 3451 | const struct regulator_ops *ops = rdev->desc->ops; |
3447 | int status = 0; | 3452 | umode_t mode = attr->mode; |
3453 | |||
3454 | /* these three are always present */ | ||
3455 | if (attr == &dev_attr_name.attr || | ||
3456 | attr == &dev_attr_num_users.attr || | ||
3457 | attr == &dev_attr_type.attr) | ||
3458 | return mode; | ||
3448 | 3459 | ||
3449 | /* some attributes need specific methods to be displayed */ | 3460 | /* some attributes need specific methods to be displayed */ |
3450 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || | 3461 | if (attr == &dev_attr_microvolts.attr) { |
3451 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || | 3462 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || |
3452 | (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || | 3463 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || |
3453 | (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) { | 3464 | (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || |
3454 | status = device_create_file(dev, &dev_attr_microvolts); | 3465 | (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) |
3455 | if (status < 0) | 3466 | return mode; |
3456 | return status; | 3467 | return 0; |
3457 | } | ||
3458 | if (ops->get_current_limit) { | ||
3459 | status = device_create_file(dev, &dev_attr_microamps); | ||
3460 | if (status < 0) | ||
3461 | return status; | ||
3462 | } | ||
3463 | if (ops->get_mode) { | ||
3464 | status = device_create_file(dev, &dev_attr_opmode); | ||
3465 | if (status < 0) | ||
3466 | return status; | ||
3467 | } | ||
3468 | if (rdev->ena_pin || ops->is_enabled) { | ||
3469 | status = device_create_file(dev, &dev_attr_state); | ||
3470 | if (status < 0) | ||
3471 | return status; | ||
3472 | } | ||
3473 | if (ops->get_status) { | ||
3474 | status = device_create_file(dev, &dev_attr_status); | ||
3475 | if (status < 0) | ||
3476 | return status; | ||
3477 | } | ||
3478 | if (ops->get_bypass) { | ||
3479 | status = device_create_file(dev, &dev_attr_bypass); | ||
3480 | if (status < 0) | ||
3481 | return status; | ||
3482 | } | 3468 | } |
3483 | 3469 | ||
3470 | if (attr == &dev_attr_microamps.attr) | ||
3471 | return ops->get_current_limit ? mode : 0; | ||
3472 | |||
3473 | if (attr == &dev_attr_opmode.attr) | ||
3474 | return ops->get_mode ? mode : 0; | ||
3475 | |||
3476 | if (attr == &dev_attr_state.attr) | ||
3477 | return (rdev->ena_pin || ops->is_enabled) ? mode : 0; | ||
3478 | |||
3479 | if (attr == &dev_attr_status.attr) | ||
3480 | return ops->get_status ? mode : 0; | ||
3481 | |||
3482 | if (attr == &dev_attr_bypass.attr) | ||
3483 | return ops->get_bypass ? mode : 0; | ||
3484 | |||
3484 | /* some attributes are type-specific */ | 3485 | /* some attributes are type-specific */ |
3485 | if (rdev->desc->type == REGULATOR_CURRENT) { | 3486 | if (attr == &dev_attr_requested_microamps.attr) |
3486 | status = device_create_file(dev, &dev_attr_requested_microamps); | 3487 | return rdev->desc->type == REGULATOR_CURRENT ? mode : 0; |
3487 | if (status < 0) | ||
3488 | return status; | ||
3489 | } | ||
3490 | 3488 | ||
3491 | /* all the other attributes exist to support constraints; | 3489 | /* all the other attributes exist to support constraints; |
3492 | * don't show them if there are no constraints, or if the | 3490 | * don't show them if there are no constraints, or if the |
3493 | * relevant supporting methods are missing. | 3491 | * relevant supporting methods are missing. |
3494 | */ | 3492 | */ |
3495 | if (!rdev->constraints) | 3493 | if (!rdev->constraints) |
3496 | return status; | 3494 | return 0; |
3497 | 3495 | ||
3498 | /* constraints need specific supporting methods */ | 3496 | /* constraints need specific supporting methods */ |
3499 | if (ops->set_voltage || ops->set_voltage_sel) { | 3497 | if (attr == &dev_attr_min_microvolts.attr || |
3500 | status = device_create_file(dev, &dev_attr_min_microvolts); | 3498 | attr == &dev_attr_max_microvolts.attr) |
3501 | if (status < 0) | 3499 | return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; |
3502 | return status; | 3500 | |
3503 | status = device_create_file(dev, &dev_attr_max_microvolts); | 3501 | if (attr == &dev_attr_min_microamps.attr || |
3504 | if (status < 0) | 3502 | attr == &dev_attr_max_microamps.attr) |
3505 | return status; | 3503 | return ops->set_current_limit ? mode : 0; |
3506 | } | 3504 | |
3507 | if (ops->set_current_limit) { | 3505 | if (attr == &dev_attr_suspend_standby_state.attr || |
3508 | status = device_create_file(dev, &dev_attr_min_microamps); | 3506 | attr == &dev_attr_suspend_mem_state.attr || |
3509 | if (status < 0) | 3507 | attr == &dev_attr_suspend_disk_state.attr) |
3510 | return status; | 3508 | return mode; |
3511 | status = device_create_file(dev, &dev_attr_max_microamps); | 3509 | |
3512 | if (status < 0) | 3510 | if (attr == &dev_attr_suspend_standby_microvolts.attr || |
3513 | return status; | 3511 | attr == &dev_attr_suspend_mem_microvolts.attr || |
3514 | } | 3512 | attr == &dev_attr_suspend_disk_microvolts.attr) |
3515 | 3513 | return ops->set_suspend_voltage ? mode : 0; | |
3516 | status = device_create_file(dev, &dev_attr_suspend_standby_state); | 3514 | |
3517 | if (status < 0) | 3515 | if (attr == &dev_attr_suspend_standby_mode.attr || |
3518 | return status; | 3516 | attr == &dev_attr_suspend_mem_mode.attr || |
3519 | status = device_create_file(dev, &dev_attr_suspend_mem_state); | 3517 | attr == &dev_attr_suspend_disk_mode.attr) |
3520 | if (status < 0) | 3518 | return ops->set_suspend_mode ? mode : 0; |
3521 | return status; | 3519 | |
3522 | status = device_create_file(dev, &dev_attr_suspend_disk_state); | 3520 | return mode; |
3523 | if (status < 0) | 3521 | } |
3524 | return status; | 3522 | |
3523 | static const struct attribute_group regulator_dev_group = { | ||
3524 | .attrs = regulator_dev_attrs, | ||
3525 | .is_visible = regulator_attr_is_visible, | ||
3526 | }; | ||
3527 | |||
3528 | static const struct attribute_group *regulator_dev_groups[] = { | ||
3529 | ®ulator_dev_group, | ||
3530 | NULL | ||
3531 | }; | ||
3525 | 3532 | ||
3526 | if (ops->set_suspend_voltage) { | 3533 | static void regulator_dev_release(struct device *dev) |
3527 | status = device_create_file(dev, | 3534 | { |
3528 | &dev_attr_suspend_standby_microvolts); | 3535 | struct regulator_dev *rdev = dev_get_drvdata(dev); |
3529 | if (status < 0) | 3536 | kfree(rdev); |
3530 | return status; | ||
3531 | status = device_create_file(dev, | ||
3532 | &dev_attr_suspend_mem_microvolts); | ||
3533 | if (status < 0) | ||
3534 | return status; | ||
3535 | status = device_create_file(dev, | ||
3536 | &dev_attr_suspend_disk_microvolts); | ||
3537 | if (status < 0) | ||
3538 | return status; | ||
3539 | } | ||
3540 | |||
3541 | if (ops->set_suspend_mode) { | ||
3542 | status = device_create_file(dev, | ||
3543 | &dev_attr_suspend_standby_mode); | ||
3544 | if (status < 0) | ||
3545 | return status; | ||
3546 | status = device_create_file(dev, | ||
3547 | &dev_attr_suspend_mem_mode); | ||
3548 | if (status < 0) | ||
3549 | return status; | ||
3550 | status = device_create_file(dev, | ||
3551 | &dev_attr_suspend_disk_mode); | ||
3552 | if (status < 0) | ||
3553 | return status; | ||
3554 | } | ||
3555 | |||
3556 | return status; | ||
3557 | } | 3537 | } |
3558 | 3538 | ||
3539 | static struct class regulator_class = { | ||
3540 | .name = "regulator", | ||
3541 | .dev_release = regulator_dev_release, | ||
3542 | .dev_groups = regulator_dev_groups, | ||
3543 | }; | ||
3544 | |||
3559 | static void rdev_init_debugfs(struct regulator_dev *rdev) | 3545 | static void rdev_init_debugfs(struct regulator_dev *rdev) |
3560 | { | 3546 | { |
3561 | rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); | 3547 | rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); |
@@ -3587,7 +3573,7 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3587 | { | 3573 | { |
3588 | const struct regulation_constraints *constraints = NULL; | 3574 | const struct regulation_constraints *constraints = NULL; |
3589 | const struct regulator_init_data *init_data; | 3575 | const struct regulator_init_data *init_data; |
3590 | static atomic_t regulator_no = ATOMIC_INIT(0); | 3576 | static atomic_t regulator_no = ATOMIC_INIT(-1); |
3591 | struct regulator_dev *rdev; | 3577 | struct regulator_dev *rdev; |
3592 | struct device *dev; | 3578 | struct device *dev; |
3593 | int ret, i; | 3579 | int ret, i; |
@@ -3660,8 +3646,8 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3660 | /* register with sysfs */ | 3646 | /* register with sysfs */ |
3661 | rdev->dev.class = ®ulator_class; | 3647 | rdev->dev.class = ®ulator_class; |
3662 | rdev->dev.parent = dev; | 3648 | rdev->dev.parent = dev; |
3663 | dev_set_name(&rdev->dev, "regulator.%d", | 3649 | dev_set_name(&rdev->dev, "regulator.%lu", |
3664 | atomic_inc_return(®ulator_no) - 1); | 3650 | (unsigned long) atomic_inc_return(®ulator_no)); |
3665 | ret = device_register(&rdev->dev); | 3651 | ret = device_register(&rdev->dev); |
3666 | if (ret != 0) { | 3652 | if (ret != 0) { |
3667 | put_device(&rdev->dev); | 3653 | put_device(&rdev->dev); |
@@ -3694,11 +3680,6 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3694 | if (ret < 0) | 3680 | if (ret < 0) |
3695 | goto scrub; | 3681 | goto scrub; |
3696 | 3682 | ||
3697 | /* add attributes supported by this regulator */ | ||
3698 | ret = add_regulator_attributes(rdev); | ||
3699 | if (ret < 0) | ||
3700 | goto scrub; | ||
3701 | |||
3702 | if (init_data && init_data->supply_regulator) | 3683 | if (init_data && init_data->supply_regulator) |
3703 | supply = init_data->supply_regulator; | 3684 | supply = init_data->supply_regulator; |
3704 | else if (regulator_desc->supply_name) | 3685 | else if (regulator_desc->supply_name) |