diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 48385318175a..419805cdd9d7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -77,6 +77,7 @@ struct regulator { | |||
77 | struct device *dev; | 77 | struct device *dev; |
78 | struct list_head list; | 78 | struct list_head list; |
79 | unsigned int always_on:1; | 79 | unsigned int always_on:1; |
80 | unsigned int bypass:1; | ||
80 | int uA_load; | 81 | int uA_load; |
81 | int min_uV; | 82 | int min_uV; |
82 | int max_uV; | 83 | int max_uV; |
@@ -394,6 +395,9 @@ static ssize_t regulator_status_show(struct device *dev, | |||
394 | case REGULATOR_STATUS_STANDBY: | 395 | case REGULATOR_STATUS_STANDBY: |
395 | label = "standby"; | 396 | label = "standby"; |
396 | break; | 397 | break; |
398 | case REGULATOR_STATUS_BYPASS: | ||
399 | label = "bypass"; | ||
400 | break; | ||
397 | case REGULATOR_STATUS_UNDEFINED: | 401 | case REGULATOR_STATUS_UNDEFINED: |
398 | label = "undefined"; | 402 | label = "undefined"; |
399 | break; | 403 | break; |
@@ -585,6 +589,27 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev, | |||
585 | static DEVICE_ATTR(suspend_standby_state, 0444, | 589 | static DEVICE_ATTR(suspend_standby_state, 0444, |
586 | regulator_suspend_standby_state_show, NULL); | 590 | regulator_suspend_standby_state_show, NULL); |
587 | 591 | ||
592 | static ssize_t regulator_bypass_show(struct device *dev, | ||
593 | struct device_attribute *attr, char *buf) | ||
594 | { | ||
595 | struct regulator_dev *rdev = dev_get_drvdata(dev); | ||
596 | const char *report; | ||
597 | bool bypass; | ||
598 | int ret; | ||
599 | |||
600 | ret = rdev->desc->ops->get_bypass(rdev, &bypass); | ||
601 | |||
602 | if (ret != 0) | ||
603 | report = "unknown"; | ||
604 | else if (bypass) | ||
605 | report = "enabled"; | ||
606 | else | ||
607 | report = "disabled"; | ||
608 | |||
609 | return sprintf(buf, "%s\n", report); | ||
610 | } | ||
611 | static DEVICE_ATTR(bypass, 0444, | ||
612 | regulator_bypass_show, NULL); | ||
588 | 613 | ||
589 | /* | 614 | /* |
590 | * These are the only attributes are present for all regulators. | 615 | * These are the only attributes are present for all regulators. |
@@ -2674,6 +2699,100 @@ out: | |||
2674 | EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); | 2699 | EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); |
2675 | 2700 | ||
2676 | /** | 2701 | /** |
2702 | * regulator_set_bypass_regmap - Default set_bypass() using regmap | ||
2703 | * | ||
2704 | * @rdev: device to operate on. | ||
2705 | * @enable: state to set. | ||
2706 | */ | ||
2707 | int regulator_set_bypass_regmap(struct regulator_dev *rdev, bool enable) | ||
2708 | { | ||
2709 | unsigned int val; | ||
2710 | |||
2711 | if (enable) | ||
2712 | val = rdev->desc->bypass_mask; | ||
2713 | else | ||
2714 | val = 0; | ||
2715 | |||
2716 | return regmap_update_bits(rdev->regmap, rdev->desc->bypass_reg, | ||
2717 | rdev->desc->bypass_mask, val); | ||
2718 | } | ||
2719 | EXPORT_SYMBOL_GPL(regulator_set_bypass_regmap); | ||
2720 | |||
2721 | /** | ||
2722 | * regulator_get_bypass_regmap - Default get_bypass() using regmap | ||
2723 | * | ||
2724 | * @rdev: device to operate on. | ||
2725 | * @enable: current state. | ||
2726 | */ | ||
2727 | int regulator_get_bypass_regmap(struct regulator_dev *rdev, bool *enable) | ||
2728 | { | ||
2729 | unsigned int val; | ||
2730 | int ret; | ||
2731 | |||
2732 | ret = regmap_read(rdev->regmap, rdev->desc->bypass_reg, &val); | ||
2733 | if (ret != 0) | ||
2734 | return ret; | ||
2735 | |||
2736 | *enable = val & rdev->desc->bypass_mask; | ||
2737 | |||
2738 | return 0; | ||
2739 | } | ||
2740 | EXPORT_SYMBOL_GPL(regulator_get_bypass_regmap); | ||
2741 | |||
2742 | /** | ||
2743 | * regulator_allow_bypass - allow the regulator to go into bypass mode | ||
2744 | * | ||
2745 | * @regulator: Regulator to configure | ||
2746 | * @allow: enable or disable bypass mode | ||
2747 | * | ||
2748 | * Allow the regulator to go into bypass mode if all other consumers | ||
2749 | * for the regulator also enable bypass mode and the machine | ||
2750 | * constraints allow this. Bypass mode means that the regulator is | ||
2751 | * simply passing the input directly to the output with no regulation. | ||
2752 | */ | ||
2753 | int regulator_allow_bypass(struct regulator *regulator, bool enable) | ||
2754 | { | ||
2755 | struct regulator_dev *rdev = regulator->rdev; | ||
2756 | int ret = 0; | ||
2757 | |||
2758 | if (!rdev->desc->ops->set_bypass) | ||
2759 | return 0; | ||
2760 | |||
2761 | if (rdev->constraints && | ||
2762 | !(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_BYPASS)) | ||
2763 | return 0; | ||
2764 | |||
2765 | mutex_lock(&rdev->mutex); | ||
2766 | |||
2767 | if (enable && !regulator->bypass) { | ||
2768 | rdev->bypass_count++; | ||
2769 | |||
2770 | if (rdev->bypass_count == rdev->open_count) { | ||
2771 | ret = rdev->desc->ops->set_bypass(rdev, enable); | ||
2772 | if (ret != 0) | ||
2773 | rdev->bypass_count--; | ||
2774 | } | ||
2775 | |||
2776 | } else if (!enable && regulator->bypass) { | ||
2777 | rdev->bypass_count--; | ||
2778 | |||
2779 | if (rdev->bypass_count != rdev->open_count) { | ||
2780 | ret = rdev->desc->ops->set_bypass(rdev, enable); | ||
2781 | if (ret != 0) | ||
2782 | rdev->bypass_count++; | ||
2783 | } | ||
2784 | } | ||
2785 | |||
2786 | if (ret == 0) | ||
2787 | regulator->bypass = enable; | ||
2788 | |||
2789 | mutex_unlock(&rdev->mutex); | ||
2790 | |||
2791 | return ret; | ||
2792 | } | ||
2793 | EXPORT_SYMBOL_GPL(regulator_allow_bypass); | ||
2794 | |||
2795 | /** | ||
2677 | * regulator_register_notifier - register regulator event notifier | 2796 | * regulator_register_notifier - register regulator event notifier |
2678 | * @regulator: regulator source | 2797 | * @regulator: regulator source |
2679 | * @nb: notifier block | 2798 | * @nb: notifier block |
@@ -3036,6 +3155,11 @@ static int add_regulator_attributes(struct regulator_dev *rdev) | |||
3036 | if (status < 0) | 3155 | if (status < 0) |
3037 | return status; | 3156 | return status; |
3038 | } | 3157 | } |
3158 | if (ops->get_bypass) { | ||
3159 | status = device_create_file(dev, &dev_attr_bypass); | ||
3160 | if (status < 0) | ||
3161 | return status; | ||
3162 | } | ||
3039 | 3163 | ||
3040 | /* some attributes are type-specific */ | 3164 | /* some attributes are type-specific */ |
3041 | if (rdev->desc->type == REGULATOR_CURRENT) { | 3165 | if (rdev->desc->type == REGULATOR_CURRENT) { |
@@ -3124,6 +3248,8 @@ static void rdev_init_debugfs(struct regulator_dev *rdev) | |||
3124 | &rdev->use_count); | 3248 | &rdev->use_count); |
3125 | debugfs_create_u32("open_count", 0444, rdev->debugfs, | 3249 | debugfs_create_u32("open_count", 0444, rdev->debugfs, |
3126 | &rdev->open_count); | 3250 | &rdev->open_count); |
3251 | debugfs_create_u32("bypass_count", 0444, rdev->debugfs, | ||
3252 | &rdev->bypass_count); | ||
3127 | } | 3253 | } |
3128 | 3254 | ||
3129 | /** | 3255 | /** |