diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 108 |
1 files changed, 107 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index d8e6a429e8ba..669d02160221 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/regulator/consumer.h> | 28 | #include <linux/regulator/consumer.h> |
29 | #include <linux/regulator/driver.h> | 29 | #include <linux/regulator/driver.h> |
30 | #include <linux/regulator/machine.h> | 30 | #include <linux/regulator/machine.h> |
31 | #include <linux/module.h> | ||
31 | 32 | ||
32 | #define CREATE_TRACE_POINTS | 33 | #define CREATE_TRACE_POINTS |
33 | #include <trace/events/regulator.h> | 34 | #include <trace/events/regulator.h> |
@@ -1425,7 +1426,7 @@ int regulator_enable(struct regulator *regulator) | |||
1425 | ret = _regulator_enable(rdev); | 1426 | ret = _regulator_enable(rdev); |
1426 | mutex_unlock(&rdev->mutex); | 1427 | mutex_unlock(&rdev->mutex); |
1427 | 1428 | ||
1428 | if (ret != 0) | 1429 | if (ret != 0 && rdev->supply) |
1429 | regulator_disable(rdev->supply); | 1430 | regulator_disable(rdev->supply); |
1430 | 1431 | ||
1431 | return ret; | 1432 | return ret; |
@@ -1552,6 +1553,68 @@ int regulator_force_disable(struct regulator *regulator) | |||
1552 | } | 1553 | } |
1553 | EXPORT_SYMBOL_GPL(regulator_force_disable); | 1554 | EXPORT_SYMBOL_GPL(regulator_force_disable); |
1554 | 1555 | ||
1556 | static void regulator_disable_work(struct work_struct *work) | ||
1557 | { | ||
1558 | struct regulator_dev *rdev = container_of(work, struct regulator_dev, | ||
1559 | disable_work.work); | ||
1560 | int count, i, ret; | ||
1561 | |||
1562 | mutex_lock(&rdev->mutex); | ||
1563 | |||
1564 | BUG_ON(!rdev->deferred_disables); | ||
1565 | |||
1566 | count = rdev->deferred_disables; | ||
1567 | rdev->deferred_disables = 0; | ||
1568 | |||
1569 | for (i = 0; i < count; i++) { | ||
1570 | ret = _regulator_disable(rdev); | ||
1571 | if (ret != 0) | ||
1572 | rdev_err(rdev, "Deferred disable failed: %d\n", ret); | ||
1573 | } | ||
1574 | |||
1575 | mutex_unlock(&rdev->mutex); | ||
1576 | |||
1577 | if (rdev->supply) { | ||
1578 | for (i = 0; i < count; i++) { | ||
1579 | ret = regulator_disable(rdev->supply); | ||
1580 | if (ret != 0) { | ||
1581 | rdev_err(rdev, | ||
1582 | "Supply disable failed: %d\n", ret); | ||
1583 | } | ||
1584 | } | ||
1585 | } | ||
1586 | } | ||
1587 | |||
1588 | /** | ||
1589 | * regulator_disable_deferred - disable regulator output with delay | ||
1590 | * @regulator: regulator source | ||
1591 | * @ms: miliseconds until the regulator is disabled | ||
1592 | * | ||
1593 | * Execute regulator_disable() on the regulator after a delay. This | ||
1594 | * is intended for use with devices that require some time to quiesce. | ||
1595 | * | ||
1596 | * NOTE: this will only disable the regulator output if no other consumer | ||
1597 | * devices have it enabled, the regulator device supports disabling and | ||
1598 | * machine constraints permit this operation. | ||
1599 | */ | ||
1600 | int regulator_disable_deferred(struct regulator *regulator, int ms) | ||
1601 | { | ||
1602 | struct regulator_dev *rdev = regulator->rdev; | ||
1603 | int ret; | ||
1604 | |||
1605 | mutex_lock(&rdev->mutex); | ||
1606 | rdev->deferred_disables++; | ||
1607 | mutex_unlock(&rdev->mutex); | ||
1608 | |||
1609 | ret = schedule_delayed_work(&rdev->disable_work, | ||
1610 | msecs_to_jiffies(ms)); | ||
1611 | if (ret < 0) | ||
1612 | return ret; | ||
1613 | else | ||
1614 | return 0; | ||
1615 | } | ||
1616 | EXPORT_SYMBOL_GPL(regulator_disable_deferred); | ||
1617 | |||
1555 | static int _regulator_is_enabled(struct regulator_dev *rdev) | 1618 | static int _regulator_is_enabled(struct regulator_dev *rdev) |
1556 | { | 1619 | { |
1557 | /* If we don't know then assume that the regulator is always on */ | 1620 | /* If we don't know then assume that the regulator is always on */ |
@@ -2622,6 +2685,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, | |||
2622 | INIT_LIST_HEAD(&rdev->consumer_list); | 2685 | INIT_LIST_HEAD(&rdev->consumer_list); |
2623 | INIT_LIST_HEAD(&rdev->list); | 2686 | INIT_LIST_HEAD(&rdev->list); |
2624 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); | 2687 | BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); |
2688 | INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); | ||
2625 | 2689 | ||
2626 | /* preform any regulator specific init */ | 2690 | /* preform any regulator specific init */ |
2627 | if (init_data->regulator_init) { | 2691 | if (init_data->regulator_init) { |
@@ -2729,6 +2793,7 @@ void regulator_unregister(struct regulator_dev *rdev) | |||
2729 | #ifdef CONFIG_DEBUG_FS | 2793 | #ifdef CONFIG_DEBUG_FS |
2730 | debugfs_remove_recursive(rdev->debugfs); | 2794 | debugfs_remove_recursive(rdev->debugfs); |
2731 | #endif | 2795 | #endif |
2796 | flush_work_sync(&rdev->disable_work.work); | ||
2732 | WARN_ON(rdev->open_count); | 2797 | WARN_ON(rdev->open_count); |
2733 | unset_regulator_supplies(rdev); | 2798 | unset_regulator_supplies(rdev); |
2734 | list_del(&rdev->list); | 2799 | list_del(&rdev->list); |
@@ -2907,6 +2972,43 @@ void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) | |||
2907 | } | 2972 | } |
2908 | EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); | 2973 | EXPORT_SYMBOL_GPL(regulator_get_init_drvdata); |
2909 | 2974 | ||
2975 | #ifdef CONFIG_DEBUG_FS | ||
2976 | static ssize_t supply_map_read_file(struct file *file, char __user *user_buf, | ||
2977 | size_t count, loff_t *ppos) | ||
2978 | { | ||
2979 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
2980 | ssize_t len, ret = 0; | ||
2981 | struct regulator_map *map; | ||
2982 | |||
2983 | if (!buf) | ||
2984 | return -ENOMEM; | ||
2985 | |||
2986 | list_for_each_entry(map, ®ulator_map_list, list) { | ||
2987 | len = snprintf(buf + ret, PAGE_SIZE - ret, | ||
2988 | "%s -> %s.%s\n", | ||
2989 | rdev_get_name(map->regulator), map->dev_name, | ||
2990 | map->supply); | ||
2991 | if (len >= 0) | ||
2992 | ret += len; | ||
2993 | if (ret > PAGE_SIZE) { | ||
2994 | ret = PAGE_SIZE; | ||
2995 | break; | ||
2996 | } | ||
2997 | } | ||
2998 | |||
2999 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | ||
3000 | |||
3001 | kfree(buf); | ||
3002 | |||
3003 | return ret; | ||
3004 | } | ||
3005 | |||
3006 | static const struct file_operations supply_map_fops = { | ||
3007 | .read = supply_map_read_file, | ||
3008 | .llseek = default_llseek, | ||
3009 | }; | ||
3010 | #endif | ||
3011 | |||
2910 | static int __init regulator_init(void) | 3012 | static int __init regulator_init(void) |
2911 | { | 3013 | { |
2912 | int ret; | 3014 | int ret; |
@@ -2919,6 +3021,10 @@ static int __init regulator_init(void) | |||
2919 | pr_warn("regulator: Failed to create debugfs directory\n"); | 3021 | pr_warn("regulator: Failed to create debugfs directory\n"); |
2920 | debugfs_root = NULL; | 3022 | debugfs_root = NULL; |
2921 | } | 3023 | } |
3024 | |||
3025 | if (IS_ERR(debugfs_create_file("supply_map", 0444, debugfs_root, | ||
3026 | NULL, &supply_map_fops))) | ||
3027 | pr_warn("regulator: Failed to create supplies debugfs\n"); | ||
2922 | #endif | 3028 | #endif |
2923 | 3029 | ||
2924 | regulator_dummy_init(); | 3030 | regulator_dummy_init(); |