diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-01-30 14:29:31 -0500 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2015-02-02 15:01:51 -0500 |
commit | 39f802d6b6d9a922f2c7a9165f0a7a5b819a1e3f (patch) | |
tree | 3d98fc2cefaeb33c3208813e64765204d26b6ab8 /drivers/regulator | |
parent | 39138818a4f5c62d70f35504477c2509f982f211 (diff) |
regulator: Build sysfs entries with static attribute groups
Instead of calling device_create_file() manually after the device
registration, put all in attribute groups and filter the unwanted ones
via is_visible callback. This not only simplifies the code but also
avoids the possible race between the device registration and sysfs
registration.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/core.c | 235 |
1 files changed, 108 insertions, 127 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c2554d89d472..91d79b84358b 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) |
@@ -3434,126 +3410,136 @@ int regulator_mode_to_status(unsigned int mode) | |||
3434 | } | 3410 | } |
3435 | EXPORT_SYMBOL_GPL(regulator_mode_to_status); | 3411 | EXPORT_SYMBOL_GPL(regulator_mode_to_status); |
3436 | 3412 | ||
3413 | static struct attribute *regulator_dev_attrs[] = { | ||
3414 | &dev_attr_name.attr, | ||
3415 | &dev_attr_num_users.attr, | ||
3416 | &dev_attr_type.attr, | ||
3417 | &dev_attr_microvolts.attr, | ||
3418 | &dev_attr_microamps.attr, | ||
3419 | &dev_attr_opmode.attr, | ||
3420 | &dev_attr_state.attr, | ||
3421 | &dev_attr_status.attr, | ||
3422 | &dev_attr_bypass.attr, | ||
3423 | &dev_attr_requested_microamps.attr, | ||
3424 | &dev_attr_min_microvolts.attr, | ||
3425 | &dev_attr_max_microvolts.attr, | ||
3426 | &dev_attr_min_microamps.attr, | ||
3427 | &dev_attr_max_microamps.attr, | ||
3428 | &dev_attr_suspend_standby_state.attr, | ||
3429 | &dev_attr_suspend_mem_state.attr, | ||
3430 | &dev_attr_suspend_disk_state.attr, | ||
3431 | &dev_attr_suspend_standby_microvolts.attr, | ||
3432 | &dev_attr_suspend_mem_microvolts.attr, | ||
3433 | &dev_attr_suspend_disk_microvolts.attr, | ||
3434 | &dev_attr_suspend_standby_mode.attr, | ||
3435 | &dev_attr_suspend_mem_mode.attr, | ||
3436 | &dev_attr_suspend_disk_mode.attr, | ||
3437 | NULL | ||
3438 | }; | ||
3439 | |||
3437 | /* | 3440 | /* |
3438 | * To avoid cluttering sysfs (and memory) with useless state, only | 3441 | * To avoid cluttering sysfs (and memory) with useless state, only |
3439 | * create attributes that can be meaningfully displayed. | 3442 | * create attributes that can be meaningfully displayed. |
3440 | */ | 3443 | */ |
3441 | static int add_regulator_attributes(struct regulator_dev *rdev) | 3444 | static umode_t regulator_attr_is_visible(struct kobject *kobj, |
3445 | struct attribute *attr, int idx) | ||
3442 | { | 3446 | { |
3443 | struct device *dev = &rdev->dev; | 3447 | struct device *dev = kobj_to_dev(kobj); |
3448 | struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev); | ||
3444 | const struct regulator_ops *ops = rdev->desc->ops; | 3449 | const struct regulator_ops *ops = rdev->desc->ops; |
3445 | int status = 0; | 3450 | umode_t mode = attr->mode; |
3451 | |||
3452 | /* these three are always present */ | ||
3453 | if (attr == &dev_attr_name.attr || | ||
3454 | attr == &dev_attr_num_users.attr || | ||
3455 | attr == &dev_attr_type.attr) | ||
3456 | return mode; | ||
3446 | 3457 | ||
3447 | /* some attributes need specific methods to be displayed */ | 3458 | /* some attributes need specific methods to be displayed */ |
3448 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || | 3459 | if (attr == &dev_attr_microvolts.attr) { |
3449 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || | 3460 | if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || |
3450 | (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || | 3461 | (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || |
3451 | (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) { | 3462 | (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || |
3452 | status = device_create_file(dev, &dev_attr_microvolts); | 3463 | (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) |
3453 | if (status < 0) | 3464 | return mode; |
3454 | return status; | 3465 | return 0; |
3455 | } | ||
3456 | if (ops->get_current_limit) { | ||
3457 | status = device_create_file(dev, &dev_attr_microamps); | ||
3458 | if (status < 0) | ||
3459 | return status; | ||
3460 | } | ||
3461 | if (ops->get_mode) { | ||
3462 | status = device_create_file(dev, &dev_attr_opmode); | ||
3463 | if (status < 0) | ||
3464 | return status; | ||
3465 | } | ||
3466 | if (rdev->ena_pin || ops->is_enabled) { | ||
3467 | status = device_create_file(dev, &dev_attr_state); | ||
3468 | if (status < 0) | ||
3469 | return status; | ||
3470 | } | ||
3471 | if (ops->get_status) { | ||
3472 | status = device_create_file(dev, &dev_attr_status); | ||
3473 | if (status < 0) | ||
3474 | return status; | ||
3475 | } | ||
3476 | if (ops->get_bypass) { | ||
3477 | status = device_create_file(dev, &dev_attr_bypass); | ||
3478 | if (status < 0) | ||
3479 | return status; | ||
3480 | } | 3466 | } |
3481 | 3467 | ||
3468 | if (attr == &dev_attr_microamps.attr) | ||
3469 | return ops->get_current_limit ? mode : 0; | ||
3470 | |||
3471 | if (attr == &dev_attr_opmode.attr) | ||
3472 | return ops->get_mode ? mode : 0; | ||
3473 | |||
3474 | if (attr == &dev_attr_state.attr) | ||
3475 | return (rdev->ena_pin || ops->is_enabled) ? mode : 0; | ||
3476 | |||
3477 | if (attr == &dev_attr_status.attr) | ||
3478 | return ops->get_status ? mode : 0; | ||
3479 | |||
3480 | if (attr == &dev_attr_bypass.attr) | ||
3481 | return ops->get_bypass ? mode : 0; | ||
3482 | |||
3482 | /* some attributes are type-specific */ | 3483 | /* some attributes are type-specific */ |
3483 | if (rdev->desc->type == REGULATOR_CURRENT) { | 3484 | if (attr == &dev_attr_requested_microamps.attr) |
3484 | status = device_create_file(dev, &dev_attr_requested_microamps); | 3485 | return rdev->desc->type == REGULATOR_CURRENT ? mode : 0; |
3485 | if (status < 0) | ||
3486 | return status; | ||
3487 | } | ||
3488 | 3486 | ||
3489 | /* all the other attributes exist to support constraints; | 3487 | /* all the other attributes exist to support constraints; |
3490 | * don't show them if there are no constraints, or if the | 3488 | * don't show them if there are no constraints, or if the |
3491 | * relevant supporting methods are missing. | 3489 | * relevant supporting methods are missing. |
3492 | */ | 3490 | */ |
3493 | if (!rdev->constraints) | 3491 | if (!rdev->constraints) |
3494 | return status; | 3492 | return 0; |
3495 | 3493 | ||
3496 | /* constraints need specific supporting methods */ | 3494 | /* constraints need specific supporting methods */ |
3497 | if (ops->set_voltage || ops->set_voltage_sel) { | 3495 | if (attr == &dev_attr_min_microvolts.attr || |
3498 | status = device_create_file(dev, &dev_attr_min_microvolts); | 3496 | attr == &dev_attr_max_microvolts.attr) |
3499 | if (status < 0) | 3497 | return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; |
3500 | return status; | 3498 | |
3501 | status = device_create_file(dev, &dev_attr_max_microvolts); | 3499 | if (attr == &dev_attr_min_microamps.attr || |
3502 | if (status < 0) | 3500 | attr == &dev_attr_max_microamps.attr) |
3503 | return status; | 3501 | return ops->set_current_limit ? mode : 0; |
3504 | } | 3502 | |
3505 | if (ops->set_current_limit) { | 3503 | if (attr == &dev_attr_suspend_standby_state.attr || |
3506 | status = device_create_file(dev, &dev_attr_min_microamps); | 3504 | attr == &dev_attr_suspend_mem_state.attr || |
3507 | if (status < 0) | 3505 | attr == &dev_attr_suspend_disk_state.attr) |
3508 | return status; | 3506 | return mode; |
3509 | status = device_create_file(dev, &dev_attr_max_microamps); | 3507 | |
3510 | if (status < 0) | 3508 | if (attr == &dev_attr_suspend_standby_microvolts.attr || |
3511 | return status; | 3509 | attr == &dev_attr_suspend_mem_microvolts.attr || |
3512 | } | 3510 | attr == &dev_attr_suspend_disk_microvolts.attr) |
3513 | 3511 | return ops->set_suspend_voltage ? mode : 0; | |
3514 | status = device_create_file(dev, &dev_attr_suspend_standby_state); | 3512 | |
3515 | if (status < 0) | 3513 | if (attr == &dev_attr_suspend_standby_mode.attr || |
3516 | return status; | 3514 | attr == &dev_attr_suspend_mem_mode.attr || |
3517 | status = device_create_file(dev, &dev_attr_suspend_mem_state); | 3515 | attr == &dev_attr_suspend_disk_mode.attr) |
3518 | if (status < 0) | 3516 | return ops->set_suspend_mode ? mode : 0; |
3519 | return status; | 3517 | |
3520 | status = device_create_file(dev, &dev_attr_suspend_disk_state); | 3518 | return mode; |
3521 | if (status < 0) | 3519 | } |
3522 | return status; | 3520 | |
3521 | static const struct attribute_group regulator_dev_group = { | ||
3522 | .attrs = regulator_dev_attrs, | ||
3523 | .is_visible = regulator_attr_is_visible, | ||
3524 | }; | ||
3525 | |||
3526 | static const struct attribute_group *regulator_dev_groups[] = { | ||
3527 | ®ulator_dev_group, | ||
3528 | NULL | ||
3529 | }; | ||
3523 | 3530 | ||
3524 | if (ops->set_suspend_voltage) { | 3531 | static void regulator_dev_release(struct device *dev) |
3525 | status = device_create_file(dev, | 3532 | { |
3526 | &dev_attr_suspend_standby_microvolts); | 3533 | struct regulator_dev *rdev = dev_get_drvdata(dev); |
3527 | if (status < 0) | 3534 | kfree(rdev); |
3528 | return status; | ||
3529 | status = device_create_file(dev, | ||
3530 | &dev_attr_suspend_mem_microvolts); | ||
3531 | if (status < 0) | ||
3532 | return status; | ||
3533 | status = device_create_file(dev, | ||
3534 | &dev_attr_suspend_disk_microvolts); | ||
3535 | if (status < 0) | ||
3536 | return status; | ||
3537 | } | ||
3538 | |||
3539 | if (ops->set_suspend_mode) { | ||
3540 | status = device_create_file(dev, | ||
3541 | &dev_attr_suspend_standby_mode); | ||
3542 | if (status < 0) | ||
3543 | return status; | ||
3544 | status = device_create_file(dev, | ||
3545 | &dev_attr_suspend_mem_mode); | ||
3546 | if (status < 0) | ||
3547 | return status; | ||
3548 | status = device_create_file(dev, | ||
3549 | &dev_attr_suspend_disk_mode); | ||
3550 | if (status < 0) | ||
3551 | return status; | ||
3552 | } | ||
3553 | |||
3554 | return status; | ||
3555 | } | 3535 | } |
3556 | 3536 | ||
3537 | static struct class regulator_class = { | ||
3538 | .name = "regulator", | ||
3539 | .dev_release = regulator_dev_release, | ||
3540 | .dev_groups = regulator_dev_groups, | ||
3541 | }; | ||
3542 | |||
3557 | static void rdev_init_debugfs(struct regulator_dev *rdev) | 3543 | static void rdev_init_debugfs(struct regulator_dev *rdev) |
3558 | { | 3544 | { |
3559 | rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); | 3545 | rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); |
@@ -3692,11 +3678,6 @@ regulator_register(const struct regulator_desc *regulator_desc, | |||
3692 | if (ret < 0) | 3678 | if (ret < 0) |
3693 | goto scrub; | 3679 | goto scrub; |
3694 | 3680 | ||
3695 | /* add attributes supported by this regulator */ | ||
3696 | ret = add_regulator_attributes(rdev); | ||
3697 | if (ret < 0) | ||
3698 | goto scrub; | ||
3699 | |||
3700 | if (init_data && init_data->supply_regulator) | 3681 | if (init_data && init_data->supply_regulator) |
3701 | supply = init_data->supply_regulator; | 3682 | supply = init_data->supply_regulator; |
3702 | else if (regulator_desc->supply_name) | 3683 | else if (regulator_desc->supply_name) |