diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 116 |
1 files changed, 115 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9fa20957847..3ffc6979d16 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1629,6 +1629,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1629 | int min_uV, int max_uV) | 1629 | int min_uV, int max_uV) |
1630 | { | 1630 | { |
1631 | int ret; | 1631 | int ret; |
1632 | int delay = 0; | ||
1632 | unsigned int selector; | 1633 | unsigned int selector; |
1633 | 1634 | ||
1634 | trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); | 1635 | trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); |
@@ -1662,6 +1663,22 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1662 | } | 1663 | } |
1663 | } | 1664 | } |
1664 | 1665 | ||
1666 | /* | ||
1667 | * If we can't obtain the old selector there is not enough | ||
1668 | * info to call set_voltage_time_sel(). | ||
1669 | */ | ||
1670 | if (rdev->desc->ops->set_voltage_time_sel && | ||
1671 | rdev->desc->ops->get_voltage_sel) { | ||
1672 | unsigned int old_selector = 0; | ||
1673 | |||
1674 | ret = rdev->desc->ops->get_voltage_sel(rdev); | ||
1675 | if (ret < 0) | ||
1676 | return ret; | ||
1677 | old_selector = ret; | ||
1678 | delay = rdev->desc->ops->set_voltage_time_sel(rdev, | ||
1679 | old_selector, selector); | ||
1680 | } | ||
1681 | |||
1665 | if (best_val != INT_MAX) { | 1682 | if (best_val != INT_MAX) { |
1666 | ret = rdev->desc->ops->set_voltage_sel(rdev, selector); | 1683 | ret = rdev->desc->ops->set_voltage_sel(rdev, selector); |
1667 | selector = best_val; | 1684 | selector = best_val; |
@@ -1672,6 +1689,14 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, | |||
1672 | ret = -EINVAL; | 1689 | ret = -EINVAL; |
1673 | } | 1690 | } |
1674 | 1691 | ||
1692 | /* Insert any necessary delays */ | ||
1693 | if (delay >= 1000) { | ||
1694 | mdelay(delay / 1000); | ||
1695 | udelay(delay % 1000); | ||
1696 | } else if (delay) { | ||
1697 | udelay(delay); | ||
1698 | } | ||
1699 | |||
1675 | if (ret == 0) | 1700 | if (ret == 0) |
1676 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, | 1701 | _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, |
1677 | NULL); | 1702 | NULL); |
@@ -1740,6 +1765,51 @@ out: | |||
1740 | EXPORT_SYMBOL_GPL(regulator_set_voltage); | 1765 | EXPORT_SYMBOL_GPL(regulator_set_voltage); |
1741 | 1766 | ||
1742 | /** | 1767 | /** |
1768 | * regulator_set_voltage_time - get raise/fall time | ||
1769 | * @regulator: regulator source | ||
1770 | * @old_uV: starting voltage in microvolts | ||
1771 | * @new_uV: target voltage in microvolts | ||
1772 | * | ||
1773 | * Provided with the starting and ending voltage, this function attempts to | ||
1774 | * calculate the time in microseconds required to rise or fall to this new | ||
1775 | * voltage. | ||
1776 | */ | ||
1777 | int regulator_set_voltage_time(struct regulator *regulator, | ||
1778 | int old_uV, int new_uV) | ||
1779 | { | ||
1780 | struct regulator_dev *rdev = regulator->rdev; | ||
1781 | struct regulator_ops *ops = rdev->desc->ops; | ||
1782 | int old_sel = -1; | ||
1783 | int new_sel = -1; | ||
1784 | int voltage; | ||
1785 | int i; | ||
1786 | |||
1787 | /* Currently requires operations to do this */ | ||
1788 | if (!ops->list_voltage || !ops->set_voltage_time_sel | ||
1789 | || !rdev->desc->n_voltages) | ||
1790 | return -EINVAL; | ||
1791 | |||
1792 | for (i = 0; i < rdev->desc->n_voltages; i++) { | ||
1793 | /* We only look for exact voltage matches here */ | ||
1794 | voltage = regulator_list_voltage(regulator, i); | ||
1795 | if (voltage < 0) | ||
1796 | return -EINVAL; | ||
1797 | if (voltage == 0) | ||
1798 | continue; | ||
1799 | if (voltage == old_uV) | ||
1800 | old_sel = i; | ||
1801 | if (voltage == new_uV) | ||
1802 | new_sel = i; | ||
1803 | } | ||
1804 | |||
1805 | if (old_sel < 0 || new_sel < 0) | ||
1806 | return -EINVAL; | ||
1807 | |||
1808 | return ops->set_voltage_time_sel(rdev, old_sel, new_sel); | ||
1809 | } | ||
1810 | EXPORT_SYMBOL_GPL(regulator_set_voltage_time); | ||
1811 | |||
1812 | /** | ||
1743 | * regulator_sync_voltage - re-apply last regulator output voltage | 1813 | * regulator_sync_voltage - re-apply last regulator output voltage |
1744 | * @regulator: regulator source | 1814 | * @regulator: regulator source |
1745 | * | 1815 | * |
@@ -2565,8 +2635,11 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, | |||
2565 | init_data->consumer_supplies[i].dev, | 2635 | init_data->consumer_supplies[i].dev, |
2566 | init_data->consumer_supplies[i].dev_name, | 2636 | init_data->consumer_supplies[i].dev_name, |
2567 | init_data->consumer_supplies[i].supply); | 2637 | init_data->consumer_supplies[i].supply); |
2568 | if (ret < 0) | 2638 | if (ret < 0) { |
2639 | dev_err(dev, "Failed to set supply %s\n", | ||
2640 | init_data->consumer_supplies[i].supply); | ||
2569 | goto unset_supplies; | 2641 | goto unset_supplies; |
2642 | } | ||
2570 | } | 2643 | } |
2571 | 2644 | ||
2572 | list_add(&rdev->list, ®ulator_list); | 2645 | list_add(&rdev->list, ®ulator_list); |
@@ -2653,6 +2726,47 @@ out: | |||
2653 | EXPORT_SYMBOL_GPL(regulator_suspend_prepare); | 2726 | EXPORT_SYMBOL_GPL(regulator_suspend_prepare); |
2654 | 2727 | ||
2655 | /** | 2728 | /** |
2729 | * regulator_suspend_finish - resume regulators from system wide suspend | ||
2730 | * | ||
2731 | * Turn on regulators that might be turned off by regulator_suspend_prepare | ||
2732 | * and that should be turned on according to the regulators properties. | ||
2733 | */ | ||
2734 | int regulator_suspend_finish(void) | ||
2735 | { | ||
2736 | struct regulator_dev *rdev; | ||
2737 | int ret = 0, error; | ||
2738 | |||
2739 | mutex_lock(®ulator_list_mutex); | ||
2740 | list_for_each_entry(rdev, ®ulator_list, list) { | ||
2741 | struct regulator_ops *ops = rdev->desc->ops; | ||
2742 | |||
2743 | mutex_lock(&rdev->mutex); | ||
2744 | if ((rdev->use_count > 0 || rdev->constraints->always_on) && | ||
2745 | ops->enable) { | ||
2746 | error = ops->enable(rdev); | ||
2747 | if (error) | ||
2748 | ret = error; | ||
2749 | } else { | ||
2750 | if (!has_full_constraints) | ||
2751 | goto unlock; | ||
2752 | if (!ops->disable) | ||
2753 | goto unlock; | ||
2754 | if (ops->is_enabled && !ops->is_enabled(rdev)) | ||
2755 | goto unlock; | ||
2756 | |||
2757 | error = ops->disable(rdev); | ||
2758 | if (error) | ||
2759 | ret = error; | ||
2760 | } | ||
2761 | unlock: | ||
2762 | mutex_unlock(&rdev->mutex); | ||
2763 | } | ||
2764 | mutex_unlock(®ulator_list_mutex); | ||
2765 | return ret; | ||
2766 | } | ||
2767 | EXPORT_SYMBOL_GPL(regulator_suspend_finish); | ||
2768 | |||
2769 | /** | ||
2656 | * regulator_has_full_constraints - the system has fully specified constraints | 2770 | * regulator_has_full_constraints - the system has fully specified constraints |
2657 | * | 2771 | * |
2658 | * Calling this function will cause the regulator API to disable all | 2772 | * Calling this function will cause the regulator API to disable all |