18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// core.c -- Voltage/Current Regulator framework. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright 2007, 2008 Wolfson Microelectronics PLC. 68c2ecf20Sopenharmony_ci// Copyright 2008 SlimLogic Ltd. 78c2ecf20Sopenharmony_ci// 88c2ecf20Sopenharmony_ci// Author: Liam Girdwood <lrg@slimlogic.co.uk> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 138c2ecf20Sopenharmony_ci#include <linux/device.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/async.h> 168c2ecf20Sopenharmony_ci#include <linux/err.h> 178c2ecf20Sopenharmony_ci#include <linux/mutex.h> 188c2ecf20Sopenharmony_ci#include <linux/suspend.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/of.h> 228c2ecf20Sopenharmony_ci#include <linux/regmap.h> 238c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 248c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 258c2ecf20Sopenharmony_ci#include <linux/regulator/coupler.h> 268c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 278c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 318c2ecf20Sopenharmony_ci#include <trace/events/regulator.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include "dummy.h" 348c2ecf20Sopenharmony_ci#include "internal.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define rdev_crit(rdev, fmt, ...) \ 378c2ecf20Sopenharmony_ci pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 388c2ecf20Sopenharmony_ci#define rdev_err(rdev, fmt, ...) \ 398c2ecf20Sopenharmony_ci pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 408c2ecf20Sopenharmony_ci#define rdev_warn(rdev, fmt, ...) \ 418c2ecf20Sopenharmony_ci pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 428c2ecf20Sopenharmony_ci#define rdev_info(rdev, fmt, ...) \ 438c2ecf20Sopenharmony_ci pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 448c2ecf20Sopenharmony_ci#define rdev_dbg(rdev, fmt, ...) \ 458c2ecf20Sopenharmony_ci pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic DEFINE_WW_CLASS(regulator_ww_class); 488c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(regulator_nesting_mutex); 498c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(regulator_list_mutex); 508c2ecf20Sopenharmony_cistatic LIST_HEAD(regulator_map_list); 518c2ecf20Sopenharmony_cistatic LIST_HEAD(regulator_ena_gpio_list); 528c2ecf20Sopenharmony_cistatic LIST_HEAD(regulator_supply_alias_list); 538c2ecf20Sopenharmony_cistatic LIST_HEAD(regulator_coupler_list); 548c2ecf20Sopenharmony_cistatic bool has_full_constraints; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic struct dentry *debugfs_root; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * struct regulator_map 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * Used to provide symbolic supply names to devices. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistruct regulator_map { 648c2ecf20Sopenharmony_ci struct list_head list; 658c2ecf20Sopenharmony_ci const char *dev_name; /* The dev_name() for the consumer */ 668c2ecf20Sopenharmony_ci const char *supply; 678c2ecf20Sopenharmony_ci struct regulator_dev *regulator; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* 718c2ecf20Sopenharmony_ci * struct regulator_enable_gpio 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * Management for shared enable GPIO pin 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistruct regulator_enable_gpio { 768c2ecf20Sopenharmony_ci struct list_head list; 778c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 788c2ecf20Sopenharmony_ci u32 enable_count; /* a number of enabled shared GPIO */ 798c2ecf20Sopenharmony_ci u32 request_count; /* a number of requested shared GPIO */ 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 838c2ecf20Sopenharmony_ci * struct regulator_supply_alias 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * Used to map lookups for a supply onto an alternative device. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistruct regulator_supply_alias { 888c2ecf20Sopenharmony_ci struct list_head list; 898c2ecf20Sopenharmony_ci struct device *src_dev; 908c2ecf20Sopenharmony_ci const char *src_supply; 918c2ecf20Sopenharmony_ci struct device *alias_dev; 928c2ecf20Sopenharmony_ci const char *alias_supply; 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic int _regulator_is_enabled(struct regulator_dev *rdev); 968c2ecf20Sopenharmony_cistatic int _regulator_disable(struct regulator *regulator); 978c2ecf20Sopenharmony_cistatic int _regulator_get_current_limit(struct regulator_dev *rdev); 988c2ecf20Sopenharmony_cistatic unsigned int _regulator_get_mode(struct regulator_dev *rdev); 998c2ecf20Sopenharmony_cistatic int _notifier_call_chain(struct regulator_dev *rdev, 1008c2ecf20Sopenharmony_ci unsigned long event, void *data); 1018c2ecf20Sopenharmony_cistatic int _regulator_do_set_voltage(struct regulator_dev *rdev, 1028c2ecf20Sopenharmony_ci int min_uV, int max_uV); 1038c2ecf20Sopenharmony_cistatic int regulator_balance_voltage(struct regulator_dev *rdev, 1048c2ecf20Sopenharmony_ci suspend_state_t state); 1058c2ecf20Sopenharmony_cistatic struct regulator *create_regulator(struct regulator_dev *rdev, 1068c2ecf20Sopenharmony_ci struct device *dev, 1078c2ecf20Sopenharmony_ci const char *supply_name); 1088c2ecf20Sopenharmony_cistatic void destroy_regulator(struct regulator *regulator); 1098c2ecf20Sopenharmony_cistatic void _regulator_put(struct regulator *regulator); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ciconst char *rdev_get_name(struct regulator_dev *rdev) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci if (rdev->constraints && rdev->constraints->name) 1148c2ecf20Sopenharmony_ci return rdev->constraints->name; 1158c2ecf20Sopenharmony_ci else if (rdev->desc->name) 1168c2ecf20Sopenharmony_ci return rdev->desc->name; 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci return ""; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic bool have_full_constraints(void) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return has_full_constraints || of_have_populated_dt(); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic bool regulator_ops_is_valid(struct regulator_dev *rdev, int ops) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci if (!rdev->constraints) { 1298c2ecf20Sopenharmony_ci rdev_err(rdev, "no constraints\n"); 1308c2ecf20Sopenharmony_ci return false; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (rdev->constraints->valid_ops_mask & ops) 1348c2ecf20Sopenharmony_ci return true; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return false; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/** 1408c2ecf20Sopenharmony_ci * regulator_lock_nested - lock a single regulator 1418c2ecf20Sopenharmony_ci * @rdev: regulator source 1428c2ecf20Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 1438c2ecf20Sopenharmony_ci * 1448c2ecf20Sopenharmony_ci * This function can be called many times by one task on 1458c2ecf20Sopenharmony_ci * a single regulator and its mutex will be locked only 1468c2ecf20Sopenharmony_ci * once. If a task, which is calling this function is other 1478c2ecf20Sopenharmony_ci * than the one, which initially locked the mutex, it will 1488c2ecf20Sopenharmony_ci * wait on mutex. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_cistatic inline int regulator_lock_nested(struct regulator_dev *rdev, 1518c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci bool lock = false; 1548c2ecf20Sopenharmony_ci int ret = 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (ww_ctx || !ww_mutex_trylock(&rdev->mutex)) { 1598c2ecf20Sopenharmony_ci if (rdev->mutex_owner == current) 1608c2ecf20Sopenharmony_ci rdev->ref_cnt++; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci lock = true; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (lock) { 1658c2ecf20Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 1668c2ecf20Sopenharmony_ci ret = ww_mutex_lock(&rdev->mutex, ww_ctx); 1678c2ecf20Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci lock = true; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (lock && ret != -EDEADLK) { 1748c2ecf20Sopenharmony_ci rdev->ref_cnt++; 1758c2ecf20Sopenharmony_ci rdev->mutex_owner = current; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return ret; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * regulator_lock - lock a single regulator 1858c2ecf20Sopenharmony_ci * @rdev: regulator source 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * This function can be called many times by one task on 1888c2ecf20Sopenharmony_ci * a single regulator and its mutex will be locked only 1898c2ecf20Sopenharmony_ci * once. If a task, which is calling this function is other 1908c2ecf20Sopenharmony_ci * than the one, which initially locked the mutex, it will 1918c2ecf20Sopenharmony_ci * wait on mutex. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_cistatic void regulator_lock(struct regulator_dev *rdev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci regulator_lock_nested(rdev, NULL); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/** 1998c2ecf20Sopenharmony_ci * regulator_unlock - unlock a single regulator 2008c2ecf20Sopenharmony_ci * @rdev: regulator_source 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * This function unlocks the mutex when the 2038c2ecf20Sopenharmony_ci * reference counter reaches 0. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic void regulator_unlock(struct regulator_dev *rdev) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci mutex_lock(®ulator_nesting_mutex); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (--rdev->ref_cnt == 0) { 2108c2ecf20Sopenharmony_ci rdev->mutex_owner = NULL; 2118c2ecf20Sopenharmony_ci ww_mutex_unlock(&rdev->mutex); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci WARN_ON_ONCE(rdev->ref_cnt < 0); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci mutex_unlock(®ulator_nesting_mutex); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci/** 2208c2ecf20Sopenharmony_ci * regulator_lock_two - lock two regulators 2218c2ecf20Sopenharmony_ci * @rdev1: first regulator 2228c2ecf20Sopenharmony_ci * @rdev2: second regulator 2238c2ecf20Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * Locks both rdevs using the regulator_ww_class. 2268c2ecf20Sopenharmony_ci */ 2278c2ecf20Sopenharmony_cistatic void regulator_lock_two(struct regulator_dev *rdev1, 2288c2ecf20Sopenharmony_ci struct regulator_dev *rdev2, 2298c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct regulator_dev *tmp; 2328c2ecf20Sopenharmony_ci int ret; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Try to just grab both of them */ 2378c2ecf20Sopenharmony_ci ret = regulator_lock_nested(rdev1, ww_ctx); 2388c2ecf20Sopenharmony_ci WARN_ON(ret); 2398c2ecf20Sopenharmony_ci ret = regulator_lock_nested(rdev2, ww_ctx); 2408c2ecf20Sopenharmony_ci if (ret != -EDEADLOCK) { 2418c2ecf20Sopenharmony_ci WARN_ON(ret); 2428c2ecf20Sopenharmony_ci goto exit; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci while (true) { 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * Start of loop: rdev1 was locked and rdev2 was contended. 2488c2ecf20Sopenharmony_ci * Need to unlock rdev1, slowly lock rdev2, then try rdev1 2498c2ecf20Sopenharmony_ci * again. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci regulator_unlock(rdev1); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ww_mutex_lock_slow(&rdev2->mutex, ww_ctx); 2548c2ecf20Sopenharmony_ci rdev2->ref_cnt++; 2558c2ecf20Sopenharmony_ci rdev2->mutex_owner = current; 2568c2ecf20Sopenharmony_ci ret = regulator_lock_nested(rdev1, ww_ctx); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (ret == -EDEADLOCK) { 2598c2ecf20Sopenharmony_ci /* More contention; swap which needs to be slow */ 2608c2ecf20Sopenharmony_ci tmp = rdev1; 2618c2ecf20Sopenharmony_ci rdev1 = rdev2; 2628c2ecf20Sopenharmony_ci rdev2 = tmp; 2638c2ecf20Sopenharmony_ci } else { 2648c2ecf20Sopenharmony_ci WARN_ON(ret); 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci } 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ciexit: 2708c2ecf20Sopenharmony_ci ww_acquire_done(ww_ctx); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/** 2748c2ecf20Sopenharmony_ci * regulator_unlock_two - unlock two regulators 2758c2ecf20Sopenharmony_ci * @rdev1: first regulator 2768c2ecf20Sopenharmony_ci * @rdev2: second regulator 2778c2ecf20Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * The inverse of regulator_lock_two(). 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic void regulator_unlock_two(struct regulator_dev *rdev1, 2838c2ecf20Sopenharmony_ci struct regulator_dev *rdev2, 2848c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci regulator_unlock(rdev2); 2878c2ecf20Sopenharmony_ci regulator_unlock(rdev1); 2888c2ecf20Sopenharmony_ci ww_acquire_fini(ww_ctx); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic bool regulator_supply_is_couple(struct regulator_dev *rdev) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct regulator_dev *c_rdev; 2948c2ecf20Sopenharmony_ci int i; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci for (i = 1; i < rdev->coupling_desc.n_coupled; i++) { 2978c2ecf20Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (rdev->supply->rdev == c_rdev) 3008c2ecf20Sopenharmony_ci return true; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return false; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void regulator_unlock_recursive(struct regulator_dev *rdev, 3078c2ecf20Sopenharmony_ci unsigned int n_coupled) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct regulator_dev *c_rdev, *supply_rdev; 3108c2ecf20Sopenharmony_ci int i, supply_n_coupled; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci for (i = n_coupled; i > 0; i--) { 3138c2ecf20Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i - 1]; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (!c_rdev) 3168c2ecf20Sopenharmony_ci continue; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 3198c2ecf20Sopenharmony_ci supply_rdev = c_rdev->supply->rdev; 3208c2ecf20Sopenharmony_ci supply_n_coupled = supply_rdev->coupling_desc.n_coupled; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci regulator_unlock_recursive(supply_rdev, 3238c2ecf20Sopenharmony_ci supply_n_coupled); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci regulator_unlock(c_rdev); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int regulator_lock_recursive(struct regulator_dev *rdev, 3318c2ecf20Sopenharmony_ci struct regulator_dev **new_contended_rdev, 3328c2ecf20Sopenharmony_ci struct regulator_dev **old_contended_rdev, 3338c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci struct regulator_dev *c_rdev; 3368c2ecf20Sopenharmony_ci int i, err; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci for (i = 0; i < rdev->coupling_desc.n_coupled; i++) { 3398c2ecf20Sopenharmony_ci c_rdev = rdev->coupling_desc.coupled_rdevs[i]; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!c_rdev) 3428c2ecf20Sopenharmony_ci continue; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (c_rdev != *old_contended_rdev) { 3458c2ecf20Sopenharmony_ci err = regulator_lock_nested(c_rdev, ww_ctx); 3468c2ecf20Sopenharmony_ci if (err) { 3478c2ecf20Sopenharmony_ci if (err == -EDEADLK) { 3488c2ecf20Sopenharmony_ci *new_contended_rdev = c_rdev; 3498c2ecf20Sopenharmony_ci goto err_unlock; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* shouldn't happen */ 3538c2ecf20Sopenharmony_ci WARN_ON_ONCE(err != -EALREADY); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci } else { 3568c2ecf20Sopenharmony_ci *old_contended_rdev = NULL; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (c_rdev->supply && !regulator_supply_is_couple(c_rdev)) { 3608c2ecf20Sopenharmony_ci err = regulator_lock_recursive(c_rdev->supply->rdev, 3618c2ecf20Sopenharmony_ci new_contended_rdev, 3628c2ecf20Sopenharmony_ci old_contended_rdev, 3638c2ecf20Sopenharmony_ci ww_ctx); 3648c2ecf20Sopenharmony_ci if (err) { 3658c2ecf20Sopenharmony_ci regulator_unlock(c_rdev); 3668c2ecf20Sopenharmony_ci goto err_unlock; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return 0; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cierr_unlock: 3748c2ecf20Sopenharmony_ci regulator_unlock_recursive(rdev, i); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/** 3808c2ecf20Sopenharmony_ci * regulator_unlock_dependent - unlock regulator's suppliers and coupled 3818c2ecf20Sopenharmony_ci * regulators 3828c2ecf20Sopenharmony_ci * @rdev: regulator source 3838c2ecf20Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * Unlock all regulators related with rdev by coupling or supplying. 3868c2ecf20Sopenharmony_ci */ 3878c2ecf20Sopenharmony_cistatic void regulator_unlock_dependent(struct regulator_dev *rdev, 3888c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci regulator_unlock_recursive(rdev, rdev->coupling_desc.n_coupled); 3918c2ecf20Sopenharmony_ci ww_acquire_fini(ww_ctx); 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/** 3958c2ecf20Sopenharmony_ci * regulator_lock_dependent - lock regulator's suppliers and coupled regulators 3968c2ecf20Sopenharmony_ci * @rdev: regulator source 3978c2ecf20Sopenharmony_ci * @ww_ctx: w/w mutex acquire context 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * This function as a wrapper on regulator_lock_recursive(), which locks 4008c2ecf20Sopenharmony_ci * all regulators related with rdev by coupling or supplying. 4018c2ecf20Sopenharmony_ci */ 4028c2ecf20Sopenharmony_cistatic void regulator_lock_dependent(struct regulator_dev *rdev, 4038c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct regulator_dev *new_contended_rdev = NULL; 4068c2ecf20Sopenharmony_ci struct regulator_dev *old_contended_rdev = NULL; 4078c2ecf20Sopenharmony_ci int err; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci do { 4148c2ecf20Sopenharmony_ci if (new_contended_rdev) { 4158c2ecf20Sopenharmony_ci ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 4168c2ecf20Sopenharmony_ci old_contended_rdev = new_contended_rdev; 4178c2ecf20Sopenharmony_ci old_contended_rdev->ref_cnt++; 4188c2ecf20Sopenharmony_ci old_contended_rdev->mutex_owner = current; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci err = regulator_lock_recursive(rdev, 4228c2ecf20Sopenharmony_ci &new_contended_rdev, 4238c2ecf20Sopenharmony_ci &old_contended_rdev, 4248c2ecf20Sopenharmony_ci ww_ctx); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (old_contended_rdev) 4278c2ecf20Sopenharmony_ci regulator_unlock(old_contended_rdev); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci } while (err == -EDEADLK); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ww_acquire_done(ww_ctx); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/** 4378c2ecf20Sopenharmony_ci * of_get_child_regulator - get a child regulator device node 4388c2ecf20Sopenharmony_ci * based on supply name 4398c2ecf20Sopenharmony_ci * @parent: Parent device node 4408c2ecf20Sopenharmony_ci * @prop_name: Combination regulator supply name and "-supply" 4418c2ecf20Sopenharmony_ci * 4428c2ecf20Sopenharmony_ci * Traverse all child nodes. 4438c2ecf20Sopenharmony_ci * Extract the child regulator device node corresponding to the supply name. 4448c2ecf20Sopenharmony_ci * returns the device node corresponding to the regulator if found, else 4458c2ecf20Sopenharmony_ci * returns NULL. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_cistatic struct device_node *of_get_child_regulator(struct device_node *parent, 4488c2ecf20Sopenharmony_ci const char *prop_name) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct device_node *regnode = NULL; 4518c2ecf20Sopenharmony_ci struct device_node *child = NULL; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci for_each_child_of_node(parent, child) { 4548c2ecf20Sopenharmony_ci regnode = of_parse_phandle(child, prop_name, 0); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (!regnode) { 4578c2ecf20Sopenharmony_ci regnode = of_get_child_regulator(child, prop_name); 4588c2ecf20Sopenharmony_ci if (regnode) 4598c2ecf20Sopenharmony_ci goto err_node_put; 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci goto err_node_put; 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci return NULL; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_cierr_node_put: 4678c2ecf20Sopenharmony_ci of_node_put(child); 4688c2ecf20Sopenharmony_ci return regnode; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/** 4728c2ecf20Sopenharmony_ci * of_get_regulator - get a regulator device node based on supply name 4738c2ecf20Sopenharmony_ci * @dev: Device pointer for the consumer (of regulator) device 4748c2ecf20Sopenharmony_ci * @supply: regulator supply name 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * Extract the regulator device node corresponding to the supply name. 4778c2ecf20Sopenharmony_ci * returns the device node corresponding to the regulator if found, else 4788c2ecf20Sopenharmony_ci * returns NULL. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_cistatic struct device_node *of_get_regulator(struct device *dev, const char *supply) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct device_node *regnode = NULL; 4838c2ecf20Sopenharmony_ci char prop_name[64]; /* 64 is max size of property name */ 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci dev_dbg(dev, "Looking up %s-supply from device tree\n", supply); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci snprintf(prop_name, 64, "%s-supply", supply); 4888c2ecf20Sopenharmony_ci regnode = of_parse_phandle(dev->of_node, prop_name, 0); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!regnode) { 4918c2ecf20Sopenharmony_ci regnode = of_get_child_regulator(dev->of_node, prop_name); 4928c2ecf20Sopenharmony_ci if (regnode) 4938c2ecf20Sopenharmony_ci return regnode; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci dev_dbg(dev, "Looking up %s property in node %pOF failed\n", 4968c2ecf20Sopenharmony_ci prop_name, dev->of_node); 4978c2ecf20Sopenharmony_ci return NULL; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci return regnode; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/* Platform voltage constraint check */ 5038c2ecf20Sopenharmony_ciint regulator_check_voltage(struct regulator_dev *rdev, 5048c2ecf20Sopenharmony_ci int *min_uV, int *max_uV) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci BUG_ON(*min_uV > *max_uV); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 5098c2ecf20Sopenharmony_ci rdev_err(rdev, "voltage operation not allowed\n"); 5108c2ecf20Sopenharmony_ci return -EPERM; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (*max_uV > rdev->constraints->max_uV) 5148c2ecf20Sopenharmony_ci *max_uV = rdev->constraints->max_uV; 5158c2ecf20Sopenharmony_ci if (*min_uV < rdev->constraints->min_uV) 5168c2ecf20Sopenharmony_ci *min_uV = rdev->constraints->min_uV; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (*min_uV > *max_uV) { 5198c2ecf20Sopenharmony_ci rdev_err(rdev, "unsupportable voltage range: %d-%duV\n", 5208c2ecf20Sopenharmony_ci *min_uV, *max_uV); 5218c2ecf20Sopenharmony_ci return -EINVAL; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* return 0 if the state is valid */ 5288c2ecf20Sopenharmony_cistatic int regulator_check_states(suspend_state_t state) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci return (state > PM_SUSPEND_MAX || state == PM_SUSPEND_TO_IDLE); 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* Make sure we select a voltage that suits the needs of all 5348c2ecf20Sopenharmony_ci * regulator consumers 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ciint regulator_check_consumers(struct regulator_dev *rdev, 5378c2ecf20Sopenharmony_ci int *min_uV, int *max_uV, 5388c2ecf20Sopenharmony_ci suspend_state_t state) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct regulator *regulator; 5418c2ecf20Sopenharmony_ci struct regulator_voltage *voltage; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 5448c2ecf20Sopenharmony_ci voltage = ®ulator->voltage[state]; 5458c2ecf20Sopenharmony_ci /* 5468c2ecf20Sopenharmony_ci * Assume consumers that didn't say anything are OK 5478c2ecf20Sopenharmony_ci * with anything in the constraint range. 5488c2ecf20Sopenharmony_ci */ 5498c2ecf20Sopenharmony_ci if (!voltage->min_uV && !voltage->max_uV) 5508c2ecf20Sopenharmony_ci continue; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (*max_uV > voltage->max_uV) 5538c2ecf20Sopenharmony_ci *max_uV = voltage->max_uV; 5548c2ecf20Sopenharmony_ci if (*min_uV < voltage->min_uV) 5558c2ecf20Sopenharmony_ci *min_uV = voltage->min_uV; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci if (*min_uV > *max_uV) { 5598c2ecf20Sopenharmony_ci rdev_err(rdev, "Restricting voltage, %u-%uuV\n", 5608c2ecf20Sopenharmony_ci *min_uV, *max_uV); 5618c2ecf20Sopenharmony_ci return -EINVAL; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci/* current constraint check */ 5688c2ecf20Sopenharmony_cistatic int regulator_check_current_limit(struct regulator_dev *rdev, 5698c2ecf20Sopenharmony_ci int *min_uA, int *max_uA) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci BUG_ON(*min_uA > *max_uA); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_CURRENT)) { 5748c2ecf20Sopenharmony_ci rdev_err(rdev, "current operation not allowed\n"); 5758c2ecf20Sopenharmony_ci return -EPERM; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (*max_uA > rdev->constraints->max_uA) 5798c2ecf20Sopenharmony_ci *max_uA = rdev->constraints->max_uA; 5808c2ecf20Sopenharmony_ci if (*min_uA < rdev->constraints->min_uA) 5818c2ecf20Sopenharmony_ci *min_uA = rdev->constraints->min_uA; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (*min_uA > *max_uA) { 5848c2ecf20Sopenharmony_ci rdev_err(rdev, "unsupportable current range: %d-%duA\n", 5858c2ecf20Sopenharmony_ci *min_uA, *max_uA); 5868c2ecf20Sopenharmony_ci return -EINVAL; 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci/* operating mode constraint check */ 5938c2ecf20Sopenharmony_cistatic int regulator_mode_constrain(struct regulator_dev *rdev, 5948c2ecf20Sopenharmony_ci unsigned int *mode) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci switch (*mode) { 5978c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 5988c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 5998c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: 6008c2ecf20Sopenharmony_ci case REGULATOR_MODE_STANDBY: 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci default: 6038c2ecf20Sopenharmony_ci rdev_err(rdev, "invalid mode %x specified\n", *mode); 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_MODE)) { 6088c2ecf20Sopenharmony_ci rdev_err(rdev, "mode operation not allowed\n"); 6098c2ecf20Sopenharmony_ci return -EPERM; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* The modes are bitmasks, the most power hungry modes having 6138c2ecf20Sopenharmony_ci * the lowest values. If the requested mode isn't supported 6148c2ecf20Sopenharmony_ci * try higher modes. */ 6158c2ecf20Sopenharmony_ci while (*mode) { 6168c2ecf20Sopenharmony_ci if (rdev->constraints->valid_modes_mask & *mode) 6178c2ecf20Sopenharmony_ci return 0; 6188c2ecf20Sopenharmony_ci *mode /= 2; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci return -EINVAL; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic inline struct regulator_state * 6258c2ecf20Sopenharmony_ciregulator_get_suspend_state(struct regulator_dev *rdev, suspend_state_t state) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci if (rdev->constraints == NULL) 6288c2ecf20Sopenharmony_ci return NULL; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci switch (state) { 6318c2ecf20Sopenharmony_ci case PM_SUSPEND_STANDBY: 6328c2ecf20Sopenharmony_ci return &rdev->constraints->state_standby; 6338c2ecf20Sopenharmony_ci case PM_SUSPEND_MEM: 6348c2ecf20Sopenharmony_ci return &rdev->constraints->state_mem; 6358c2ecf20Sopenharmony_ci case PM_SUSPEND_MAX: 6368c2ecf20Sopenharmony_ci return &rdev->constraints->state_disk; 6378c2ecf20Sopenharmony_ci default: 6388c2ecf20Sopenharmony_ci return NULL; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic const struct regulator_state * 6438c2ecf20Sopenharmony_ciregulator_get_suspend_state_check(struct regulator_dev *rdev, suspend_state_t state) 6448c2ecf20Sopenharmony_ci{ 6458c2ecf20Sopenharmony_ci const struct regulator_state *rstate; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 6488c2ecf20Sopenharmony_ci if (rstate == NULL) 6498c2ecf20Sopenharmony_ci return NULL; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* If we have no suspend mode configuration don't set anything; 6528c2ecf20Sopenharmony_ci * only warn if the driver implements set_suspend_voltage or 6538c2ecf20Sopenharmony_ci * set_suspend_mode callback. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci if (rstate->enabled != ENABLE_IN_SUSPEND && 6568c2ecf20Sopenharmony_ci rstate->enabled != DISABLE_IN_SUSPEND) { 6578c2ecf20Sopenharmony_ci if (rdev->desc->ops->set_suspend_voltage || 6588c2ecf20Sopenharmony_ci rdev->desc->ops->set_suspend_mode) 6598c2ecf20Sopenharmony_ci rdev_warn(rdev, "No configuration\n"); 6608c2ecf20Sopenharmony_ci return NULL; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci return rstate; 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic ssize_t regulator_uV_show(struct device *dev, 6678c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 6708c2ecf20Sopenharmony_ci int uV; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci regulator_lock(rdev); 6738c2ecf20Sopenharmony_ci uV = regulator_get_voltage_rdev(rdev); 6748c2ecf20Sopenharmony_ci regulator_unlock(rdev); 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (uV < 0) 6778c2ecf20Sopenharmony_ci return uV; 6788c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", uV); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_cistatic ssize_t regulator_uA_show(struct device *dev, 6838c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_cistatic DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, 6928c2ecf20Sopenharmony_ci char *buf) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", rdev_get_name(rdev)); 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_cistatic const char *regulator_opmode_to_str(int mode) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci switch (mode) { 7038c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 7048c2ecf20Sopenharmony_ci return "fast"; 7058c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 7068c2ecf20Sopenharmony_ci return "normal"; 7078c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: 7088c2ecf20Sopenharmony_ci return "idle"; 7098c2ecf20Sopenharmony_ci case REGULATOR_MODE_STANDBY: 7108c2ecf20Sopenharmony_ci return "standby"; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci return "unknown"; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic ssize_t regulator_print_opmode(char *buf, int mode) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", regulator_opmode_to_str(mode)); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic ssize_t regulator_opmode_show(struct device *dev, 7218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 7228c2ecf20Sopenharmony_ci{ 7238c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return regulator_print_opmode(buf, _regulator_get_mode(rdev)); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_cistatic DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic ssize_t regulator_print_state(char *buf, int state) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci if (state > 0) 7328c2ecf20Sopenharmony_ci return sprintf(buf, "enabled\n"); 7338c2ecf20Sopenharmony_ci else if (state == 0) 7348c2ecf20Sopenharmony_ci return sprintf(buf, "disabled\n"); 7358c2ecf20Sopenharmony_ci else 7368c2ecf20Sopenharmony_ci return sprintf(buf, "unknown\n"); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic ssize_t regulator_state_show(struct device *dev, 7408c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 7438c2ecf20Sopenharmony_ci ssize_t ret; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci regulator_lock(rdev); 7468c2ecf20Sopenharmony_ci ret = regulator_print_state(buf, _regulator_is_enabled(rdev)); 7478c2ecf20Sopenharmony_ci regulator_unlock(rdev); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return ret; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(state, 0444, regulator_state_show, NULL); 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_cistatic ssize_t regulator_status_show(struct device *dev, 7548c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 7578c2ecf20Sopenharmony_ci int status; 7588c2ecf20Sopenharmony_ci char *label; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci status = rdev->desc->ops->get_status(rdev); 7618c2ecf20Sopenharmony_ci if (status < 0) 7628c2ecf20Sopenharmony_ci return status; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci switch (status) { 7658c2ecf20Sopenharmony_ci case REGULATOR_STATUS_OFF: 7668c2ecf20Sopenharmony_ci label = "off"; 7678c2ecf20Sopenharmony_ci break; 7688c2ecf20Sopenharmony_ci case REGULATOR_STATUS_ON: 7698c2ecf20Sopenharmony_ci label = "on"; 7708c2ecf20Sopenharmony_ci break; 7718c2ecf20Sopenharmony_ci case REGULATOR_STATUS_ERROR: 7728c2ecf20Sopenharmony_ci label = "error"; 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci case REGULATOR_STATUS_FAST: 7758c2ecf20Sopenharmony_ci label = "fast"; 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci case REGULATOR_STATUS_NORMAL: 7788c2ecf20Sopenharmony_ci label = "normal"; 7798c2ecf20Sopenharmony_ci break; 7808c2ecf20Sopenharmony_ci case REGULATOR_STATUS_IDLE: 7818c2ecf20Sopenharmony_ci label = "idle"; 7828c2ecf20Sopenharmony_ci break; 7838c2ecf20Sopenharmony_ci case REGULATOR_STATUS_STANDBY: 7848c2ecf20Sopenharmony_ci label = "standby"; 7858c2ecf20Sopenharmony_ci break; 7868c2ecf20Sopenharmony_ci case REGULATOR_STATUS_BYPASS: 7878c2ecf20Sopenharmony_ci label = "bypass"; 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci case REGULATOR_STATUS_UNDEFINED: 7908c2ecf20Sopenharmony_ci label = "undefined"; 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci default: 7938c2ecf20Sopenharmony_ci return -ERANGE; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", label); 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(status, 0444, regulator_status_show, NULL); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic ssize_t regulator_min_uA_show(struct device *dev, 8018c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci if (!rdev->constraints) 8068c2ecf20Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->min_uA); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_cistatic DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic ssize_t regulator_max_uA_show(struct device *dev, 8138c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci if (!rdev->constraints) 8188c2ecf20Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->max_uA); 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic ssize_t regulator_min_uV_show(struct device *dev, 8258c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8268c2ecf20Sopenharmony_ci{ 8278c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (!rdev->constraints) 8308c2ecf20Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->min_uV); 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_cistatic DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic ssize_t regulator_max_uV_show(struct device *dev, 8378c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci if (!rdev->constraints) 8428c2ecf20Sopenharmony_ci return sprintf(buf, "constraint not defined\n"); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->max_uV); 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_cistatic DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL); 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistatic ssize_t regulator_total_uA_show(struct device *dev, 8498c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8528c2ecf20Sopenharmony_ci struct regulator *regulator; 8538c2ecf20Sopenharmony_ci int uA = 0; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci regulator_lock(rdev); 8568c2ecf20Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 8578c2ecf20Sopenharmony_ci if (regulator->enable_count) 8588c2ecf20Sopenharmony_ci uA += regulator->uA_load; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci regulator_unlock(rdev); 8618c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", uA); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_cistatic DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic ssize_t num_users_show(struct device *dev, struct device_attribute *attr, 8668c2ecf20Sopenharmony_ci char *buf) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8698c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->use_count); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(num_users); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_cistatic ssize_t type_show(struct device *dev, struct device_attribute *attr, 8748c2ecf20Sopenharmony_ci char *buf) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci switch (rdev->desc->type) { 8798c2ecf20Sopenharmony_ci case REGULATOR_VOLTAGE: 8808c2ecf20Sopenharmony_ci return sprintf(buf, "voltage\n"); 8818c2ecf20Sopenharmony_ci case REGULATOR_CURRENT: 8828c2ecf20Sopenharmony_ci return sprintf(buf, "current\n"); 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci return sprintf(buf, "unknown\n"); 8858c2ecf20Sopenharmony_ci} 8868c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(type); 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_mem_uV_show(struct device *dev, 8898c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_mem_microvolts, 0444, 8968c2ecf20Sopenharmony_ci regulator_suspend_mem_uV_show, NULL); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_disk_uV_show(struct device *dev, 8998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_disk_microvolts, 0444, 9068c2ecf20Sopenharmony_ci regulator_suspend_disk_uV_show, NULL); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_standby_uV_show(struct device *dev, 9098c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_standby_microvolts, 0444, 9168c2ecf20Sopenharmony_ci regulator_suspend_standby_uV_show, NULL); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_mem_mode_show(struct device *dev, 9198c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return regulator_print_opmode(buf, 9248c2ecf20Sopenharmony_ci rdev->constraints->state_mem.mode); 9258c2ecf20Sopenharmony_ci} 9268c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_mem_mode, 0444, 9278c2ecf20Sopenharmony_ci regulator_suspend_mem_mode_show, NULL); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_disk_mode_show(struct device *dev, 9308c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9318c2ecf20Sopenharmony_ci{ 9328c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return regulator_print_opmode(buf, 9358c2ecf20Sopenharmony_ci rdev->constraints->state_disk.mode); 9368c2ecf20Sopenharmony_ci} 9378c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_disk_mode, 0444, 9388c2ecf20Sopenharmony_ci regulator_suspend_disk_mode_show, NULL); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_standby_mode_show(struct device *dev, 9418c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return regulator_print_opmode(buf, 9468c2ecf20Sopenharmony_ci rdev->constraints->state_standby.mode); 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_standby_mode, 0444, 9498c2ecf20Sopenharmony_ci regulator_suspend_standby_mode_show, NULL); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_mem_state_show(struct device *dev, 9528c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return regulator_print_state(buf, 9578c2ecf20Sopenharmony_ci rdev->constraints->state_mem.enabled); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_mem_state, 0444, 9608c2ecf20Sopenharmony_ci regulator_suspend_mem_state_show, NULL); 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_disk_state_show(struct device *dev, 9638c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci return regulator_print_state(buf, 9688c2ecf20Sopenharmony_ci rdev->constraints->state_disk.enabled); 9698c2ecf20Sopenharmony_ci} 9708c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_disk_state, 0444, 9718c2ecf20Sopenharmony_ci regulator_suspend_disk_state_show, NULL); 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic ssize_t regulator_suspend_standby_state_show(struct device *dev, 9748c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return regulator_print_state(buf, 9798c2ecf20Sopenharmony_ci rdev->constraints->state_standby.enabled); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_cistatic DEVICE_ATTR(suspend_standby_state, 0444, 9828c2ecf20Sopenharmony_ci regulator_suspend_standby_state_show, NULL); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic ssize_t regulator_bypass_show(struct device *dev, 9858c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 9888c2ecf20Sopenharmony_ci const char *report; 9898c2ecf20Sopenharmony_ci bool bypass; 9908c2ecf20Sopenharmony_ci int ret; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci ret = rdev->desc->ops->get_bypass(rdev, &bypass); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (ret != 0) 9958c2ecf20Sopenharmony_ci report = "unknown"; 9968c2ecf20Sopenharmony_ci else if (bypass) 9978c2ecf20Sopenharmony_ci report = "enabled"; 9988c2ecf20Sopenharmony_ci else 9998c2ecf20Sopenharmony_ci report = "disabled"; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", report); 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_cistatic DEVICE_ATTR(bypass, 0444, 10048c2ecf20Sopenharmony_ci regulator_bypass_show, NULL); 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci/* Calculate the new optimum regulator operating mode based on the new total 10078c2ecf20Sopenharmony_ci * consumer load. All locks held by caller */ 10088c2ecf20Sopenharmony_cistatic int drms_uA_update(struct regulator_dev *rdev) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci struct regulator *sibling; 10118c2ecf20Sopenharmony_ci int current_uA = 0, output_uV, input_uV, err; 10128c2ecf20Sopenharmony_ci unsigned int mode; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci /* 10158c2ecf20Sopenharmony_ci * first check to see if we can set modes at all, otherwise just 10168c2ecf20Sopenharmony_ci * tell the consumer everything is OK. 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_DRMS)) { 10198c2ecf20Sopenharmony_ci rdev_dbg(rdev, "DRMS operation not allowed\n"); 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (!rdev->desc->ops->get_optimum_mode && 10248c2ecf20Sopenharmony_ci !rdev->desc->ops->set_load) 10258c2ecf20Sopenharmony_ci return 0; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_mode && 10288c2ecf20Sopenharmony_ci !rdev->desc->ops->set_load) 10298c2ecf20Sopenharmony_ci return -EINVAL; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* calc total requested load */ 10328c2ecf20Sopenharmony_ci list_for_each_entry(sibling, &rdev->consumer_list, list) { 10338c2ecf20Sopenharmony_ci if (sibling->enable_count) 10348c2ecf20Sopenharmony_ci current_uA += sibling->uA_load; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci current_uA += rdev->constraints->system_load; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (rdev->desc->ops->set_load) { 10408c2ecf20Sopenharmony_ci /* set the optimum mode for our new total regulator load */ 10418c2ecf20Sopenharmony_ci err = rdev->desc->ops->set_load(rdev, current_uA); 10428c2ecf20Sopenharmony_ci if (err < 0) 10438c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set load %d: %pe\n", 10448c2ecf20Sopenharmony_ci current_uA, ERR_PTR(err)); 10458c2ecf20Sopenharmony_ci } else { 10468c2ecf20Sopenharmony_ci /* get output voltage */ 10478c2ecf20Sopenharmony_ci output_uV = regulator_get_voltage_rdev(rdev); 10488c2ecf20Sopenharmony_ci if (output_uV <= 0) { 10498c2ecf20Sopenharmony_ci rdev_err(rdev, "invalid output voltage found\n"); 10508c2ecf20Sopenharmony_ci return -EINVAL; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* get input voltage */ 10548c2ecf20Sopenharmony_ci input_uV = 0; 10558c2ecf20Sopenharmony_ci if (rdev->supply) 10568c2ecf20Sopenharmony_ci input_uV = regulator_get_voltage_rdev(rdev->supply->rdev); 10578c2ecf20Sopenharmony_ci if (input_uV <= 0) 10588c2ecf20Sopenharmony_ci input_uV = rdev->constraints->input_uV; 10598c2ecf20Sopenharmony_ci if (input_uV <= 0) { 10608c2ecf20Sopenharmony_ci rdev_err(rdev, "invalid input voltage found\n"); 10618c2ecf20Sopenharmony_ci return -EINVAL; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* now get the optimum mode for our new total regulator load */ 10658c2ecf20Sopenharmony_ci mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, 10668c2ecf20Sopenharmony_ci output_uV, current_uA); 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci /* check the new mode is allowed */ 10698c2ecf20Sopenharmony_ci err = regulator_mode_constrain(rdev, &mode); 10708c2ecf20Sopenharmony_ci if (err < 0) { 10718c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV: %pe\n", 10728c2ecf20Sopenharmony_ci current_uA, input_uV, output_uV, ERR_PTR(err)); 10738c2ecf20Sopenharmony_ci return err; 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci err = rdev->desc->ops->set_mode(rdev, mode); 10778c2ecf20Sopenharmony_ci if (err < 0) 10788c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set optimum mode %x: %pe\n", 10798c2ecf20Sopenharmony_ci mode, ERR_PTR(err)); 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return err; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int __suspend_set_state(struct regulator_dev *rdev, 10868c2ecf20Sopenharmony_ci const struct regulator_state *rstate) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci int ret = 0; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (rstate->enabled == ENABLE_IN_SUSPEND && 10918c2ecf20Sopenharmony_ci rdev->desc->ops->set_suspend_enable) 10928c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_suspend_enable(rdev); 10938c2ecf20Sopenharmony_ci else if (rstate->enabled == DISABLE_IN_SUSPEND && 10948c2ecf20Sopenharmony_ci rdev->desc->ops->set_suspend_disable) 10958c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_suspend_disable(rdev); 10968c2ecf20Sopenharmony_ci else /* OK if set_suspend_enable or set_suspend_disable is NULL */ 10978c2ecf20Sopenharmony_ci ret = 0; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (ret < 0) { 11008c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to enabled/disable: %pe\n", ERR_PTR(ret)); 11018c2ecf20Sopenharmony_ci return ret; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { 11058c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); 11068c2ecf20Sopenharmony_ci if (ret < 0) { 11078c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set voltage: %pe\n", ERR_PTR(ret)); 11088c2ecf20Sopenharmony_ci return ret; 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { 11138c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); 11148c2ecf20Sopenharmony_ci if (ret < 0) { 11158c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set mode: %pe\n", ERR_PTR(ret)); 11168c2ecf20Sopenharmony_ci return ret; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci return ret; 11218c2ecf20Sopenharmony_ci} 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int suspend_set_initial_state(struct regulator_dev *rdev) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci const struct regulator_state *rstate; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state_check(rdev, 11288c2ecf20Sopenharmony_ci rdev->constraints->initial_state); 11298c2ecf20Sopenharmony_ci if (!rstate) 11308c2ecf20Sopenharmony_ci return 0; 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_ci return __suspend_set_state(rdev, rstate); 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) 11368c2ecf20Sopenharmony_cistatic void print_constraints_debug(struct regulator_dev *rdev) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 11398c2ecf20Sopenharmony_ci char buf[160] = ""; 11408c2ecf20Sopenharmony_ci size_t len = sizeof(buf) - 1; 11418c2ecf20Sopenharmony_ci int count = 0; 11428c2ecf20Sopenharmony_ci int ret; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (constraints->min_uV && constraints->max_uV) { 11458c2ecf20Sopenharmony_ci if (constraints->min_uV == constraints->max_uV) 11468c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "%d mV ", 11478c2ecf20Sopenharmony_ci constraints->min_uV / 1000); 11488c2ecf20Sopenharmony_ci else 11498c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, 11508c2ecf20Sopenharmony_ci "%d <--> %d mV ", 11518c2ecf20Sopenharmony_ci constraints->min_uV / 1000, 11528c2ecf20Sopenharmony_ci constraints->max_uV / 1000); 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (!constraints->min_uV || 11568c2ecf20Sopenharmony_ci constraints->min_uV != constraints->max_uV) { 11578c2ecf20Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev); 11588c2ecf20Sopenharmony_ci if (ret > 0) 11598c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, 11608c2ecf20Sopenharmony_ci "at %d mV ", ret / 1000); 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci if (constraints->uV_offset) 11648c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "%dmV offset ", 11658c2ecf20Sopenharmony_ci constraints->uV_offset / 1000); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (constraints->min_uA && constraints->max_uA) { 11688c2ecf20Sopenharmony_ci if (constraints->min_uA == constraints->max_uA) 11698c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "%d mA ", 11708c2ecf20Sopenharmony_ci constraints->min_uA / 1000); 11718c2ecf20Sopenharmony_ci else 11728c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, 11738c2ecf20Sopenharmony_ci "%d <--> %d mA ", 11748c2ecf20Sopenharmony_ci constraints->min_uA / 1000, 11758c2ecf20Sopenharmony_ci constraints->max_uA / 1000); 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!constraints->min_uA || 11798c2ecf20Sopenharmony_ci constraints->min_uA != constraints->max_uA) { 11808c2ecf20Sopenharmony_ci ret = _regulator_get_current_limit(rdev); 11818c2ecf20Sopenharmony_ci if (ret > 0) 11828c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, 11838c2ecf20Sopenharmony_ci "at %d mA ", ret / 1000); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_FAST) 11878c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "fast "); 11888c2ecf20Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_NORMAL) 11898c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "normal "); 11908c2ecf20Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_IDLE) 11918c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "idle "); 11928c2ecf20Sopenharmony_ci if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) 11938c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, "standby "); 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci if (!count) 11968c2ecf20Sopenharmony_ci count = scnprintf(buf, len, "no parameters"); 11978c2ecf20Sopenharmony_ci else 11988c2ecf20Sopenharmony_ci --count; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci count += scnprintf(buf + count, len - count, ", %s", 12018c2ecf20Sopenharmony_ci _regulator_is_enabled(rdev) ? "enabled" : "disabled"); 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci rdev_dbg(rdev, "%s\n", buf); 12048c2ecf20Sopenharmony_ci} 12058c2ecf20Sopenharmony_ci#else /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 12068c2ecf20Sopenharmony_cistatic inline void print_constraints_debug(struct regulator_dev *rdev) {} 12078c2ecf20Sopenharmony_ci#endif /* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic void print_constraints(struct regulator_dev *rdev) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci print_constraints_debug(rdev); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if ((constraints->min_uV != constraints->max_uV) && 12168c2ecf20Sopenharmony_ci !regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) 12178c2ecf20Sopenharmony_ci rdev_warn(rdev, 12188c2ecf20Sopenharmony_ci "Voltage range but no REGULATOR_CHANGE_VOLTAGE\n"); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_cistatic int machine_constraints_voltage(struct regulator_dev *rdev, 12228c2ecf20Sopenharmony_ci struct regulation_constraints *constraints) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 12258c2ecf20Sopenharmony_ci int ret; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci /* do we need to apply the constraint voltage */ 12288c2ecf20Sopenharmony_ci if (rdev->constraints->apply_uV && 12298c2ecf20Sopenharmony_ci rdev->constraints->min_uV && rdev->constraints->max_uV) { 12308c2ecf20Sopenharmony_ci int target_min, target_max; 12318c2ecf20Sopenharmony_ci int current_uV = regulator_get_voltage_rdev(rdev); 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci if (current_uV == -ENOTRECOVERABLE) { 12348c2ecf20Sopenharmony_ci /* This regulator can't be read and must be initialized */ 12358c2ecf20Sopenharmony_ci rdev_info(rdev, "Setting %d-%duV\n", 12368c2ecf20Sopenharmony_ci rdev->constraints->min_uV, 12378c2ecf20Sopenharmony_ci rdev->constraints->max_uV); 12388c2ecf20Sopenharmony_ci _regulator_do_set_voltage(rdev, 12398c2ecf20Sopenharmony_ci rdev->constraints->min_uV, 12408c2ecf20Sopenharmony_ci rdev->constraints->max_uV); 12418c2ecf20Sopenharmony_ci current_uV = regulator_get_voltage_rdev(rdev); 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci if (current_uV < 0) { 12458c2ecf20Sopenharmony_ci rdev_err(rdev, 12468c2ecf20Sopenharmony_ci "failed to get the current voltage: %pe\n", 12478c2ecf20Sopenharmony_ci ERR_PTR(current_uV)); 12488c2ecf20Sopenharmony_ci return current_uV; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci /* 12528c2ecf20Sopenharmony_ci * If we're below the minimum voltage move up to the 12538c2ecf20Sopenharmony_ci * minimum voltage, if we're above the maximum voltage 12548c2ecf20Sopenharmony_ci * then move down to the maximum. 12558c2ecf20Sopenharmony_ci */ 12568c2ecf20Sopenharmony_ci target_min = current_uV; 12578c2ecf20Sopenharmony_ci target_max = current_uV; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci if (current_uV < rdev->constraints->min_uV) { 12608c2ecf20Sopenharmony_ci target_min = rdev->constraints->min_uV; 12618c2ecf20Sopenharmony_ci target_max = rdev->constraints->min_uV; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (current_uV > rdev->constraints->max_uV) { 12658c2ecf20Sopenharmony_ci target_min = rdev->constraints->max_uV; 12668c2ecf20Sopenharmony_ci target_max = rdev->constraints->max_uV; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci if (target_min != current_uV || target_max != current_uV) { 12708c2ecf20Sopenharmony_ci rdev_info(rdev, "Bringing %duV into %d-%duV\n", 12718c2ecf20Sopenharmony_ci current_uV, target_min, target_max); 12728c2ecf20Sopenharmony_ci ret = _regulator_do_set_voltage( 12738c2ecf20Sopenharmony_ci rdev, target_min, target_max); 12748c2ecf20Sopenharmony_ci if (ret < 0) { 12758c2ecf20Sopenharmony_ci rdev_err(rdev, 12768c2ecf20Sopenharmony_ci "failed to apply %d-%duV constraint: %pe\n", 12778c2ecf20Sopenharmony_ci target_min, target_max, ERR_PTR(ret)); 12788c2ecf20Sopenharmony_ci return ret; 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci } 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci /* constrain machine-level voltage specs to fit 12848c2ecf20Sopenharmony_ci * the actual range supported by this regulator. 12858c2ecf20Sopenharmony_ci */ 12868c2ecf20Sopenharmony_ci if (ops->list_voltage && rdev->desc->n_voltages) { 12878c2ecf20Sopenharmony_ci int count = rdev->desc->n_voltages; 12888c2ecf20Sopenharmony_ci int i; 12898c2ecf20Sopenharmony_ci int min_uV = INT_MAX; 12908c2ecf20Sopenharmony_ci int max_uV = INT_MIN; 12918c2ecf20Sopenharmony_ci int cmin = constraints->min_uV; 12928c2ecf20Sopenharmony_ci int cmax = constraints->max_uV; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci /* it's safe to autoconfigure fixed-voltage supplies 12958c2ecf20Sopenharmony_ci and the constraints are used by list_voltage. */ 12968c2ecf20Sopenharmony_ci if (count == 1 && !cmin) { 12978c2ecf20Sopenharmony_ci cmin = 1; 12988c2ecf20Sopenharmony_ci cmax = INT_MAX; 12998c2ecf20Sopenharmony_ci constraints->min_uV = cmin; 13008c2ecf20Sopenharmony_ci constraints->max_uV = cmax; 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* voltage constraints are optional */ 13048c2ecf20Sopenharmony_ci if ((cmin == 0) && (cmax == 0)) 13058c2ecf20Sopenharmony_ci return 0; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* else require explicit machine-level constraints */ 13088c2ecf20Sopenharmony_ci if (cmin <= 0 || cmax <= 0 || cmax < cmin) { 13098c2ecf20Sopenharmony_ci rdev_err(rdev, "invalid voltage constraints\n"); 13108c2ecf20Sopenharmony_ci return -EINVAL; 13118c2ecf20Sopenharmony_ci } 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* no need to loop voltages if range is continuous */ 13148c2ecf20Sopenharmony_ci if (rdev->desc->continuous_voltage_range) 13158c2ecf20Sopenharmony_ci return 0; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* initial: [cmin..cmax] valid, [min_uV..max_uV] not */ 13188c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 13198c2ecf20Sopenharmony_ci int value; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci value = ops->list_voltage(rdev, i); 13228c2ecf20Sopenharmony_ci if (value <= 0) 13238c2ecf20Sopenharmony_ci continue; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* maybe adjust [min_uV..max_uV] */ 13268c2ecf20Sopenharmony_ci if (value >= cmin && value < min_uV) 13278c2ecf20Sopenharmony_ci min_uV = value; 13288c2ecf20Sopenharmony_ci if (value <= cmax && value > max_uV) 13298c2ecf20Sopenharmony_ci max_uV = value; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* final: [min_uV..max_uV] valid iff constraints valid */ 13338c2ecf20Sopenharmony_ci if (max_uV < min_uV) { 13348c2ecf20Sopenharmony_ci rdev_err(rdev, 13358c2ecf20Sopenharmony_ci "unsupportable voltage constraints %u-%uuV\n", 13368c2ecf20Sopenharmony_ci min_uV, max_uV); 13378c2ecf20Sopenharmony_ci return -EINVAL; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* use regulator's subset of machine constraints */ 13418c2ecf20Sopenharmony_ci if (constraints->min_uV < min_uV) { 13428c2ecf20Sopenharmony_ci rdev_dbg(rdev, "override min_uV, %d -> %d\n", 13438c2ecf20Sopenharmony_ci constraints->min_uV, min_uV); 13448c2ecf20Sopenharmony_ci constraints->min_uV = min_uV; 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci if (constraints->max_uV > max_uV) { 13478c2ecf20Sopenharmony_ci rdev_dbg(rdev, "override max_uV, %d -> %d\n", 13488c2ecf20Sopenharmony_ci constraints->max_uV, max_uV); 13498c2ecf20Sopenharmony_ci constraints->max_uV = max_uV; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci} 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_cistatic int machine_constraints_current(struct regulator_dev *rdev, 13578c2ecf20Sopenharmony_ci struct regulation_constraints *constraints) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 13608c2ecf20Sopenharmony_ci int ret; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (!constraints->min_uA && !constraints->max_uA) 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (constraints->min_uA > constraints->max_uA) { 13668c2ecf20Sopenharmony_ci rdev_err(rdev, "Invalid current constraints\n"); 13678c2ecf20Sopenharmony_ci return -EINVAL; 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (!ops->set_current_limit || !ops->get_current_limit) { 13718c2ecf20Sopenharmony_ci rdev_warn(rdev, "Operation of current configuration missing\n"); 13728c2ecf20Sopenharmony_ci return 0; 13738c2ecf20Sopenharmony_ci } 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci /* Set regulator current in constraints range */ 13768c2ecf20Sopenharmony_ci ret = ops->set_current_limit(rdev, constraints->min_uA, 13778c2ecf20Sopenharmony_ci constraints->max_uA); 13788c2ecf20Sopenharmony_ci if (ret < 0) { 13798c2ecf20Sopenharmony_ci rdev_err(rdev, "Failed to set current constraint, %d\n", ret); 13808c2ecf20Sopenharmony_ci return ret; 13818c2ecf20Sopenharmony_ci } 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci return 0; 13848c2ecf20Sopenharmony_ci} 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cistatic int _regulator_do_enable(struct regulator_dev *rdev); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci/** 13898c2ecf20Sopenharmony_ci * set_machine_constraints - sets regulator constraints 13908c2ecf20Sopenharmony_ci * @rdev: regulator source 13918c2ecf20Sopenharmony_ci * 13928c2ecf20Sopenharmony_ci * Allows platform initialisation code to define and constrain 13938c2ecf20Sopenharmony_ci * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: 13948c2ecf20Sopenharmony_ci * Constraints *must* be set by platform code in order for some 13958c2ecf20Sopenharmony_ci * regulator operations to proceed i.e. set_voltage, set_current_limit, 13968c2ecf20Sopenharmony_ci * set_mode. 13978c2ecf20Sopenharmony_ci */ 13988c2ecf20Sopenharmony_cistatic int set_machine_constraints(struct regulator_dev *rdev) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci int ret = 0; 14018c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci ret = machine_constraints_voltage(rdev, rdev->constraints); 14048c2ecf20Sopenharmony_ci if (ret != 0) 14058c2ecf20Sopenharmony_ci return ret; 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = machine_constraints_current(rdev, rdev->constraints); 14088c2ecf20Sopenharmony_ci if (ret != 0) 14098c2ecf20Sopenharmony_ci return ret; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if (rdev->constraints->ilim_uA && ops->set_input_current_limit) { 14128c2ecf20Sopenharmony_ci ret = ops->set_input_current_limit(rdev, 14138c2ecf20Sopenharmony_ci rdev->constraints->ilim_uA); 14148c2ecf20Sopenharmony_ci if (ret < 0) { 14158c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set input limit: %pe\n", ERR_PTR(ret)); 14168c2ecf20Sopenharmony_ci return ret; 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* do we need to setup our suspend state */ 14218c2ecf20Sopenharmony_ci if (rdev->constraints->initial_state) { 14228c2ecf20Sopenharmony_ci ret = suspend_set_initial_state(rdev); 14238c2ecf20Sopenharmony_ci if (ret < 0) { 14248c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set suspend state: %pe\n", ERR_PTR(ret)); 14258c2ecf20Sopenharmony_ci return ret; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (rdev->constraints->initial_mode) { 14308c2ecf20Sopenharmony_ci if (!ops->set_mode) { 14318c2ecf20Sopenharmony_ci rdev_err(rdev, "no set_mode operation\n"); 14328c2ecf20Sopenharmony_ci return -EINVAL; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci ret = ops->set_mode(rdev, rdev->constraints->initial_mode); 14368c2ecf20Sopenharmony_ci if (ret < 0) { 14378c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set initial mode: %pe\n", ERR_PTR(ret)); 14388c2ecf20Sopenharmony_ci return ret; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci } else if (rdev->constraints->system_load) { 14418c2ecf20Sopenharmony_ci /* 14428c2ecf20Sopenharmony_ci * We'll only apply the initial system load if an 14438c2ecf20Sopenharmony_ci * initial mode wasn't specified. 14448c2ecf20Sopenharmony_ci */ 14458c2ecf20Sopenharmony_ci drms_uA_update(rdev); 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if ((rdev->constraints->ramp_delay || rdev->constraints->ramp_disable) 14498c2ecf20Sopenharmony_ci && ops->set_ramp_delay) { 14508c2ecf20Sopenharmony_ci ret = ops->set_ramp_delay(rdev, rdev->constraints->ramp_delay); 14518c2ecf20Sopenharmony_ci if (ret < 0) { 14528c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set ramp_delay: %pe\n", ERR_PTR(ret)); 14538c2ecf20Sopenharmony_ci return ret; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (rdev->constraints->pull_down && ops->set_pull_down) { 14588c2ecf20Sopenharmony_ci ret = ops->set_pull_down(rdev); 14598c2ecf20Sopenharmony_ci if (ret < 0) { 14608c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set pull down: %pe\n", ERR_PTR(ret)); 14618c2ecf20Sopenharmony_ci return ret; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (rdev->constraints->soft_start && ops->set_soft_start) { 14668c2ecf20Sopenharmony_ci ret = ops->set_soft_start(rdev); 14678c2ecf20Sopenharmony_ci if (ret < 0) { 14688c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set soft start: %pe\n", ERR_PTR(ret)); 14698c2ecf20Sopenharmony_ci return ret; 14708c2ecf20Sopenharmony_ci } 14718c2ecf20Sopenharmony_ci } 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (rdev->constraints->over_current_protection 14748c2ecf20Sopenharmony_ci && ops->set_over_current_protection) { 14758c2ecf20Sopenharmony_ci ret = ops->set_over_current_protection(rdev); 14768c2ecf20Sopenharmony_ci if (ret < 0) { 14778c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set over current protection: %pe\n", 14788c2ecf20Sopenharmony_ci ERR_PTR(ret)); 14798c2ecf20Sopenharmony_ci return ret; 14808c2ecf20Sopenharmony_ci } 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci if (rdev->constraints->active_discharge && ops->set_active_discharge) { 14848c2ecf20Sopenharmony_ci bool ad_state = (rdev->constraints->active_discharge == 14858c2ecf20Sopenharmony_ci REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci ret = ops->set_active_discharge(rdev, ad_state); 14888c2ecf20Sopenharmony_ci if (ret < 0) { 14898c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to set active discharge: %pe\n", ERR_PTR(ret)); 14908c2ecf20Sopenharmony_ci return ret; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci /* If the constraints say the regulator should be on at this point 14958c2ecf20Sopenharmony_ci * and we have control then make sure it is enabled. 14968c2ecf20Sopenharmony_ci */ 14978c2ecf20Sopenharmony_ci if (rdev->constraints->always_on || rdev->constraints->boot_on) { 14988c2ecf20Sopenharmony_ci /* If we want to enable this regulator, make sure that we know 14998c2ecf20Sopenharmony_ci * the supplying regulator. 15008c2ecf20Sopenharmony_ci */ 15018c2ecf20Sopenharmony_ci if (rdev->supply_name && !rdev->supply) 15028c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* If supplying regulator has already been enabled, 15058c2ecf20Sopenharmony_ci * it's not intended to have use_count increment 15068c2ecf20Sopenharmony_ci * when rdev is only boot-on. 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ci if (rdev->supply && 15098c2ecf20Sopenharmony_ci (rdev->constraints->always_on || 15108c2ecf20Sopenharmony_ci !regulator_is_enabled(rdev->supply))) { 15118c2ecf20Sopenharmony_ci ret = regulator_enable(rdev->supply); 15128c2ecf20Sopenharmony_ci if (ret < 0) { 15138c2ecf20Sopenharmony_ci _regulator_put(rdev->supply); 15148c2ecf20Sopenharmony_ci rdev->supply = NULL; 15158c2ecf20Sopenharmony_ci return ret; 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci } 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci ret = _regulator_do_enable(rdev); 15208c2ecf20Sopenharmony_ci if (ret < 0 && ret != -EINVAL) { 15218c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret)); 15228c2ecf20Sopenharmony_ci return ret; 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (rdev->constraints->always_on) 15268c2ecf20Sopenharmony_ci rdev->use_count++; 15278c2ecf20Sopenharmony_ci } else if (rdev->desc->off_on_delay) { 15288c2ecf20Sopenharmony_ci rdev->last_off_jiffy = jiffies; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci print_constraints(rdev); 15328c2ecf20Sopenharmony_ci return 0; 15338c2ecf20Sopenharmony_ci} 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci/** 15368c2ecf20Sopenharmony_ci * set_supply - set regulator supply regulator 15378c2ecf20Sopenharmony_ci * @rdev: regulator (locked) 15388c2ecf20Sopenharmony_ci * @supply_rdev: supply regulator (locked)) 15398c2ecf20Sopenharmony_ci * 15408c2ecf20Sopenharmony_ci * Called by platform initialisation code to set the supply regulator for this 15418c2ecf20Sopenharmony_ci * regulator. This ensures that a regulators supply will also be enabled by the 15428c2ecf20Sopenharmony_ci * core if it's child is enabled. 15438c2ecf20Sopenharmony_ci */ 15448c2ecf20Sopenharmony_cistatic int set_supply(struct regulator_dev *rdev, 15458c2ecf20Sopenharmony_ci struct regulator_dev *supply_rdev) 15468c2ecf20Sopenharmony_ci{ 15478c2ecf20Sopenharmony_ci int err; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci rdev_info(rdev, "supplied by %s\n", rdev_get_name(supply_rdev)); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (!try_module_get(supply_rdev->owner)) 15528c2ecf20Sopenharmony_ci return -ENODEV; 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci rdev->supply = create_regulator(supply_rdev, &rdev->dev, "SUPPLY"); 15558c2ecf20Sopenharmony_ci if (rdev->supply == NULL) { 15568c2ecf20Sopenharmony_ci module_put(supply_rdev->owner); 15578c2ecf20Sopenharmony_ci err = -ENOMEM; 15588c2ecf20Sopenharmony_ci return err; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci supply_rdev->open_count++; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci return 0; 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci/** 15668c2ecf20Sopenharmony_ci * set_consumer_device_supply - Bind a regulator to a symbolic supply 15678c2ecf20Sopenharmony_ci * @rdev: regulator source 15688c2ecf20Sopenharmony_ci * @consumer_dev_name: dev_name() string for device supply applies to 15698c2ecf20Sopenharmony_ci * @supply: symbolic name for supply 15708c2ecf20Sopenharmony_ci * 15718c2ecf20Sopenharmony_ci * Allows platform initialisation code to map physical regulator 15728c2ecf20Sopenharmony_ci * sources to symbolic names for supplies for use by devices. Devices 15738c2ecf20Sopenharmony_ci * should use these symbolic names to request regulators, avoiding the 15748c2ecf20Sopenharmony_ci * need to provide board-specific regulator names as platform data. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_cistatic int set_consumer_device_supply(struct regulator_dev *rdev, 15778c2ecf20Sopenharmony_ci const char *consumer_dev_name, 15788c2ecf20Sopenharmony_ci const char *supply) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci struct regulator_map *node, *new_node; 15818c2ecf20Sopenharmony_ci int has_dev; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (supply == NULL) 15848c2ecf20Sopenharmony_ci return -EINVAL; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if (consumer_dev_name != NULL) 15878c2ecf20Sopenharmony_ci has_dev = 1; 15888c2ecf20Sopenharmony_ci else 15898c2ecf20Sopenharmony_ci has_dev = 0; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci new_node = kzalloc(sizeof(struct regulator_map), GFP_KERNEL); 15928c2ecf20Sopenharmony_ci if (new_node == NULL) 15938c2ecf20Sopenharmony_ci return -ENOMEM; 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci new_node->regulator = rdev; 15968c2ecf20Sopenharmony_ci new_node->supply = supply; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (has_dev) { 15998c2ecf20Sopenharmony_ci new_node->dev_name = kstrdup(consumer_dev_name, GFP_KERNEL); 16008c2ecf20Sopenharmony_ci if (new_node->dev_name == NULL) { 16018c2ecf20Sopenharmony_ci kfree(new_node); 16028c2ecf20Sopenharmony_ci return -ENOMEM; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci } 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 16078c2ecf20Sopenharmony_ci list_for_each_entry(node, ®ulator_map_list, list) { 16088c2ecf20Sopenharmony_ci if (node->dev_name && consumer_dev_name) { 16098c2ecf20Sopenharmony_ci if (strcmp(node->dev_name, consumer_dev_name) != 0) 16108c2ecf20Sopenharmony_ci continue; 16118c2ecf20Sopenharmony_ci } else if (node->dev_name || consumer_dev_name) { 16128c2ecf20Sopenharmony_ci continue; 16138c2ecf20Sopenharmony_ci } 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (strcmp(node->supply, supply) != 0) 16168c2ecf20Sopenharmony_ci continue; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ci pr_debug("%s: %s/%s is '%s' supply; fail %s/%s\n", 16198c2ecf20Sopenharmony_ci consumer_dev_name, 16208c2ecf20Sopenharmony_ci dev_name(&node->regulator->dev), 16218c2ecf20Sopenharmony_ci node->regulator->desc->name, 16228c2ecf20Sopenharmony_ci supply, 16238c2ecf20Sopenharmony_ci dev_name(&rdev->dev), rdev_get_name(rdev)); 16248c2ecf20Sopenharmony_ci goto fail; 16258c2ecf20Sopenharmony_ci } 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci list_add(&new_node->list, ®ulator_map_list); 16288c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return 0; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cifail: 16338c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 16348c2ecf20Sopenharmony_ci kfree(new_node->dev_name); 16358c2ecf20Sopenharmony_ci kfree(new_node); 16368c2ecf20Sopenharmony_ci return -EBUSY; 16378c2ecf20Sopenharmony_ci} 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_cistatic void unset_regulator_supplies(struct regulator_dev *rdev) 16408c2ecf20Sopenharmony_ci{ 16418c2ecf20Sopenharmony_ci struct regulator_map *node, *n; 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci list_for_each_entry_safe(node, n, ®ulator_map_list, list) { 16448c2ecf20Sopenharmony_ci if (rdev == node->regulator) { 16458c2ecf20Sopenharmony_ci list_del(&node->list); 16468c2ecf20Sopenharmony_ci kfree(node->dev_name); 16478c2ecf20Sopenharmony_ci kfree(node); 16488c2ecf20Sopenharmony_ci } 16498c2ecf20Sopenharmony_ci } 16508c2ecf20Sopenharmony_ci} 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 16538c2ecf20Sopenharmony_cistatic ssize_t constraint_flags_read_file(struct file *file, 16548c2ecf20Sopenharmony_ci char __user *user_buf, 16558c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci const struct regulator *regulator = file->private_data; 16588c2ecf20Sopenharmony_ci const struct regulation_constraints *c = regulator->rdev->constraints; 16598c2ecf20Sopenharmony_ci char *buf; 16608c2ecf20Sopenharmony_ci ssize_t ret; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (!c) 16638c2ecf20Sopenharmony_ci return 0; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci buf = kmalloc(PAGE_SIZE, GFP_KERNEL); 16668c2ecf20Sopenharmony_ci if (!buf) 16678c2ecf20Sopenharmony_ci return -ENOMEM; 16688c2ecf20Sopenharmony_ci 16698c2ecf20Sopenharmony_ci ret = snprintf(buf, PAGE_SIZE, 16708c2ecf20Sopenharmony_ci "always_on: %u\n" 16718c2ecf20Sopenharmony_ci "boot_on: %u\n" 16728c2ecf20Sopenharmony_ci "apply_uV: %u\n" 16738c2ecf20Sopenharmony_ci "ramp_disable: %u\n" 16748c2ecf20Sopenharmony_ci "soft_start: %u\n" 16758c2ecf20Sopenharmony_ci "pull_down: %u\n" 16768c2ecf20Sopenharmony_ci "over_current_protection: %u\n", 16778c2ecf20Sopenharmony_ci c->always_on, 16788c2ecf20Sopenharmony_ci c->boot_on, 16798c2ecf20Sopenharmony_ci c->apply_uV, 16808c2ecf20Sopenharmony_ci c->ramp_disable, 16818c2ecf20Sopenharmony_ci c->soft_start, 16828c2ecf20Sopenharmony_ci c->pull_down, 16838c2ecf20Sopenharmony_ci c->over_current_protection); 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); 16868c2ecf20Sopenharmony_ci kfree(buf); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci return ret; 16898c2ecf20Sopenharmony_ci} 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci#endif 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic const struct file_operations constraint_flags_fops = { 16948c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 16958c2ecf20Sopenharmony_ci .open = simple_open, 16968c2ecf20Sopenharmony_ci .read = constraint_flags_read_file, 16978c2ecf20Sopenharmony_ci .llseek = default_llseek, 16988c2ecf20Sopenharmony_ci#endif 16998c2ecf20Sopenharmony_ci}; 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci#define REG_STR_SIZE 64 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_cistatic struct regulator *create_regulator(struct regulator_dev *rdev, 17048c2ecf20Sopenharmony_ci struct device *dev, 17058c2ecf20Sopenharmony_ci const char *supply_name) 17068c2ecf20Sopenharmony_ci{ 17078c2ecf20Sopenharmony_ci struct regulator *regulator; 17088c2ecf20Sopenharmony_ci int err = 0; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci if (dev) { 17138c2ecf20Sopenharmony_ci char buf[REG_STR_SIZE]; 17148c2ecf20Sopenharmony_ci int size; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci size = snprintf(buf, REG_STR_SIZE, "%s-%s", 17178c2ecf20Sopenharmony_ci dev->kobj.name, supply_name); 17188c2ecf20Sopenharmony_ci if (size >= REG_STR_SIZE) 17198c2ecf20Sopenharmony_ci return NULL; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci supply_name = kstrdup(buf, GFP_KERNEL); 17228c2ecf20Sopenharmony_ci if (supply_name == NULL) 17238c2ecf20Sopenharmony_ci return NULL; 17248c2ecf20Sopenharmony_ci } else { 17258c2ecf20Sopenharmony_ci supply_name = kstrdup_const(supply_name, GFP_KERNEL); 17268c2ecf20Sopenharmony_ci if (supply_name == NULL) 17278c2ecf20Sopenharmony_ci return NULL; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci regulator = kzalloc(sizeof(*regulator), GFP_KERNEL); 17318c2ecf20Sopenharmony_ci if (regulator == NULL) { 17328c2ecf20Sopenharmony_ci kfree_const(supply_name); 17338c2ecf20Sopenharmony_ci return NULL; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci regulator->rdev = rdev; 17378c2ecf20Sopenharmony_ci regulator->supply_name = supply_name; 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci list_add(®ulator->list, &rdev->consumer_list); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (dev) { 17428c2ecf20Sopenharmony_ci regulator->dev = dev; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci /* Add a link to the device sysfs entry */ 17458c2ecf20Sopenharmony_ci err = sysfs_create_link_nowarn(&rdev->dev.kobj, &dev->kobj, 17468c2ecf20Sopenharmony_ci supply_name); 17478c2ecf20Sopenharmony_ci if (err) { 17488c2ecf20Sopenharmony_ci rdev_dbg(rdev, "could not add device link %s: %pe\n", 17498c2ecf20Sopenharmony_ci dev->kobj.name, ERR_PTR(err)); 17508c2ecf20Sopenharmony_ci /* non-fatal */ 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if (err != -EEXIST) 17558c2ecf20Sopenharmony_ci regulator->debugfs = debugfs_create_dir(supply_name, rdev->debugfs); 17568c2ecf20Sopenharmony_ci if (IS_ERR(regulator->debugfs)) 17578c2ecf20Sopenharmony_ci rdev_dbg(rdev, "Failed to create debugfs directory\n"); 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci debugfs_create_u32("uA_load", 0444, regulator->debugfs, 17608c2ecf20Sopenharmony_ci ®ulator->uA_load); 17618c2ecf20Sopenharmony_ci debugfs_create_u32("min_uV", 0444, regulator->debugfs, 17628c2ecf20Sopenharmony_ci ®ulator->voltage[PM_SUSPEND_ON].min_uV); 17638c2ecf20Sopenharmony_ci debugfs_create_u32("max_uV", 0444, regulator->debugfs, 17648c2ecf20Sopenharmony_ci ®ulator->voltage[PM_SUSPEND_ON].max_uV); 17658c2ecf20Sopenharmony_ci debugfs_create_file("constraint_flags", 0444, regulator->debugfs, 17668c2ecf20Sopenharmony_ci regulator, &constraint_flags_fops); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci /* 17698c2ecf20Sopenharmony_ci * Check now if the regulator is an always on regulator - if 17708c2ecf20Sopenharmony_ci * it is then we don't need to do nearly so much work for 17718c2ecf20Sopenharmony_ci * enable/disable calls. 17728c2ecf20Sopenharmony_ci */ 17738c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS) && 17748c2ecf20Sopenharmony_ci _regulator_is_enabled(rdev)) 17758c2ecf20Sopenharmony_ci regulator->always_on = true; 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci return regulator; 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_cistatic int _regulator_get_enable_time(struct regulator_dev *rdev) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci if (rdev->constraints && rdev->constraints->enable_time) 17838c2ecf20Sopenharmony_ci return rdev->constraints->enable_time; 17848c2ecf20Sopenharmony_ci if (rdev->desc->ops->enable_time) 17858c2ecf20Sopenharmony_ci return rdev->desc->ops->enable_time(rdev); 17868c2ecf20Sopenharmony_ci return rdev->desc->enable_time; 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_cistatic struct regulator_supply_alias *regulator_find_supply_alias( 17908c2ecf20Sopenharmony_ci struct device *dev, const char *supply) 17918c2ecf20Sopenharmony_ci{ 17928c2ecf20Sopenharmony_ci struct regulator_supply_alias *map; 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci list_for_each_entry(map, ®ulator_supply_alias_list, list) 17958c2ecf20Sopenharmony_ci if (map->src_dev == dev && strcmp(map->src_supply, supply) == 0) 17968c2ecf20Sopenharmony_ci return map; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci return NULL; 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_cistatic void regulator_supply_alias(struct device **dev, const char **supply) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci struct regulator_supply_alias *map; 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci map = regulator_find_supply_alias(*dev, *supply); 18068c2ecf20Sopenharmony_ci if (map) { 18078c2ecf20Sopenharmony_ci dev_dbg(*dev, "Mapping supply %s to %s,%s\n", 18088c2ecf20Sopenharmony_ci *supply, map->alias_supply, 18098c2ecf20Sopenharmony_ci dev_name(map->alias_dev)); 18108c2ecf20Sopenharmony_ci *dev = map->alias_dev; 18118c2ecf20Sopenharmony_ci *supply = map->alias_supply; 18128c2ecf20Sopenharmony_ci } 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic int regulator_match(struct device *dev, const void *data) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci struct regulator_dev *r = dev_to_rdev(dev); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci return strcmp(rdev_get_name(r), data) == 0; 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_cistatic struct regulator_dev *regulator_lookup_by_name(const char *name) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci struct device *dev; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci dev = class_find_device(®ulator_class, NULL, name, regulator_match); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci return dev ? dev_to_rdev(dev) : NULL; 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci/** 18328c2ecf20Sopenharmony_ci * regulator_dev_lookup - lookup a regulator device. 18338c2ecf20Sopenharmony_ci * @dev: device for regulator "consumer". 18348c2ecf20Sopenharmony_ci * @supply: Supply name or regulator ID. 18358c2ecf20Sopenharmony_ci * 18368c2ecf20Sopenharmony_ci * If successful, returns a struct regulator_dev that corresponds to the name 18378c2ecf20Sopenharmony_ci * @supply and with the embedded struct device refcount incremented by one. 18388c2ecf20Sopenharmony_ci * The refcount must be dropped by calling put_device(). 18398c2ecf20Sopenharmony_ci * On failure one of the following ERR-PTR-encoded values is returned: 18408c2ecf20Sopenharmony_ci * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed 18418c2ecf20Sopenharmony_ci * in the future. 18428c2ecf20Sopenharmony_ci */ 18438c2ecf20Sopenharmony_cistatic struct regulator_dev *regulator_dev_lookup(struct device *dev, 18448c2ecf20Sopenharmony_ci const char *supply) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci struct regulator_dev *r = NULL; 18478c2ecf20Sopenharmony_ci struct device_node *node; 18488c2ecf20Sopenharmony_ci struct regulator_map *map; 18498c2ecf20Sopenharmony_ci const char *devname = NULL; 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci regulator_supply_alias(&dev, &supply); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci /* first do a dt based lookup */ 18548c2ecf20Sopenharmony_ci if (dev && dev->of_node) { 18558c2ecf20Sopenharmony_ci node = of_get_regulator(dev, supply); 18568c2ecf20Sopenharmony_ci if (node) { 18578c2ecf20Sopenharmony_ci r = of_find_regulator_by_node(node); 18588c2ecf20Sopenharmony_ci of_node_put(node); 18598c2ecf20Sopenharmony_ci if (r) 18608c2ecf20Sopenharmony_ci return r; 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci /* 18638c2ecf20Sopenharmony_ci * We have a node, but there is no device. 18648c2ecf20Sopenharmony_ci * assume it has not registered yet. 18658c2ecf20Sopenharmony_ci */ 18668c2ecf20Sopenharmony_ci return ERR_PTR(-EPROBE_DEFER); 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_ci /* if not found, try doing it non-dt way */ 18718c2ecf20Sopenharmony_ci if (dev) 18728c2ecf20Sopenharmony_ci devname = dev_name(dev); 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 18758c2ecf20Sopenharmony_ci list_for_each_entry(map, ®ulator_map_list, list) { 18768c2ecf20Sopenharmony_ci /* If the mapping has a device set up it must match */ 18778c2ecf20Sopenharmony_ci if (map->dev_name && 18788c2ecf20Sopenharmony_ci (!devname || strcmp(map->dev_name, devname))) 18798c2ecf20Sopenharmony_ci continue; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci if (strcmp(map->supply, supply) == 0 && 18828c2ecf20Sopenharmony_ci get_device(&map->regulator->dev)) { 18838c2ecf20Sopenharmony_ci r = map->regulator; 18848c2ecf20Sopenharmony_ci break; 18858c2ecf20Sopenharmony_ci } 18868c2ecf20Sopenharmony_ci } 18878c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci if (r) 18908c2ecf20Sopenharmony_ci return r; 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci r = regulator_lookup_by_name(supply); 18938c2ecf20Sopenharmony_ci if (r) 18948c2ecf20Sopenharmony_ci return r; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 18978c2ecf20Sopenharmony_ci} 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_cistatic int regulator_resolve_supply(struct regulator_dev *rdev) 19008c2ecf20Sopenharmony_ci{ 19018c2ecf20Sopenharmony_ci struct regulator_dev *r; 19028c2ecf20Sopenharmony_ci struct device *dev = rdev->dev.parent; 19038c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 19048c2ecf20Sopenharmony_ci int ret = 0; 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci /* No supply to resolve? */ 19078c2ecf20Sopenharmony_ci if (!rdev->supply_name) 19088c2ecf20Sopenharmony_ci return 0; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci /* Supply already resolved? (fast-path without locking contention) */ 19118c2ecf20Sopenharmony_ci if (rdev->supply) 19128c2ecf20Sopenharmony_ci return 0; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci r = regulator_dev_lookup(dev, rdev->supply_name); 19158c2ecf20Sopenharmony_ci if (IS_ERR(r)) { 19168c2ecf20Sopenharmony_ci ret = PTR_ERR(r); 19178c2ecf20Sopenharmony_ci 19188c2ecf20Sopenharmony_ci /* Did the lookup explicitly defer for us? */ 19198c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) 19208c2ecf20Sopenharmony_ci goto out; 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_ci if (have_full_constraints()) { 19238c2ecf20Sopenharmony_ci r = dummy_regulator_rdev; 19248c2ecf20Sopenharmony_ci get_device(&r->dev); 19258c2ecf20Sopenharmony_ci } else { 19268c2ecf20Sopenharmony_ci dev_err(dev, "Failed to resolve %s-supply for %s\n", 19278c2ecf20Sopenharmony_ci rdev->supply_name, rdev->desc->name); 19288c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 19298c2ecf20Sopenharmony_ci goto out; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci if (r == rdev) { 19348c2ecf20Sopenharmony_ci dev_err(dev, "Supply for %s (%s) resolved to itself\n", 19358c2ecf20Sopenharmony_ci rdev->desc->name, rdev->supply_name); 19368c2ecf20Sopenharmony_ci if (!have_full_constraints()) { 19378c2ecf20Sopenharmony_ci ret = -EINVAL; 19388c2ecf20Sopenharmony_ci goto out; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci r = dummy_regulator_rdev; 19418c2ecf20Sopenharmony_ci get_device(&r->dev); 19428c2ecf20Sopenharmony_ci } 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci /* 19458c2ecf20Sopenharmony_ci * If the supply's parent device is not the same as the 19468c2ecf20Sopenharmony_ci * regulator's parent device, then ensure the parent device 19478c2ecf20Sopenharmony_ci * is bound before we resolve the supply, in case the parent 19488c2ecf20Sopenharmony_ci * device get probe deferred and unregisters the supply. 19498c2ecf20Sopenharmony_ci */ 19508c2ecf20Sopenharmony_ci if (r->dev.parent && r->dev.parent != rdev->dev.parent) { 19518c2ecf20Sopenharmony_ci if (!device_is_bound(r->dev.parent)) { 19528c2ecf20Sopenharmony_ci put_device(&r->dev); 19538c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 19548c2ecf20Sopenharmony_ci goto out; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci } 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci /* Recursively resolve the supply of the supply */ 19598c2ecf20Sopenharmony_ci ret = regulator_resolve_supply(r); 19608c2ecf20Sopenharmony_ci if (ret < 0) { 19618c2ecf20Sopenharmony_ci put_device(&r->dev); 19628c2ecf20Sopenharmony_ci goto out; 19638c2ecf20Sopenharmony_ci } 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci /* 19668c2ecf20Sopenharmony_ci * Recheck rdev->supply with rdev->mutex lock held to avoid a race 19678c2ecf20Sopenharmony_ci * between rdev->supply null check and setting rdev->supply in 19688c2ecf20Sopenharmony_ci * set_supply() from concurrent tasks. 19698c2ecf20Sopenharmony_ci */ 19708c2ecf20Sopenharmony_ci regulator_lock_two(rdev, r, &ww_ctx); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci /* Supply just resolved by a concurrent task? */ 19738c2ecf20Sopenharmony_ci if (rdev->supply) { 19748c2ecf20Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 19758c2ecf20Sopenharmony_ci put_device(&r->dev); 19768c2ecf20Sopenharmony_ci goto out; 19778c2ecf20Sopenharmony_ci } 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci ret = set_supply(rdev, r); 19808c2ecf20Sopenharmony_ci if (ret < 0) { 19818c2ecf20Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 19828c2ecf20Sopenharmony_ci put_device(&r->dev); 19838c2ecf20Sopenharmony_ci goto out; 19848c2ecf20Sopenharmony_ci } 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci regulator_unlock_two(rdev, r, &ww_ctx); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci /* 19898c2ecf20Sopenharmony_ci * In set_machine_constraints() we may have turned this regulator on 19908c2ecf20Sopenharmony_ci * but we couldn't propagate to the supply if it hadn't been resolved 19918c2ecf20Sopenharmony_ci * yet. Do it now. 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_ci if (rdev->use_count) { 19948c2ecf20Sopenharmony_ci ret = regulator_enable(rdev->supply); 19958c2ecf20Sopenharmony_ci if (ret < 0) { 19968c2ecf20Sopenharmony_ci _regulator_put(rdev->supply); 19978c2ecf20Sopenharmony_ci rdev->supply = NULL; 19988c2ecf20Sopenharmony_ci goto out; 19998c2ecf20Sopenharmony_ci } 20008c2ecf20Sopenharmony_ci } 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ciout: 20038c2ecf20Sopenharmony_ci return ret; 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci/* Internal regulator request function */ 20078c2ecf20Sopenharmony_cistruct regulator *_regulator_get(struct device *dev, const char *id, 20088c2ecf20Sopenharmony_ci enum regulator_get_type get_type) 20098c2ecf20Sopenharmony_ci{ 20108c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 20118c2ecf20Sopenharmony_ci struct regulator *regulator; 20128c2ecf20Sopenharmony_ci struct device_link *link; 20138c2ecf20Sopenharmony_ci int ret; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (get_type >= MAX_GET_TYPE) { 20168c2ecf20Sopenharmony_ci dev_err(dev, "invalid type %d in %s\n", get_type, __func__); 20178c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (id == NULL) { 20218c2ecf20Sopenharmony_ci pr_err("get() with no identifier\n"); 20228c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 20238c2ecf20Sopenharmony_ci } 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci rdev = regulator_dev_lookup(dev, id); 20268c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 20278c2ecf20Sopenharmony_ci ret = PTR_ERR(rdev); 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ci /* 20308c2ecf20Sopenharmony_ci * If regulator_dev_lookup() fails with error other 20318c2ecf20Sopenharmony_ci * than -ENODEV our job here is done, we simply return it. 20328c2ecf20Sopenharmony_ci */ 20338c2ecf20Sopenharmony_ci if (ret != -ENODEV) 20348c2ecf20Sopenharmony_ci return ERR_PTR(ret); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci if (!have_full_constraints()) { 20378c2ecf20Sopenharmony_ci dev_warn(dev, 20388c2ecf20Sopenharmony_ci "incomplete constraints, dummy supplies not allowed\n"); 20398c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci switch (get_type) { 20438c2ecf20Sopenharmony_ci case NORMAL_GET: 20448c2ecf20Sopenharmony_ci /* 20458c2ecf20Sopenharmony_ci * Assume that a regulator is physically present and 20468c2ecf20Sopenharmony_ci * enabled, even if it isn't hooked up, and just 20478c2ecf20Sopenharmony_ci * provide a dummy. 20488c2ecf20Sopenharmony_ci */ 20498c2ecf20Sopenharmony_ci dev_warn(dev, "supply %s not found, using dummy regulator\n", id); 20508c2ecf20Sopenharmony_ci rdev = dummy_regulator_rdev; 20518c2ecf20Sopenharmony_ci get_device(&rdev->dev); 20528c2ecf20Sopenharmony_ci break; 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci case EXCLUSIVE_GET: 20558c2ecf20Sopenharmony_ci dev_warn(dev, 20568c2ecf20Sopenharmony_ci "dummy supplies not allowed for exclusive requests\n"); 20578c2ecf20Sopenharmony_ci fallthrough; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci default: 20608c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 20618c2ecf20Sopenharmony_ci } 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci if (rdev->exclusive) { 20658c2ecf20Sopenharmony_ci regulator = ERR_PTR(-EPERM); 20668c2ecf20Sopenharmony_ci put_device(&rdev->dev); 20678c2ecf20Sopenharmony_ci return regulator; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci if (get_type == EXCLUSIVE_GET && rdev->open_count) { 20718c2ecf20Sopenharmony_ci regulator = ERR_PTR(-EBUSY); 20728c2ecf20Sopenharmony_ci put_device(&rdev->dev); 20738c2ecf20Sopenharmony_ci return regulator; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 20778c2ecf20Sopenharmony_ci ret = (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled); 20788c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (ret != 0) { 20818c2ecf20Sopenharmony_ci regulator = ERR_PTR(-EPROBE_DEFER); 20828c2ecf20Sopenharmony_ci put_device(&rdev->dev); 20838c2ecf20Sopenharmony_ci return regulator; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci ret = regulator_resolve_supply(rdev); 20878c2ecf20Sopenharmony_ci if (ret < 0) { 20888c2ecf20Sopenharmony_ci regulator = ERR_PTR(ret); 20898c2ecf20Sopenharmony_ci put_device(&rdev->dev); 20908c2ecf20Sopenharmony_ci return regulator; 20918c2ecf20Sopenharmony_ci } 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci if (!try_module_get(rdev->owner)) { 20948c2ecf20Sopenharmony_ci regulator = ERR_PTR(-EPROBE_DEFER); 20958c2ecf20Sopenharmony_ci put_device(&rdev->dev); 20968c2ecf20Sopenharmony_ci return regulator; 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci regulator_lock(rdev); 21008c2ecf20Sopenharmony_ci regulator = create_regulator(rdev, dev, id); 21018c2ecf20Sopenharmony_ci regulator_unlock(rdev); 21028c2ecf20Sopenharmony_ci if (regulator == NULL) { 21038c2ecf20Sopenharmony_ci regulator = ERR_PTR(-ENOMEM); 21048c2ecf20Sopenharmony_ci module_put(rdev->owner); 21058c2ecf20Sopenharmony_ci put_device(&rdev->dev); 21068c2ecf20Sopenharmony_ci return regulator; 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci rdev->open_count++; 21108c2ecf20Sopenharmony_ci if (get_type == EXCLUSIVE_GET) { 21118c2ecf20Sopenharmony_ci rdev->exclusive = 1; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci ret = _regulator_is_enabled(rdev); 21148c2ecf20Sopenharmony_ci if (ret > 0) { 21158c2ecf20Sopenharmony_ci rdev->use_count = 1; 21168c2ecf20Sopenharmony_ci regulator->enable_count = 1; 21178c2ecf20Sopenharmony_ci } else { 21188c2ecf20Sopenharmony_ci rdev->use_count = 0; 21198c2ecf20Sopenharmony_ci regulator->enable_count = 0; 21208c2ecf20Sopenharmony_ci } 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci link = device_link_add(dev, &rdev->dev, DL_FLAG_STATELESS); 21248c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(link)) 21258c2ecf20Sopenharmony_ci regulator->device_link = true; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci return regulator; 21288c2ecf20Sopenharmony_ci} 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci/** 21318c2ecf20Sopenharmony_ci * regulator_get - lookup and obtain a reference to a regulator. 21328c2ecf20Sopenharmony_ci * @dev: device for regulator "consumer" 21338c2ecf20Sopenharmony_ci * @id: Supply name or regulator ID. 21348c2ecf20Sopenharmony_ci * 21358c2ecf20Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 21368c2ecf20Sopenharmony_ci * or IS_ERR() condition containing errno. 21378c2ecf20Sopenharmony_ci * 21388c2ecf20Sopenharmony_ci * Use of supply names configured via regulator_set_device_supply() is 21398c2ecf20Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 21408c2ecf20Sopenharmony_ci * should match the name used for the supply and/or the relevant 21418c2ecf20Sopenharmony_ci * device pins in the datasheet. 21428c2ecf20Sopenharmony_ci */ 21438c2ecf20Sopenharmony_cistruct regulator *regulator_get(struct device *dev, const char *id) 21448c2ecf20Sopenharmony_ci{ 21458c2ecf20Sopenharmony_ci return _regulator_get(dev, id, NORMAL_GET); 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get); 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci/** 21508c2ecf20Sopenharmony_ci * regulator_get_exclusive - obtain exclusive access to a regulator. 21518c2ecf20Sopenharmony_ci * @dev: device for regulator "consumer" 21528c2ecf20Sopenharmony_ci * @id: Supply name or regulator ID. 21538c2ecf20Sopenharmony_ci * 21548c2ecf20Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 21558c2ecf20Sopenharmony_ci * or IS_ERR() condition containing errno. Other consumers will be 21568c2ecf20Sopenharmony_ci * unable to obtain this regulator while this reference is held and the 21578c2ecf20Sopenharmony_ci * use count for the regulator will be initialised to reflect the current 21588c2ecf20Sopenharmony_ci * state of the regulator. 21598c2ecf20Sopenharmony_ci * 21608c2ecf20Sopenharmony_ci * This is intended for use by consumers which cannot tolerate shared 21618c2ecf20Sopenharmony_ci * use of the regulator such as those which need to force the 21628c2ecf20Sopenharmony_ci * regulator off for correct operation of the hardware they are 21638c2ecf20Sopenharmony_ci * controlling. 21648c2ecf20Sopenharmony_ci * 21658c2ecf20Sopenharmony_ci * Use of supply names configured via regulator_set_device_supply() is 21668c2ecf20Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 21678c2ecf20Sopenharmony_ci * should match the name used for the supply and/or the relevant 21688c2ecf20Sopenharmony_ci * device pins in the datasheet. 21698c2ecf20Sopenharmony_ci */ 21708c2ecf20Sopenharmony_cistruct regulator *regulator_get_exclusive(struct device *dev, const char *id) 21718c2ecf20Sopenharmony_ci{ 21728c2ecf20Sopenharmony_ci return _regulator_get(dev, id, EXCLUSIVE_GET); 21738c2ecf20Sopenharmony_ci} 21748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_exclusive); 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci/** 21778c2ecf20Sopenharmony_ci * regulator_get_optional - obtain optional access to a regulator. 21788c2ecf20Sopenharmony_ci * @dev: device for regulator "consumer" 21798c2ecf20Sopenharmony_ci * @id: Supply name or regulator ID. 21808c2ecf20Sopenharmony_ci * 21818c2ecf20Sopenharmony_ci * Returns a struct regulator corresponding to the regulator producer, 21828c2ecf20Sopenharmony_ci * or IS_ERR() condition containing errno. 21838c2ecf20Sopenharmony_ci * 21848c2ecf20Sopenharmony_ci * This is intended for use by consumers for devices which can have 21858c2ecf20Sopenharmony_ci * some supplies unconnected in normal use, such as some MMC devices. 21868c2ecf20Sopenharmony_ci * It can allow the regulator core to provide stub supplies for other 21878c2ecf20Sopenharmony_ci * supplies requested using normal regulator_get() calls without 21888c2ecf20Sopenharmony_ci * disrupting the operation of drivers that can handle absent 21898c2ecf20Sopenharmony_ci * supplies. 21908c2ecf20Sopenharmony_ci * 21918c2ecf20Sopenharmony_ci * Use of supply names configured via regulator_set_device_supply() is 21928c2ecf20Sopenharmony_ci * strongly encouraged. It is recommended that the supply name used 21938c2ecf20Sopenharmony_ci * should match the name used for the supply and/or the relevant 21948c2ecf20Sopenharmony_ci * device pins in the datasheet. 21958c2ecf20Sopenharmony_ci */ 21968c2ecf20Sopenharmony_cistruct regulator *regulator_get_optional(struct device *dev, const char *id) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci return _regulator_get(dev, id, OPTIONAL_GET); 21998c2ecf20Sopenharmony_ci} 22008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_optional); 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_cistatic void destroy_regulator(struct regulator *regulator) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci debugfs_remove_recursive(regulator->debugfs); 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci if (regulator->dev) { 22098c2ecf20Sopenharmony_ci if (regulator->device_link) 22108c2ecf20Sopenharmony_ci device_link_remove(regulator->dev, &rdev->dev); 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci /* remove any sysfs entries */ 22138c2ecf20Sopenharmony_ci sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); 22148c2ecf20Sopenharmony_ci } 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci regulator_lock(rdev); 22178c2ecf20Sopenharmony_ci list_del(®ulator->list); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci rdev->open_count--; 22208c2ecf20Sopenharmony_ci rdev->exclusive = 0; 22218c2ecf20Sopenharmony_ci regulator_unlock(rdev); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci kfree_const(regulator->supply_name); 22248c2ecf20Sopenharmony_ci kfree(regulator); 22258c2ecf20Sopenharmony_ci} 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci/* regulator_list_mutex lock held by regulator_put() */ 22288c2ecf20Sopenharmony_cistatic void _regulator_put(struct regulator *regulator) 22298c2ecf20Sopenharmony_ci{ 22308c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(regulator)) 22338c2ecf20Sopenharmony_ci return; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci lockdep_assert_held_once(®ulator_list_mutex); 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci /* Docs say you must disable before calling regulator_put() */ 22388c2ecf20Sopenharmony_ci WARN_ON(regulator->enable_count); 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci rdev = regulator->rdev; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci destroy_regulator(regulator); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci module_put(rdev->owner); 22458c2ecf20Sopenharmony_ci put_device(&rdev->dev); 22468c2ecf20Sopenharmony_ci} 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci/** 22498c2ecf20Sopenharmony_ci * regulator_put - "free" the regulator source 22508c2ecf20Sopenharmony_ci * @regulator: regulator source 22518c2ecf20Sopenharmony_ci * 22528c2ecf20Sopenharmony_ci * Note: drivers must ensure that all regulator_enable calls made on this 22538c2ecf20Sopenharmony_ci * regulator source are balanced by regulator_disable calls prior to calling 22548c2ecf20Sopenharmony_ci * this function. 22558c2ecf20Sopenharmony_ci */ 22568c2ecf20Sopenharmony_civoid regulator_put(struct regulator *regulator) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 22598c2ecf20Sopenharmony_ci _regulator_put(regulator); 22608c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 22618c2ecf20Sopenharmony_ci} 22628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_put); 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci/** 22658c2ecf20Sopenharmony_ci * regulator_register_supply_alias - Provide device alias for supply lookup 22668c2ecf20Sopenharmony_ci * 22678c2ecf20Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 22688c2ecf20Sopenharmony_ci * @id: Supply name or regulator ID 22698c2ecf20Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 22708c2ecf20Sopenharmony_ci * @alias_id: Supply name or regulator ID that should be used to lookup the 22718c2ecf20Sopenharmony_ci * supply 22728c2ecf20Sopenharmony_ci * 22738c2ecf20Sopenharmony_ci * All lookups for id on dev will instead be conducted for alias_id on 22748c2ecf20Sopenharmony_ci * alias_dev. 22758c2ecf20Sopenharmony_ci */ 22768c2ecf20Sopenharmony_ciint regulator_register_supply_alias(struct device *dev, const char *id, 22778c2ecf20Sopenharmony_ci struct device *alias_dev, 22788c2ecf20Sopenharmony_ci const char *alias_id) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci struct regulator_supply_alias *map; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci map = regulator_find_supply_alias(dev, id); 22838c2ecf20Sopenharmony_ci if (map) 22848c2ecf20Sopenharmony_ci return -EEXIST; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci map = kzalloc(sizeof(struct regulator_supply_alias), GFP_KERNEL); 22878c2ecf20Sopenharmony_ci if (!map) 22888c2ecf20Sopenharmony_ci return -ENOMEM; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci map->src_dev = dev; 22918c2ecf20Sopenharmony_ci map->src_supply = id; 22928c2ecf20Sopenharmony_ci map->alias_dev = alias_dev; 22938c2ecf20Sopenharmony_ci map->alias_supply = alias_id; 22948c2ecf20Sopenharmony_ci 22958c2ecf20Sopenharmony_ci list_add(&map->list, ®ulator_supply_alias_list); 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci pr_info("Adding alias for supply %s,%s -> %s,%s\n", 22988c2ecf20Sopenharmony_ci id, dev_name(dev), alias_id, dev_name(alias_dev)); 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci return 0; 23018c2ecf20Sopenharmony_ci} 23028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register_supply_alias); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci/** 23058c2ecf20Sopenharmony_ci * regulator_unregister_supply_alias - Remove device alias 23068c2ecf20Sopenharmony_ci * 23078c2ecf20Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 23088c2ecf20Sopenharmony_ci * @id: Supply name or regulator ID 23098c2ecf20Sopenharmony_ci * 23108c2ecf20Sopenharmony_ci * Remove a lookup alias if one exists for id on dev. 23118c2ecf20Sopenharmony_ci */ 23128c2ecf20Sopenharmony_civoid regulator_unregister_supply_alias(struct device *dev, const char *id) 23138c2ecf20Sopenharmony_ci{ 23148c2ecf20Sopenharmony_ci struct regulator_supply_alias *map; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci map = regulator_find_supply_alias(dev, id); 23178c2ecf20Sopenharmony_ci if (map) { 23188c2ecf20Sopenharmony_ci list_del(&map->list); 23198c2ecf20Sopenharmony_ci kfree(map); 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci} 23228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister_supply_alias); 23238c2ecf20Sopenharmony_ci 23248c2ecf20Sopenharmony_ci/** 23258c2ecf20Sopenharmony_ci * regulator_bulk_register_supply_alias - register multiple aliases 23268c2ecf20Sopenharmony_ci * 23278c2ecf20Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 23288c2ecf20Sopenharmony_ci * @id: List of supply names or regulator IDs 23298c2ecf20Sopenharmony_ci * @alias_dev: device that should be used to lookup the supply 23308c2ecf20Sopenharmony_ci * @alias_id: List of supply names or regulator IDs that should be used to 23318c2ecf20Sopenharmony_ci * lookup the supply 23328c2ecf20Sopenharmony_ci * @num_id: Number of aliases to register 23338c2ecf20Sopenharmony_ci * 23348c2ecf20Sopenharmony_ci * @return 0 on success, an errno on failure. 23358c2ecf20Sopenharmony_ci * 23368c2ecf20Sopenharmony_ci * This helper function allows drivers to register several supply 23378c2ecf20Sopenharmony_ci * aliases in one operation. If any of the aliases cannot be 23388c2ecf20Sopenharmony_ci * registered any aliases that were registered will be removed 23398c2ecf20Sopenharmony_ci * before returning to the caller. 23408c2ecf20Sopenharmony_ci */ 23418c2ecf20Sopenharmony_ciint regulator_bulk_register_supply_alias(struct device *dev, 23428c2ecf20Sopenharmony_ci const char *const *id, 23438c2ecf20Sopenharmony_ci struct device *alias_dev, 23448c2ecf20Sopenharmony_ci const char *const *alias_id, 23458c2ecf20Sopenharmony_ci int num_id) 23468c2ecf20Sopenharmony_ci{ 23478c2ecf20Sopenharmony_ci int i; 23488c2ecf20Sopenharmony_ci int ret; 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci for (i = 0; i < num_id; ++i) { 23518c2ecf20Sopenharmony_ci ret = regulator_register_supply_alias(dev, id[i], alias_dev, 23528c2ecf20Sopenharmony_ci alias_id[i]); 23538c2ecf20Sopenharmony_ci if (ret < 0) 23548c2ecf20Sopenharmony_ci goto err; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci return 0; 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_cierr: 23608c2ecf20Sopenharmony_ci dev_err(dev, 23618c2ecf20Sopenharmony_ci "Failed to create supply alias %s,%s -> %s,%s\n", 23628c2ecf20Sopenharmony_ci id[i], dev_name(dev), alias_id[i], dev_name(alias_dev)); 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci while (--i >= 0) 23658c2ecf20Sopenharmony_ci regulator_unregister_supply_alias(dev, id[i]); 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci return ret; 23688c2ecf20Sopenharmony_ci} 23698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_register_supply_alias); 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci/** 23728c2ecf20Sopenharmony_ci * regulator_bulk_unregister_supply_alias - unregister multiple aliases 23738c2ecf20Sopenharmony_ci * 23748c2ecf20Sopenharmony_ci * @dev: device that will be given as the regulator "consumer" 23758c2ecf20Sopenharmony_ci * @id: List of supply names or regulator IDs 23768c2ecf20Sopenharmony_ci * @num_id: Number of aliases to unregister 23778c2ecf20Sopenharmony_ci * 23788c2ecf20Sopenharmony_ci * This helper function allows drivers to unregister several supply 23798c2ecf20Sopenharmony_ci * aliases in one operation. 23808c2ecf20Sopenharmony_ci */ 23818c2ecf20Sopenharmony_civoid regulator_bulk_unregister_supply_alias(struct device *dev, 23828c2ecf20Sopenharmony_ci const char *const *id, 23838c2ecf20Sopenharmony_ci int num_id) 23848c2ecf20Sopenharmony_ci{ 23858c2ecf20Sopenharmony_ci int i; 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci for (i = 0; i < num_id; ++i) 23888c2ecf20Sopenharmony_ci regulator_unregister_supply_alias(dev, id[i]); 23898c2ecf20Sopenharmony_ci} 23908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_unregister_supply_alias); 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci/* Manage enable GPIO list. Same GPIO pin can be shared among regulators */ 23948c2ecf20Sopenharmony_cistatic int regulator_ena_gpio_request(struct regulator_dev *rdev, 23958c2ecf20Sopenharmony_ci const struct regulator_config *config) 23968c2ecf20Sopenharmony_ci{ 23978c2ecf20Sopenharmony_ci struct regulator_enable_gpio *pin, *new_pin; 23988c2ecf20Sopenharmony_ci struct gpio_desc *gpiod; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci gpiod = config->ena_gpiod; 24018c2ecf20Sopenharmony_ci new_pin = kzalloc(sizeof(*new_pin), GFP_KERNEL); 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci list_for_each_entry(pin, ®ulator_ena_gpio_list, list) { 24068c2ecf20Sopenharmony_ci if (pin->gpiod == gpiod) { 24078c2ecf20Sopenharmony_ci rdev_dbg(rdev, "GPIO is already used\n"); 24088c2ecf20Sopenharmony_ci goto update_ena_gpio_to_rdev; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci } 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (new_pin == NULL) { 24138c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 24148c2ecf20Sopenharmony_ci return -ENOMEM; 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci pin = new_pin; 24188c2ecf20Sopenharmony_ci new_pin = NULL; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci pin->gpiod = gpiod; 24218c2ecf20Sopenharmony_ci list_add(&pin->list, ®ulator_ena_gpio_list); 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_ciupdate_ena_gpio_to_rdev: 24248c2ecf20Sopenharmony_ci pin->request_count++; 24258c2ecf20Sopenharmony_ci rdev->ena_pin = pin; 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 24288c2ecf20Sopenharmony_ci kfree(new_pin); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci return 0; 24318c2ecf20Sopenharmony_ci} 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_cistatic void regulator_ena_gpio_free(struct regulator_dev *rdev) 24348c2ecf20Sopenharmony_ci{ 24358c2ecf20Sopenharmony_ci struct regulator_enable_gpio *pin, *n; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci if (!rdev->ena_pin) 24388c2ecf20Sopenharmony_ci return; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci /* Free the GPIO only in case of no use */ 24418c2ecf20Sopenharmony_ci list_for_each_entry_safe(pin, n, ®ulator_ena_gpio_list, list) { 24428c2ecf20Sopenharmony_ci if (pin != rdev->ena_pin) 24438c2ecf20Sopenharmony_ci continue; 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci if (--pin->request_count) 24468c2ecf20Sopenharmony_ci break; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci gpiod_put(pin->gpiod); 24498c2ecf20Sopenharmony_ci list_del(&pin->list); 24508c2ecf20Sopenharmony_ci kfree(pin); 24518c2ecf20Sopenharmony_ci break; 24528c2ecf20Sopenharmony_ci } 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci rdev->ena_pin = NULL; 24558c2ecf20Sopenharmony_ci} 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ci/** 24588c2ecf20Sopenharmony_ci * regulator_ena_gpio_ctrl - balance enable_count of each GPIO and actual GPIO pin control 24598c2ecf20Sopenharmony_ci * @rdev: regulator_dev structure 24608c2ecf20Sopenharmony_ci * @enable: enable GPIO at initial use? 24618c2ecf20Sopenharmony_ci * 24628c2ecf20Sopenharmony_ci * GPIO is enabled in case of initial use. (enable_count is 0) 24638c2ecf20Sopenharmony_ci * GPIO is disabled when it is not shared any more. (enable_count <= 1) 24648c2ecf20Sopenharmony_ci */ 24658c2ecf20Sopenharmony_cistatic int regulator_ena_gpio_ctrl(struct regulator_dev *rdev, bool enable) 24668c2ecf20Sopenharmony_ci{ 24678c2ecf20Sopenharmony_ci struct regulator_enable_gpio *pin = rdev->ena_pin; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (!pin) 24708c2ecf20Sopenharmony_ci return -EINVAL; 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci if (enable) { 24738c2ecf20Sopenharmony_ci /* Enable GPIO at initial use */ 24748c2ecf20Sopenharmony_ci if (pin->enable_count == 0) 24758c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(pin->gpiod, 1); 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci pin->enable_count++; 24788c2ecf20Sopenharmony_ci } else { 24798c2ecf20Sopenharmony_ci if (pin->enable_count > 1) { 24808c2ecf20Sopenharmony_ci pin->enable_count--; 24818c2ecf20Sopenharmony_ci return 0; 24828c2ecf20Sopenharmony_ci } 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_ci /* Disable GPIO if not used */ 24858c2ecf20Sopenharmony_ci if (pin->enable_count <= 1) { 24868c2ecf20Sopenharmony_ci gpiod_set_value_cansleep(pin->gpiod, 0); 24878c2ecf20Sopenharmony_ci pin->enable_count = 0; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci return 0; 24928c2ecf20Sopenharmony_ci} 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci/** 24958c2ecf20Sopenharmony_ci * _regulator_enable_delay - a delay helper function 24968c2ecf20Sopenharmony_ci * @delay: time to delay in microseconds 24978c2ecf20Sopenharmony_ci * 24988c2ecf20Sopenharmony_ci * Delay for the requested amount of time as per the guidelines in: 24998c2ecf20Sopenharmony_ci * 25008c2ecf20Sopenharmony_ci * Documentation/timers/timers-howto.rst 25018c2ecf20Sopenharmony_ci * 25028c2ecf20Sopenharmony_ci * The assumption here is that regulators will never be enabled in 25038c2ecf20Sopenharmony_ci * atomic context and therefore sleeping functions can be used. 25048c2ecf20Sopenharmony_ci */ 25058c2ecf20Sopenharmony_cistatic void _regulator_enable_delay(unsigned int delay) 25068c2ecf20Sopenharmony_ci{ 25078c2ecf20Sopenharmony_ci unsigned int ms = delay / 1000; 25088c2ecf20Sopenharmony_ci unsigned int us = delay % 1000; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (ms > 0) { 25118c2ecf20Sopenharmony_ci /* 25128c2ecf20Sopenharmony_ci * For small enough values, handle super-millisecond 25138c2ecf20Sopenharmony_ci * delays in the usleep_range() call below. 25148c2ecf20Sopenharmony_ci */ 25158c2ecf20Sopenharmony_ci if (ms < 20) 25168c2ecf20Sopenharmony_ci us += ms * 1000; 25178c2ecf20Sopenharmony_ci else 25188c2ecf20Sopenharmony_ci msleep(ms); 25198c2ecf20Sopenharmony_ci } 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci /* 25228c2ecf20Sopenharmony_ci * Give the scheduler some room to coalesce with any other 25238c2ecf20Sopenharmony_ci * wakeup sources. For delays shorter than 10 us, don't even 25248c2ecf20Sopenharmony_ci * bother setting up high-resolution timers and just busy- 25258c2ecf20Sopenharmony_ci * loop. 25268c2ecf20Sopenharmony_ci */ 25278c2ecf20Sopenharmony_ci if (us >= 10) 25288c2ecf20Sopenharmony_ci usleep_range(us, us + 100); 25298c2ecf20Sopenharmony_ci else 25308c2ecf20Sopenharmony_ci udelay(us); 25318c2ecf20Sopenharmony_ci} 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci/** 25348c2ecf20Sopenharmony_ci * _regulator_check_status_enabled 25358c2ecf20Sopenharmony_ci * 25368c2ecf20Sopenharmony_ci * A helper function to check if the regulator status can be interpreted 25378c2ecf20Sopenharmony_ci * as 'regulator is enabled'. 25388c2ecf20Sopenharmony_ci * @rdev: the regulator device to check 25398c2ecf20Sopenharmony_ci * 25408c2ecf20Sopenharmony_ci * Return: 25418c2ecf20Sopenharmony_ci * * 1 - if status shows regulator is in enabled state 25428c2ecf20Sopenharmony_ci * * 0 - if not enabled state 25438c2ecf20Sopenharmony_ci * * Error Value - as received from ops->get_status() 25448c2ecf20Sopenharmony_ci */ 25458c2ecf20Sopenharmony_cistatic inline int _regulator_check_status_enabled(struct regulator_dev *rdev) 25468c2ecf20Sopenharmony_ci{ 25478c2ecf20Sopenharmony_ci int ret = rdev->desc->ops->get_status(rdev); 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci if (ret < 0) { 25508c2ecf20Sopenharmony_ci rdev_info(rdev, "get_status returned error: %d\n", ret); 25518c2ecf20Sopenharmony_ci return ret; 25528c2ecf20Sopenharmony_ci } 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci switch (ret) { 25558c2ecf20Sopenharmony_ci case REGULATOR_STATUS_OFF: 25568c2ecf20Sopenharmony_ci case REGULATOR_STATUS_ERROR: 25578c2ecf20Sopenharmony_ci case REGULATOR_STATUS_UNDEFINED: 25588c2ecf20Sopenharmony_ci return 0; 25598c2ecf20Sopenharmony_ci default: 25608c2ecf20Sopenharmony_ci return 1; 25618c2ecf20Sopenharmony_ci } 25628c2ecf20Sopenharmony_ci} 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_cistatic int _regulator_do_enable(struct regulator_dev *rdev) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci int ret, delay; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci /* Query before enabling in case configuration dependent. */ 25698c2ecf20Sopenharmony_ci ret = _regulator_get_enable_time(rdev); 25708c2ecf20Sopenharmony_ci if (ret >= 0) { 25718c2ecf20Sopenharmony_ci delay = ret; 25728c2ecf20Sopenharmony_ci } else { 25738c2ecf20Sopenharmony_ci rdev_warn(rdev, "enable_time() failed: %pe\n", ERR_PTR(ret)); 25748c2ecf20Sopenharmony_ci delay = 0; 25758c2ecf20Sopenharmony_ci } 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci trace_regulator_enable(rdev_get_name(rdev)); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci if (rdev->desc->off_on_delay) { 25808c2ecf20Sopenharmony_ci /* if needed, keep a distance of off_on_delay from last time 25818c2ecf20Sopenharmony_ci * this regulator was disabled. 25828c2ecf20Sopenharmony_ci */ 25838c2ecf20Sopenharmony_ci unsigned long start_jiffy = jiffies; 25848c2ecf20Sopenharmony_ci unsigned long intended, max_delay, remaining; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci max_delay = usecs_to_jiffies(rdev->desc->off_on_delay); 25878c2ecf20Sopenharmony_ci intended = rdev->last_off_jiffy + max_delay; 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_ci if (time_before(start_jiffy, intended)) { 25908c2ecf20Sopenharmony_ci /* calc remaining jiffies to deal with one-time 25918c2ecf20Sopenharmony_ci * timer wrapping. 25928c2ecf20Sopenharmony_ci * in case of multiple timer wrapping, either it can be 25938c2ecf20Sopenharmony_ci * detected by out-of-range remaining, or it cannot be 25948c2ecf20Sopenharmony_ci * detected and we get a penalty of 25958c2ecf20Sopenharmony_ci * _regulator_enable_delay(). 25968c2ecf20Sopenharmony_ci */ 25978c2ecf20Sopenharmony_ci remaining = intended - start_jiffy; 25988c2ecf20Sopenharmony_ci if (remaining <= max_delay) 25998c2ecf20Sopenharmony_ci _regulator_enable_delay( 26008c2ecf20Sopenharmony_ci jiffies_to_usecs(remaining)); 26018c2ecf20Sopenharmony_ci } 26028c2ecf20Sopenharmony_ci } 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci if (rdev->ena_pin) { 26058c2ecf20Sopenharmony_ci if (!rdev->ena_gpio_state) { 26068c2ecf20Sopenharmony_ci ret = regulator_ena_gpio_ctrl(rdev, true); 26078c2ecf20Sopenharmony_ci if (ret < 0) 26088c2ecf20Sopenharmony_ci return ret; 26098c2ecf20Sopenharmony_ci rdev->ena_gpio_state = 1; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci } else if (rdev->desc->ops->enable) { 26128c2ecf20Sopenharmony_ci ret = rdev->desc->ops->enable(rdev); 26138c2ecf20Sopenharmony_ci if (ret < 0) 26148c2ecf20Sopenharmony_ci return ret; 26158c2ecf20Sopenharmony_ci } else { 26168c2ecf20Sopenharmony_ci return -EINVAL; 26178c2ecf20Sopenharmony_ci } 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci /* Allow the regulator to ramp; it would be useful to extend 26208c2ecf20Sopenharmony_ci * this for bulk operations so that the regulators can ramp 26218c2ecf20Sopenharmony_ci * together. */ 26228c2ecf20Sopenharmony_ci trace_regulator_enable_delay(rdev_get_name(rdev)); 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci /* If poll_enabled_time is set, poll upto the delay calculated 26258c2ecf20Sopenharmony_ci * above, delaying poll_enabled_time uS to check if the regulator 26268c2ecf20Sopenharmony_ci * actually got enabled. 26278c2ecf20Sopenharmony_ci * If the regulator isn't enabled after enable_delay has 26288c2ecf20Sopenharmony_ci * expired, return -ETIMEDOUT. 26298c2ecf20Sopenharmony_ci */ 26308c2ecf20Sopenharmony_ci if (rdev->desc->poll_enabled_time) { 26318c2ecf20Sopenharmony_ci int time_remaining = delay; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci while (time_remaining > 0) { 26348c2ecf20Sopenharmony_ci _regulator_enable_delay(rdev->desc->poll_enabled_time); 26358c2ecf20Sopenharmony_ci 26368c2ecf20Sopenharmony_ci if (rdev->desc->ops->get_status) { 26378c2ecf20Sopenharmony_ci ret = _regulator_check_status_enabled(rdev); 26388c2ecf20Sopenharmony_ci if (ret < 0) 26398c2ecf20Sopenharmony_ci return ret; 26408c2ecf20Sopenharmony_ci else if (ret) 26418c2ecf20Sopenharmony_ci break; 26428c2ecf20Sopenharmony_ci } else if (rdev->desc->ops->is_enabled(rdev)) 26438c2ecf20Sopenharmony_ci break; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci time_remaining -= rdev->desc->poll_enabled_time; 26468c2ecf20Sopenharmony_ci } 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci if (time_remaining <= 0) { 26498c2ecf20Sopenharmony_ci rdev_err(rdev, "Enabled check timed out\n"); 26508c2ecf20Sopenharmony_ci return -ETIMEDOUT; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci } else { 26538c2ecf20Sopenharmony_ci _regulator_enable_delay(delay); 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci trace_regulator_enable_complete(rdev_get_name(rdev)); 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci return 0; 26598c2ecf20Sopenharmony_ci} 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci/** 26628c2ecf20Sopenharmony_ci * _regulator_handle_consumer_enable - handle that a consumer enabled 26638c2ecf20Sopenharmony_ci * @regulator: regulator source 26648c2ecf20Sopenharmony_ci * 26658c2ecf20Sopenharmony_ci * Some things on a regulator consumer (like the contribution towards total 26668c2ecf20Sopenharmony_ci * load on the regulator) only have an effect when the consumer wants the 26678c2ecf20Sopenharmony_ci * regulator enabled. Explained in example with two consumers of the same 26688c2ecf20Sopenharmony_ci * regulator: 26698c2ecf20Sopenharmony_ci * consumer A: set_load(100); => total load = 0 26708c2ecf20Sopenharmony_ci * consumer A: regulator_enable(); => total load = 100 26718c2ecf20Sopenharmony_ci * consumer B: set_load(1000); => total load = 100 26728c2ecf20Sopenharmony_ci * consumer B: regulator_enable(); => total load = 1100 26738c2ecf20Sopenharmony_ci * consumer A: regulator_disable(); => total_load = 1000 26748c2ecf20Sopenharmony_ci * 26758c2ecf20Sopenharmony_ci * This function (together with _regulator_handle_consumer_disable) is 26768c2ecf20Sopenharmony_ci * responsible for keeping track of the refcount for a given regulator consumer 26778c2ecf20Sopenharmony_ci * and applying / unapplying these things. 26788c2ecf20Sopenharmony_ci * 26798c2ecf20Sopenharmony_ci * Returns 0 upon no error; -error upon error. 26808c2ecf20Sopenharmony_ci */ 26818c2ecf20Sopenharmony_cistatic int _regulator_handle_consumer_enable(struct regulator *regulator) 26828c2ecf20Sopenharmony_ci{ 26838c2ecf20Sopenharmony_ci int ret; 26848c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci regulator->enable_count++; 26898c2ecf20Sopenharmony_ci if (regulator->uA_load && regulator->enable_count == 1) { 26908c2ecf20Sopenharmony_ci ret = drms_uA_update(rdev); 26918c2ecf20Sopenharmony_ci if (ret) 26928c2ecf20Sopenharmony_ci regulator->enable_count--; 26938c2ecf20Sopenharmony_ci return ret; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci return 0; 26978c2ecf20Sopenharmony_ci} 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci/** 27008c2ecf20Sopenharmony_ci * _regulator_handle_consumer_disable - handle that a consumer disabled 27018c2ecf20Sopenharmony_ci * @regulator: regulator source 27028c2ecf20Sopenharmony_ci * 27038c2ecf20Sopenharmony_ci * The opposite of _regulator_handle_consumer_enable(). 27048c2ecf20Sopenharmony_ci * 27058c2ecf20Sopenharmony_ci * Returns 0 upon no error; -error upon error. 27068c2ecf20Sopenharmony_ci */ 27078c2ecf20Sopenharmony_cistatic int _regulator_handle_consumer_disable(struct regulator *regulator) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (!regulator->enable_count) { 27148c2ecf20Sopenharmony_ci rdev_err(rdev, "Underflow of regulator enable count\n"); 27158c2ecf20Sopenharmony_ci return -EINVAL; 27168c2ecf20Sopenharmony_ci } 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci regulator->enable_count--; 27198c2ecf20Sopenharmony_ci if (regulator->uA_load && regulator->enable_count == 0) 27208c2ecf20Sopenharmony_ci return drms_uA_update(rdev); 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci return 0; 27238c2ecf20Sopenharmony_ci} 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci/* locks held by regulator_enable() */ 27268c2ecf20Sopenharmony_cistatic int _regulator_enable(struct regulator *regulator) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 27298c2ecf20Sopenharmony_ci int ret; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci if (rdev->use_count == 0 && rdev->supply) { 27348c2ecf20Sopenharmony_ci ret = _regulator_enable(rdev->supply); 27358c2ecf20Sopenharmony_ci if (ret < 0) 27368c2ecf20Sopenharmony_ci return ret; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci /* balance only if there are regulators coupled */ 27408c2ecf20Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) { 27418c2ecf20Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 27428c2ecf20Sopenharmony_ci if (ret < 0) 27438c2ecf20Sopenharmony_ci goto err_disable_supply; 27448c2ecf20Sopenharmony_ci } 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci ret = _regulator_handle_consumer_enable(regulator); 27478c2ecf20Sopenharmony_ci if (ret < 0) 27488c2ecf20Sopenharmony_ci goto err_disable_supply; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci if (rdev->use_count == 0) { 27518c2ecf20Sopenharmony_ci /* The regulator may on if it's not switchable or left on */ 27528c2ecf20Sopenharmony_ci ret = _regulator_is_enabled(rdev); 27538c2ecf20Sopenharmony_ci if (ret == -EINVAL || ret == 0) { 27548c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, 27558c2ecf20Sopenharmony_ci REGULATOR_CHANGE_STATUS)) { 27568c2ecf20Sopenharmony_ci ret = -EPERM; 27578c2ecf20Sopenharmony_ci goto err_consumer_disable; 27588c2ecf20Sopenharmony_ci } 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci ret = _regulator_do_enable(rdev); 27618c2ecf20Sopenharmony_ci if (ret < 0) 27628c2ecf20Sopenharmony_ci goto err_consumer_disable; 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ENABLE, 27658c2ecf20Sopenharmony_ci NULL); 27668c2ecf20Sopenharmony_ci } else if (ret < 0) { 27678c2ecf20Sopenharmony_ci rdev_err(rdev, "is_enabled() failed: %pe\n", ERR_PTR(ret)); 27688c2ecf20Sopenharmony_ci goto err_consumer_disable; 27698c2ecf20Sopenharmony_ci } 27708c2ecf20Sopenharmony_ci /* Fallthrough on positive return values - already enabled */ 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci if (regulator->enable_count == 1) 27748c2ecf20Sopenharmony_ci rdev->use_count++; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci return 0; 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_cierr_consumer_disable: 27798c2ecf20Sopenharmony_ci _regulator_handle_consumer_disable(regulator); 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_cierr_disable_supply: 27828c2ecf20Sopenharmony_ci if (rdev->use_count == 0 && rdev->supply) 27838c2ecf20Sopenharmony_ci _regulator_disable(rdev->supply); 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci return ret; 27868c2ecf20Sopenharmony_ci} 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci/** 27898c2ecf20Sopenharmony_ci * regulator_enable - enable regulator output 27908c2ecf20Sopenharmony_ci * @regulator: regulator source 27918c2ecf20Sopenharmony_ci * 27928c2ecf20Sopenharmony_ci * Request that the regulator be enabled with the regulator output at 27938c2ecf20Sopenharmony_ci * the predefined voltage or current value. Calls to regulator_enable() 27948c2ecf20Sopenharmony_ci * must be balanced with calls to regulator_disable(). 27958c2ecf20Sopenharmony_ci * 27968c2ecf20Sopenharmony_ci * NOTE: the output value can be set by other drivers, boot loader or may be 27978c2ecf20Sopenharmony_ci * hardwired in the regulator. 27988c2ecf20Sopenharmony_ci */ 27998c2ecf20Sopenharmony_ciint regulator_enable(struct regulator *regulator) 28008c2ecf20Sopenharmony_ci{ 28018c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 28028c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 28038c2ecf20Sopenharmony_ci int ret; 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 28068c2ecf20Sopenharmony_ci ret = _regulator_enable(regulator); 28078c2ecf20Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci return ret; 28108c2ecf20Sopenharmony_ci} 28118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_enable); 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_cistatic int _regulator_do_disable(struct regulator_dev *rdev) 28148c2ecf20Sopenharmony_ci{ 28158c2ecf20Sopenharmony_ci int ret; 28168c2ecf20Sopenharmony_ci 28178c2ecf20Sopenharmony_ci trace_regulator_disable(rdev_get_name(rdev)); 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci if (rdev->ena_pin) { 28208c2ecf20Sopenharmony_ci if (rdev->ena_gpio_state) { 28218c2ecf20Sopenharmony_ci ret = regulator_ena_gpio_ctrl(rdev, false); 28228c2ecf20Sopenharmony_ci if (ret < 0) 28238c2ecf20Sopenharmony_ci return ret; 28248c2ecf20Sopenharmony_ci rdev->ena_gpio_state = 0; 28258c2ecf20Sopenharmony_ci } 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci } else if (rdev->desc->ops->disable) { 28288c2ecf20Sopenharmony_ci ret = rdev->desc->ops->disable(rdev); 28298c2ecf20Sopenharmony_ci if (ret != 0) 28308c2ecf20Sopenharmony_ci return ret; 28318c2ecf20Sopenharmony_ci } 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci /* cares about last_off_jiffy only if off_on_delay is required by 28348c2ecf20Sopenharmony_ci * device. 28358c2ecf20Sopenharmony_ci */ 28368c2ecf20Sopenharmony_ci if (rdev->desc->off_on_delay) 28378c2ecf20Sopenharmony_ci rdev->last_off_jiffy = jiffies; 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci trace_regulator_disable_complete(rdev_get_name(rdev)); 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci return 0; 28428c2ecf20Sopenharmony_ci} 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci/* locks held by regulator_disable() */ 28458c2ecf20Sopenharmony_cistatic int _regulator_disable(struct regulator *regulator) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 28488c2ecf20Sopenharmony_ci int ret = 0; 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci if (WARN(regulator->enable_count == 0, 28538c2ecf20Sopenharmony_ci "unbalanced disables for %s\n", rdev_get_name(rdev))) 28548c2ecf20Sopenharmony_ci return -EIO; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci if (regulator->enable_count == 1) { 28578c2ecf20Sopenharmony_ci /* disabling last enable_count from this regulator */ 28588c2ecf20Sopenharmony_ci /* are we the last user and permitted to disable ? */ 28598c2ecf20Sopenharmony_ci if (rdev->use_count == 1 && 28608c2ecf20Sopenharmony_ci (rdev->constraints && !rdev->constraints->always_on)) { 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci /* we are last user */ 28638c2ecf20Sopenharmony_ci if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { 28648c2ecf20Sopenharmony_ci ret = _notifier_call_chain(rdev, 28658c2ecf20Sopenharmony_ci REGULATOR_EVENT_PRE_DISABLE, 28668c2ecf20Sopenharmony_ci NULL); 28678c2ecf20Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 28688c2ecf20Sopenharmony_ci return -EINVAL; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci ret = _regulator_do_disable(rdev); 28718c2ecf20Sopenharmony_ci if (ret < 0) { 28728c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret)); 28738c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, 28748c2ecf20Sopenharmony_ci REGULATOR_EVENT_ABORT_DISABLE, 28758c2ecf20Sopenharmony_ci NULL); 28768c2ecf20Sopenharmony_ci return ret; 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, 28798c2ecf20Sopenharmony_ci NULL); 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci rdev->use_count = 0; 28838c2ecf20Sopenharmony_ci } else if (rdev->use_count > 1) { 28848c2ecf20Sopenharmony_ci rdev->use_count--; 28858c2ecf20Sopenharmony_ci } 28868c2ecf20Sopenharmony_ci } 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci if (ret == 0) 28898c2ecf20Sopenharmony_ci ret = _regulator_handle_consumer_disable(regulator); 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci if (ret == 0 && rdev->coupling_desc.n_coupled > 1) 28928c2ecf20Sopenharmony_ci ret = regulator_balance_voltage(rdev, PM_SUSPEND_ON); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (ret == 0 && rdev->use_count == 0 && rdev->supply) 28958c2ecf20Sopenharmony_ci ret = _regulator_disable(rdev->supply); 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci return ret; 28988c2ecf20Sopenharmony_ci} 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci/** 29018c2ecf20Sopenharmony_ci * regulator_disable - disable regulator output 29028c2ecf20Sopenharmony_ci * @regulator: regulator source 29038c2ecf20Sopenharmony_ci * 29048c2ecf20Sopenharmony_ci * Disable the regulator output voltage or current. Calls to 29058c2ecf20Sopenharmony_ci * regulator_enable() must be balanced with calls to 29068c2ecf20Sopenharmony_ci * regulator_disable(). 29078c2ecf20Sopenharmony_ci * 29088c2ecf20Sopenharmony_ci * NOTE: this will only disable the regulator output if no other consumer 29098c2ecf20Sopenharmony_ci * devices have it enabled, the regulator device supports disabling and 29108c2ecf20Sopenharmony_ci * machine constraints permit this operation. 29118c2ecf20Sopenharmony_ci */ 29128c2ecf20Sopenharmony_ciint regulator_disable(struct regulator *regulator) 29138c2ecf20Sopenharmony_ci{ 29148c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 29158c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 29168c2ecf20Sopenharmony_ci int ret; 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 29198c2ecf20Sopenharmony_ci ret = _regulator_disable(regulator); 29208c2ecf20Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci return ret; 29238c2ecf20Sopenharmony_ci} 29248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_disable); 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci/* locks held by regulator_force_disable() */ 29278c2ecf20Sopenharmony_cistatic int _regulator_force_disable(struct regulator_dev *rdev) 29288c2ecf20Sopenharmony_ci{ 29298c2ecf20Sopenharmony_ci int ret = 0; 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci lockdep_assert_held_once(&rdev->mutex.base); 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 29348c2ecf20Sopenharmony_ci REGULATOR_EVENT_PRE_DISABLE, NULL); 29358c2ecf20Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 29368c2ecf20Sopenharmony_ci return -EINVAL; 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci ret = _regulator_do_disable(rdev); 29398c2ecf20Sopenharmony_ci if (ret < 0) { 29408c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to force disable: %pe\n", ERR_PTR(ret)); 29418c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 29428c2ecf20Sopenharmony_ci REGULATOR_EVENT_ABORT_DISABLE, NULL); 29438c2ecf20Sopenharmony_ci return ret; 29448c2ecf20Sopenharmony_ci } 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | 29478c2ecf20Sopenharmony_ci REGULATOR_EVENT_DISABLE, NULL); 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci return 0; 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci/** 29538c2ecf20Sopenharmony_ci * regulator_force_disable - force disable regulator output 29548c2ecf20Sopenharmony_ci * @regulator: regulator source 29558c2ecf20Sopenharmony_ci * 29568c2ecf20Sopenharmony_ci * Forcibly disable the regulator output voltage or current. 29578c2ecf20Sopenharmony_ci * NOTE: this *will* disable the regulator output even if other consumer 29588c2ecf20Sopenharmony_ci * devices have it enabled. This should be used for situations when device 29598c2ecf20Sopenharmony_ci * damage will likely occur if the regulator is not disabled (e.g. over temp). 29608c2ecf20Sopenharmony_ci */ 29618c2ecf20Sopenharmony_ciint regulator_force_disable(struct regulator *regulator) 29628c2ecf20Sopenharmony_ci{ 29638c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 29648c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 29658c2ecf20Sopenharmony_ci int ret; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci ret = _regulator_force_disable(regulator->rdev); 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 29728c2ecf20Sopenharmony_ci regulator_balance_voltage(rdev, PM_SUSPEND_ON); 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci if (regulator->uA_load) { 29758c2ecf20Sopenharmony_ci regulator->uA_load = 0; 29768c2ecf20Sopenharmony_ci ret = drms_uA_update(rdev); 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci if (rdev->use_count != 0 && rdev->supply) 29808c2ecf20Sopenharmony_ci _regulator_disable(rdev->supply); 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci return ret; 29858c2ecf20Sopenharmony_ci} 29868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_force_disable); 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_cistatic void regulator_disable_work(struct work_struct *work) 29898c2ecf20Sopenharmony_ci{ 29908c2ecf20Sopenharmony_ci struct regulator_dev *rdev = container_of(work, struct regulator_dev, 29918c2ecf20Sopenharmony_ci disable_work.work); 29928c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 29938c2ecf20Sopenharmony_ci int count, i, ret; 29948c2ecf20Sopenharmony_ci struct regulator *regulator; 29958c2ecf20Sopenharmony_ci int total_count = 0; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci regulator_lock_dependent(rdev, &ww_ctx); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci /* 30008c2ecf20Sopenharmony_ci * Workqueue functions queue the new work instance while the previous 30018c2ecf20Sopenharmony_ci * work instance is being processed. Cancel the queued work instance 30028c2ecf20Sopenharmony_ci * as the work instance under processing does the job of the queued 30038c2ecf20Sopenharmony_ci * work instance. 30048c2ecf20Sopenharmony_ci */ 30058c2ecf20Sopenharmony_ci cancel_delayed_work(&rdev->disable_work); 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 30088c2ecf20Sopenharmony_ci count = regulator->deferred_disables; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci if (!count) 30118c2ecf20Sopenharmony_ci continue; 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci total_count += count; 30148c2ecf20Sopenharmony_ci regulator->deferred_disables = 0; 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 30178c2ecf20Sopenharmony_ci ret = _regulator_disable(regulator); 30188c2ecf20Sopenharmony_ci if (ret != 0) 30198c2ecf20Sopenharmony_ci rdev_err(rdev, "Deferred disable failed: %pe\n", 30208c2ecf20Sopenharmony_ci ERR_PTR(ret)); 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci } 30238c2ecf20Sopenharmony_ci WARN_ON(!total_count); 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 1) 30268c2ecf20Sopenharmony_ci regulator_balance_voltage(rdev, PM_SUSPEND_ON); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci regulator_unlock_dependent(rdev, &ww_ctx); 30298c2ecf20Sopenharmony_ci} 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci/** 30328c2ecf20Sopenharmony_ci * regulator_disable_deferred - disable regulator output with delay 30338c2ecf20Sopenharmony_ci * @regulator: regulator source 30348c2ecf20Sopenharmony_ci * @ms: milliseconds until the regulator is disabled 30358c2ecf20Sopenharmony_ci * 30368c2ecf20Sopenharmony_ci * Execute regulator_disable() on the regulator after a delay. This 30378c2ecf20Sopenharmony_ci * is intended for use with devices that require some time to quiesce. 30388c2ecf20Sopenharmony_ci * 30398c2ecf20Sopenharmony_ci * NOTE: this will only disable the regulator output if no other consumer 30408c2ecf20Sopenharmony_ci * devices have it enabled, the regulator device supports disabling and 30418c2ecf20Sopenharmony_ci * machine constraints permit this operation. 30428c2ecf20Sopenharmony_ci */ 30438c2ecf20Sopenharmony_ciint regulator_disable_deferred(struct regulator *regulator, int ms) 30448c2ecf20Sopenharmony_ci{ 30458c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci if (!ms) 30488c2ecf20Sopenharmony_ci return regulator_disable(regulator); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci regulator_lock(rdev); 30518c2ecf20Sopenharmony_ci regulator->deferred_disables++; 30528c2ecf20Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, &rdev->disable_work, 30538c2ecf20Sopenharmony_ci msecs_to_jiffies(ms)); 30548c2ecf20Sopenharmony_ci regulator_unlock(rdev); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci return 0; 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_disable_deferred); 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_cistatic int _regulator_is_enabled(struct regulator_dev *rdev) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci /* A GPIO control always takes precedence */ 30638c2ecf20Sopenharmony_ci if (rdev->ena_pin) 30648c2ecf20Sopenharmony_ci return rdev->ena_gpio_state; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci /* If we don't know then assume that the regulator is always on */ 30678c2ecf20Sopenharmony_ci if (!rdev->desc->ops->is_enabled) 30688c2ecf20Sopenharmony_ci return 1; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci return rdev->desc->ops->is_enabled(rdev); 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_cistatic int _regulator_list_voltage(struct regulator_dev *rdev, 30748c2ecf20Sopenharmony_ci unsigned selector, int lock) 30758c2ecf20Sopenharmony_ci{ 30768c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 30778c2ecf20Sopenharmony_ci int ret; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci if (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1 && !selector) 30808c2ecf20Sopenharmony_ci return rdev->desc->fixed_uV; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci if (ops->list_voltage) { 30838c2ecf20Sopenharmony_ci if (selector >= rdev->desc->n_voltages) 30848c2ecf20Sopenharmony_ci return -EINVAL; 30858c2ecf20Sopenharmony_ci if (lock) 30868c2ecf20Sopenharmony_ci regulator_lock(rdev); 30878c2ecf20Sopenharmony_ci ret = ops->list_voltage(rdev, selector); 30888c2ecf20Sopenharmony_ci if (lock) 30898c2ecf20Sopenharmony_ci regulator_unlock(rdev); 30908c2ecf20Sopenharmony_ci } else if (rdev->is_switch && rdev->supply) { 30918c2ecf20Sopenharmony_ci ret = _regulator_list_voltage(rdev->supply->rdev, 30928c2ecf20Sopenharmony_ci selector, lock); 30938c2ecf20Sopenharmony_ci } else { 30948c2ecf20Sopenharmony_ci return -EINVAL; 30958c2ecf20Sopenharmony_ci } 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_ci if (ret > 0) { 30988c2ecf20Sopenharmony_ci if (ret < rdev->constraints->min_uV) 30998c2ecf20Sopenharmony_ci ret = 0; 31008c2ecf20Sopenharmony_ci else if (ret > rdev->constraints->max_uV) 31018c2ecf20Sopenharmony_ci ret = 0; 31028c2ecf20Sopenharmony_ci } 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci return ret; 31058c2ecf20Sopenharmony_ci} 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci/** 31088c2ecf20Sopenharmony_ci * regulator_is_enabled - is the regulator output enabled 31098c2ecf20Sopenharmony_ci * @regulator: regulator source 31108c2ecf20Sopenharmony_ci * 31118c2ecf20Sopenharmony_ci * Returns positive if the regulator driver backing the source/client 31128c2ecf20Sopenharmony_ci * has requested that the device be enabled, zero if it hasn't, else a 31138c2ecf20Sopenharmony_ci * negative errno code. 31148c2ecf20Sopenharmony_ci * 31158c2ecf20Sopenharmony_ci * Note that the device backing this regulator handle can have multiple 31168c2ecf20Sopenharmony_ci * users, so it might be enabled even if regulator_enable() was never 31178c2ecf20Sopenharmony_ci * called for this particular source. 31188c2ecf20Sopenharmony_ci */ 31198c2ecf20Sopenharmony_ciint regulator_is_enabled(struct regulator *regulator) 31208c2ecf20Sopenharmony_ci{ 31218c2ecf20Sopenharmony_ci int ret; 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci if (regulator->always_on) 31248c2ecf20Sopenharmony_ci return 1; 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci regulator_lock(regulator->rdev); 31278c2ecf20Sopenharmony_ci ret = _regulator_is_enabled(regulator->rdev); 31288c2ecf20Sopenharmony_ci regulator_unlock(regulator->rdev); 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci return ret; 31318c2ecf20Sopenharmony_ci} 31328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_is_enabled); 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci/** 31358c2ecf20Sopenharmony_ci * regulator_count_voltages - count regulator_list_voltage() selectors 31368c2ecf20Sopenharmony_ci * @regulator: regulator source 31378c2ecf20Sopenharmony_ci * 31388c2ecf20Sopenharmony_ci * Returns number of selectors, or negative errno. Selectors are 31398c2ecf20Sopenharmony_ci * numbered starting at zero, and typically correspond to bitfields 31408c2ecf20Sopenharmony_ci * in hardware registers. 31418c2ecf20Sopenharmony_ci */ 31428c2ecf20Sopenharmony_ciint regulator_count_voltages(struct regulator *regulator) 31438c2ecf20Sopenharmony_ci{ 31448c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci if (rdev->desc->n_voltages) 31478c2ecf20Sopenharmony_ci return rdev->desc->n_voltages; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci if (!rdev->is_switch || !rdev->supply) 31508c2ecf20Sopenharmony_ci return -EINVAL; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci return regulator_count_voltages(rdev->supply); 31538c2ecf20Sopenharmony_ci} 31548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_count_voltages); 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci/** 31578c2ecf20Sopenharmony_ci * regulator_list_voltage - enumerate supported voltages 31588c2ecf20Sopenharmony_ci * @regulator: regulator source 31598c2ecf20Sopenharmony_ci * @selector: identify voltage to list 31608c2ecf20Sopenharmony_ci * Context: can sleep 31618c2ecf20Sopenharmony_ci * 31628c2ecf20Sopenharmony_ci * Returns a voltage that can be passed to @regulator_set_voltage(), 31638c2ecf20Sopenharmony_ci * zero if this selector code can't be used on this system, or a 31648c2ecf20Sopenharmony_ci * negative errno. 31658c2ecf20Sopenharmony_ci */ 31668c2ecf20Sopenharmony_ciint regulator_list_voltage(struct regulator *regulator, unsigned selector) 31678c2ecf20Sopenharmony_ci{ 31688c2ecf20Sopenharmony_ci return _regulator_list_voltage(regulator->rdev, selector, 1); 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_list_voltage); 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci/** 31738c2ecf20Sopenharmony_ci * regulator_get_regmap - get the regulator's register map 31748c2ecf20Sopenharmony_ci * @regulator: regulator source 31758c2ecf20Sopenharmony_ci * 31768c2ecf20Sopenharmony_ci * Returns the register map for the given regulator, or an ERR_PTR value 31778c2ecf20Sopenharmony_ci * if the regulator doesn't use regmap. 31788c2ecf20Sopenharmony_ci */ 31798c2ecf20Sopenharmony_cistruct regmap *regulator_get_regmap(struct regulator *regulator) 31808c2ecf20Sopenharmony_ci{ 31818c2ecf20Sopenharmony_ci struct regmap *map = regulator->rdev->regmap; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci return map ? map : ERR_PTR(-EOPNOTSUPP); 31848c2ecf20Sopenharmony_ci} 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci/** 31878c2ecf20Sopenharmony_ci * regulator_get_hardware_vsel_register - get the HW voltage selector register 31888c2ecf20Sopenharmony_ci * @regulator: regulator source 31898c2ecf20Sopenharmony_ci * @vsel_reg: voltage selector register, output parameter 31908c2ecf20Sopenharmony_ci * @vsel_mask: mask for voltage selector bitfield, output parameter 31918c2ecf20Sopenharmony_ci * 31928c2ecf20Sopenharmony_ci * Returns the hardware register offset and bitmask used for setting the 31938c2ecf20Sopenharmony_ci * regulator voltage. This might be useful when configuring voltage-scaling 31948c2ecf20Sopenharmony_ci * hardware or firmware that can make I2C requests behind the kernel's back, 31958c2ecf20Sopenharmony_ci * for example. 31968c2ecf20Sopenharmony_ci * 31978c2ecf20Sopenharmony_ci * On success, the output parameters @vsel_reg and @vsel_mask are filled in 31988c2ecf20Sopenharmony_ci * and 0 is returned, otherwise a negative errno is returned. 31998c2ecf20Sopenharmony_ci */ 32008c2ecf20Sopenharmony_ciint regulator_get_hardware_vsel_register(struct regulator *regulator, 32018c2ecf20Sopenharmony_ci unsigned *vsel_reg, 32028c2ecf20Sopenharmony_ci unsigned *vsel_mask) 32038c2ecf20Sopenharmony_ci{ 32048c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 32058c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 32088c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci *vsel_reg = rdev->desc->vsel_reg; 32118c2ecf20Sopenharmony_ci *vsel_mask = rdev->desc->vsel_mask; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci return 0; 32148c2ecf20Sopenharmony_ci} 32158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_hardware_vsel_register); 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci/** 32188c2ecf20Sopenharmony_ci * regulator_list_hardware_vsel - get the HW-specific register value for a selector 32198c2ecf20Sopenharmony_ci * @regulator: regulator source 32208c2ecf20Sopenharmony_ci * @selector: identify voltage to list 32218c2ecf20Sopenharmony_ci * 32228c2ecf20Sopenharmony_ci * Converts the selector to a hardware-specific voltage selector that can be 32238c2ecf20Sopenharmony_ci * directly written to the regulator registers. The address of the voltage 32248c2ecf20Sopenharmony_ci * register can be determined by calling @regulator_get_hardware_vsel_register. 32258c2ecf20Sopenharmony_ci * 32268c2ecf20Sopenharmony_ci * On error a negative errno is returned. 32278c2ecf20Sopenharmony_ci */ 32288c2ecf20Sopenharmony_ciint regulator_list_hardware_vsel(struct regulator *regulator, 32298c2ecf20Sopenharmony_ci unsigned selector) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 32328c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci if (selector >= rdev->desc->n_voltages) 32358c2ecf20Sopenharmony_ci return -EINVAL; 32368c2ecf20Sopenharmony_ci if (ops->set_voltage_sel != regulator_set_voltage_sel_regmap) 32378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci return selector; 32408c2ecf20Sopenharmony_ci} 32418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_list_hardware_vsel); 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci/** 32448c2ecf20Sopenharmony_ci * regulator_get_linear_step - return the voltage step size between VSEL values 32458c2ecf20Sopenharmony_ci * @regulator: regulator source 32468c2ecf20Sopenharmony_ci * 32478c2ecf20Sopenharmony_ci * Returns the voltage step size between VSEL values for linear 32488c2ecf20Sopenharmony_ci * regulators, or return 0 if the regulator isn't a linear regulator. 32498c2ecf20Sopenharmony_ci */ 32508c2ecf20Sopenharmony_ciunsigned int regulator_get_linear_step(struct regulator *regulator) 32518c2ecf20Sopenharmony_ci{ 32528c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci return rdev->desc->uV_step; 32558c2ecf20Sopenharmony_ci} 32568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_linear_step); 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci/** 32598c2ecf20Sopenharmony_ci * regulator_is_supported_voltage - check if a voltage range can be supported 32608c2ecf20Sopenharmony_ci * 32618c2ecf20Sopenharmony_ci * @regulator: Regulator to check. 32628c2ecf20Sopenharmony_ci * @min_uV: Minimum required voltage in uV. 32638c2ecf20Sopenharmony_ci * @max_uV: Maximum required voltage in uV. 32648c2ecf20Sopenharmony_ci * 32658c2ecf20Sopenharmony_ci * Returns a boolean. 32668c2ecf20Sopenharmony_ci */ 32678c2ecf20Sopenharmony_ciint regulator_is_supported_voltage(struct regulator *regulator, 32688c2ecf20Sopenharmony_ci int min_uV, int max_uV) 32698c2ecf20Sopenharmony_ci{ 32708c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 32718c2ecf20Sopenharmony_ci int i, voltages, ret; 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci /* If we can't change voltage check the current voltage */ 32748c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 32758c2ecf20Sopenharmony_ci ret = regulator_get_voltage(regulator); 32768c2ecf20Sopenharmony_ci if (ret >= 0) 32778c2ecf20Sopenharmony_ci return min_uV <= ret && ret <= max_uV; 32788c2ecf20Sopenharmony_ci else 32798c2ecf20Sopenharmony_ci return ret; 32808c2ecf20Sopenharmony_ci } 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci /* Any voltage within constrains range is fine? */ 32838c2ecf20Sopenharmony_ci if (rdev->desc->continuous_voltage_range) 32848c2ecf20Sopenharmony_ci return min_uV >= rdev->constraints->min_uV && 32858c2ecf20Sopenharmony_ci max_uV <= rdev->constraints->max_uV; 32868c2ecf20Sopenharmony_ci 32878c2ecf20Sopenharmony_ci ret = regulator_count_voltages(regulator); 32888c2ecf20Sopenharmony_ci if (ret < 0) 32898c2ecf20Sopenharmony_ci return 0; 32908c2ecf20Sopenharmony_ci voltages = ret; 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci for (i = 0; i < voltages; i++) { 32938c2ecf20Sopenharmony_ci ret = regulator_list_voltage(regulator, i); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci if (ret >= min_uV && ret <= max_uV) 32968c2ecf20Sopenharmony_ci return 1; 32978c2ecf20Sopenharmony_ci } 32988c2ecf20Sopenharmony_ci 32998c2ecf20Sopenharmony_ci return 0; 33008c2ecf20Sopenharmony_ci} 33018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_is_supported_voltage); 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_cistatic int regulator_map_voltage(struct regulator_dev *rdev, int min_uV, 33048c2ecf20Sopenharmony_ci int max_uV) 33058c2ecf20Sopenharmony_ci{ 33068c2ecf20Sopenharmony_ci const struct regulator_desc *desc = rdev->desc; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci if (desc->ops->map_voltage) 33098c2ecf20Sopenharmony_ci return desc->ops->map_voltage(rdev, min_uV, max_uV); 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci if (desc->ops->list_voltage == regulator_list_voltage_linear) 33128c2ecf20Sopenharmony_ci return regulator_map_voltage_linear(rdev, min_uV, max_uV); 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci if (desc->ops->list_voltage == regulator_list_voltage_linear_range) 33158c2ecf20Sopenharmony_ci return regulator_map_voltage_linear_range(rdev, min_uV, max_uV); 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (desc->ops->list_voltage == 33188c2ecf20Sopenharmony_ci regulator_list_voltage_pickable_linear_range) 33198c2ecf20Sopenharmony_ci return regulator_map_voltage_pickable_linear_range(rdev, 33208c2ecf20Sopenharmony_ci min_uV, max_uV); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci return regulator_map_voltage_iterate(rdev, min_uV, max_uV); 33238c2ecf20Sopenharmony_ci} 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_cistatic int _regulator_call_set_voltage(struct regulator_dev *rdev, 33268c2ecf20Sopenharmony_ci int min_uV, int max_uV, 33278c2ecf20Sopenharmony_ci unsigned *selector) 33288c2ecf20Sopenharmony_ci{ 33298c2ecf20Sopenharmony_ci struct pre_voltage_change_data data; 33308c2ecf20Sopenharmony_ci int ret; 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci data.old_uV = regulator_get_voltage_rdev(rdev); 33338c2ecf20Sopenharmony_ci data.min_uV = min_uV; 33348c2ecf20Sopenharmony_ci data.max_uV = max_uV; 33358c2ecf20Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 33368c2ecf20Sopenharmony_ci &data); 33378c2ecf20Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 33388c2ecf20Sopenharmony_ci return -EINVAL; 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, selector); 33418c2ecf20Sopenharmony_ci if (ret >= 0) 33428c2ecf20Sopenharmony_ci return ret; 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 33458c2ecf20Sopenharmony_ci (void *)data.old_uV); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci return ret; 33488c2ecf20Sopenharmony_ci} 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_cistatic int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, 33518c2ecf20Sopenharmony_ci int uV, unsigned selector) 33528c2ecf20Sopenharmony_ci{ 33538c2ecf20Sopenharmony_ci struct pre_voltage_change_data data; 33548c2ecf20Sopenharmony_ci int ret; 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci data.old_uV = regulator_get_voltage_rdev(rdev); 33578c2ecf20Sopenharmony_ci data.min_uV = uV; 33588c2ecf20Sopenharmony_ci data.max_uV = uV; 33598c2ecf20Sopenharmony_ci ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, 33608c2ecf20Sopenharmony_ci &data); 33618c2ecf20Sopenharmony_ci if (ret & NOTIFY_STOP_MASK) 33628c2ecf20Sopenharmony_ci return -EINVAL; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_voltage_sel(rdev, selector); 33658c2ecf20Sopenharmony_ci if (ret >= 0) 33668c2ecf20Sopenharmony_ci return ret; 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE, 33698c2ecf20Sopenharmony_ci (void *)data.old_uV); 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci return ret; 33728c2ecf20Sopenharmony_ci} 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_cistatic int _regulator_set_voltage_sel_step(struct regulator_dev *rdev, 33758c2ecf20Sopenharmony_ci int uV, int new_selector) 33768c2ecf20Sopenharmony_ci{ 33778c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 33788c2ecf20Sopenharmony_ci int diff, old_sel, curr_sel, ret; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci /* Stepping is only needed if the regulator is enabled. */ 33818c2ecf20Sopenharmony_ci if (!_regulator_is_enabled(rdev)) 33828c2ecf20Sopenharmony_ci goto final_set; 33838c2ecf20Sopenharmony_ci 33848c2ecf20Sopenharmony_ci if (!ops->get_voltage_sel) 33858c2ecf20Sopenharmony_ci return -EINVAL; 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_ci old_sel = ops->get_voltage_sel(rdev); 33888c2ecf20Sopenharmony_ci if (old_sel < 0) 33898c2ecf20Sopenharmony_ci return old_sel; 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci diff = new_selector - old_sel; 33928c2ecf20Sopenharmony_ci if (diff == 0) 33938c2ecf20Sopenharmony_ci return 0; /* No change needed. */ 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci if (diff > 0) { 33968c2ecf20Sopenharmony_ci /* Stepping up. */ 33978c2ecf20Sopenharmony_ci for (curr_sel = old_sel + rdev->desc->vsel_step; 33988c2ecf20Sopenharmony_ci curr_sel < new_selector; 33998c2ecf20Sopenharmony_ci curr_sel += rdev->desc->vsel_step) { 34008c2ecf20Sopenharmony_ci /* 34018c2ecf20Sopenharmony_ci * Call the callback directly instead of using 34028c2ecf20Sopenharmony_ci * _regulator_call_set_voltage_sel() as we don't 34038c2ecf20Sopenharmony_ci * want to notify anyone yet. Same in the branch 34048c2ecf20Sopenharmony_ci * below. 34058c2ecf20Sopenharmony_ci */ 34068c2ecf20Sopenharmony_ci ret = ops->set_voltage_sel(rdev, curr_sel); 34078c2ecf20Sopenharmony_ci if (ret) 34088c2ecf20Sopenharmony_ci goto try_revert; 34098c2ecf20Sopenharmony_ci } 34108c2ecf20Sopenharmony_ci } else { 34118c2ecf20Sopenharmony_ci /* Stepping down. */ 34128c2ecf20Sopenharmony_ci for (curr_sel = old_sel - rdev->desc->vsel_step; 34138c2ecf20Sopenharmony_ci curr_sel > new_selector; 34148c2ecf20Sopenharmony_ci curr_sel -= rdev->desc->vsel_step) { 34158c2ecf20Sopenharmony_ci ret = ops->set_voltage_sel(rdev, curr_sel); 34168c2ecf20Sopenharmony_ci if (ret) 34178c2ecf20Sopenharmony_ci goto try_revert; 34188c2ecf20Sopenharmony_ci } 34198c2ecf20Sopenharmony_ci } 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_cifinal_set: 34228c2ecf20Sopenharmony_ci /* The final selector will trigger the notifiers. */ 34238c2ecf20Sopenharmony_ci return _regulator_call_set_voltage_sel(rdev, uV, new_selector); 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_citry_revert: 34268c2ecf20Sopenharmony_ci /* 34278c2ecf20Sopenharmony_ci * At least try to return to the previous voltage if setting a new 34288c2ecf20Sopenharmony_ci * one failed. 34298c2ecf20Sopenharmony_ci */ 34308c2ecf20Sopenharmony_ci (void)ops->set_voltage_sel(rdev, old_sel); 34318c2ecf20Sopenharmony_ci return ret; 34328c2ecf20Sopenharmony_ci} 34338c2ecf20Sopenharmony_ci 34348c2ecf20Sopenharmony_cistatic int _regulator_set_voltage_time(struct regulator_dev *rdev, 34358c2ecf20Sopenharmony_ci int old_uV, int new_uV) 34368c2ecf20Sopenharmony_ci{ 34378c2ecf20Sopenharmony_ci unsigned int ramp_delay = 0; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci if (rdev->constraints->ramp_delay) 34408c2ecf20Sopenharmony_ci ramp_delay = rdev->constraints->ramp_delay; 34418c2ecf20Sopenharmony_ci else if (rdev->desc->ramp_delay) 34428c2ecf20Sopenharmony_ci ramp_delay = rdev->desc->ramp_delay; 34438c2ecf20Sopenharmony_ci else if (rdev->constraints->settling_time) 34448c2ecf20Sopenharmony_ci return rdev->constraints->settling_time; 34458c2ecf20Sopenharmony_ci else if (rdev->constraints->settling_time_up && 34468c2ecf20Sopenharmony_ci (new_uV > old_uV)) 34478c2ecf20Sopenharmony_ci return rdev->constraints->settling_time_up; 34488c2ecf20Sopenharmony_ci else if (rdev->constraints->settling_time_down && 34498c2ecf20Sopenharmony_ci (new_uV < old_uV)) 34508c2ecf20Sopenharmony_ci return rdev->constraints->settling_time_down; 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci if (ramp_delay == 0) { 34538c2ecf20Sopenharmony_ci rdev_dbg(rdev, "ramp_delay not set\n"); 34548c2ecf20Sopenharmony_ci return 0; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci return DIV_ROUND_UP(abs(new_uV - old_uV), ramp_delay); 34588c2ecf20Sopenharmony_ci} 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_cistatic int _regulator_do_set_voltage(struct regulator_dev *rdev, 34618c2ecf20Sopenharmony_ci int min_uV, int max_uV) 34628c2ecf20Sopenharmony_ci{ 34638c2ecf20Sopenharmony_ci int ret; 34648c2ecf20Sopenharmony_ci int delay = 0; 34658c2ecf20Sopenharmony_ci int best_val = 0; 34668c2ecf20Sopenharmony_ci unsigned int selector; 34678c2ecf20Sopenharmony_ci int old_selector = -1; 34688c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 34698c2ecf20Sopenharmony_ci int old_uV = regulator_get_voltage_rdev(rdev); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci min_uV += rdev->constraints->uV_offset; 34748c2ecf20Sopenharmony_ci max_uV += rdev->constraints->uV_offset; 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci /* 34778c2ecf20Sopenharmony_ci * If we can't obtain the old selector there is not enough 34788c2ecf20Sopenharmony_ci * info to call set_voltage_time_sel(). 34798c2ecf20Sopenharmony_ci */ 34808c2ecf20Sopenharmony_ci if (_regulator_is_enabled(rdev) && 34818c2ecf20Sopenharmony_ci ops->set_voltage_time_sel && ops->get_voltage_sel) { 34828c2ecf20Sopenharmony_ci old_selector = ops->get_voltage_sel(rdev); 34838c2ecf20Sopenharmony_ci if (old_selector < 0) 34848c2ecf20Sopenharmony_ci return old_selector; 34858c2ecf20Sopenharmony_ci } 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci if (ops->set_voltage) { 34888c2ecf20Sopenharmony_ci ret = _regulator_call_set_voltage(rdev, min_uV, max_uV, 34898c2ecf20Sopenharmony_ci &selector); 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci if (ret >= 0) { 34928c2ecf20Sopenharmony_ci if (ops->list_voltage) 34938c2ecf20Sopenharmony_ci best_val = ops->list_voltage(rdev, 34948c2ecf20Sopenharmony_ci selector); 34958c2ecf20Sopenharmony_ci else 34968c2ecf20Sopenharmony_ci best_val = regulator_get_voltage_rdev(rdev); 34978c2ecf20Sopenharmony_ci } 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci } else if (ops->set_voltage_sel) { 35008c2ecf20Sopenharmony_ci ret = regulator_map_voltage(rdev, min_uV, max_uV); 35018c2ecf20Sopenharmony_ci if (ret >= 0) { 35028c2ecf20Sopenharmony_ci best_val = ops->list_voltage(rdev, ret); 35038c2ecf20Sopenharmony_ci if (min_uV <= best_val && max_uV >= best_val) { 35048c2ecf20Sopenharmony_ci selector = ret; 35058c2ecf20Sopenharmony_ci if (old_selector == selector) 35068c2ecf20Sopenharmony_ci ret = 0; 35078c2ecf20Sopenharmony_ci else if (rdev->desc->vsel_step) 35088c2ecf20Sopenharmony_ci ret = _regulator_set_voltage_sel_step( 35098c2ecf20Sopenharmony_ci rdev, best_val, selector); 35108c2ecf20Sopenharmony_ci else 35118c2ecf20Sopenharmony_ci ret = _regulator_call_set_voltage_sel( 35128c2ecf20Sopenharmony_ci rdev, best_val, selector); 35138c2ecf20Sopenharmony_ci } else { 35148c2ecf20Sopenharmony_ci ret = -EINVAL; 35158c2ecf20Sopenharmony_ci } 35168c2ecf20Sopenharmony_ci } 35178c2ecf20Sopenharmony_ci } else { 35188c2ecf20Sopenharmony_ci ret = -EINVAL; 35198c2ecf20Sopenharmony_ci } 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (ret) 35228c2ecf20Sopenharmony_ci goto out; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci if (ops->set_voltage_time_sel) { 35258c2ecf20Sopenharmony_ci /* 35268c2ecf20Sopenharmony_ci * Call set_voltage_time_sel if successfully obtained 35278c2ecf20Sopenharmony_ci * old_selector 35288c2ecf20Sopenharmony_ci */ 35298c2ecf20Sopenharmony_ci if (old_selector >= 0 && old_selector != selector) 35308c2ecf20Sopenharmony_ci delay = ops->set_voltage_time_sel(rdev, old_selector, 35318c2ecf20Sopenharmony_ci selector); 35328c2ecf20Sopenharmony_ci } else { 35338c2ecf20Sopenharmony_ci if (old_uV != best_val) { 35348c2ecf20Sopenharmony_ci if (ops->set_voltage_time) 35358c2ecf20Sopenharmony_ci delay = ops->set_voltage_time(rdev, old_uV, 35368c2ecf20Sopenharmony_ci best_val); 35378c2ecf20Sopenharmony_ci else 35388c2ecf20Sopenharmony_ci delay = _regulator_set_voltage_time(rdev, 35398c2ecf20Sopenharmony_ci old_uV, 35408c2ecf20Sopenharmony_ci best_val); 35418c2ecf20Sopenharmony_ci } 35428c2ecf20Sopenharmony_ci } 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci if (delay < 0) { 35458c2ecf20Sopenharmony_ci rdev_warn(rdev, "failed to get delay: %pe\n", ERR_PTR(delay)); 35468c2ecf20Sopenharmony_ci delay = 0; 35478c2ecf20Sopenharmony_ci } 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci /* Insert any necessary delays */ 35508c2ecf20Sopenharmony_ci if (delay >= 1000) { 35518c2ecf20Sopenharmony_ci mdelay(delay / 1000); 35528c2ecf20Sopenharmony_ci udelay(delay % 1000); 35538c2ecf20Sopenharmony_ci } else if (delay) { 35548c2ecf20Sopenharmony_ci udelay(delay); 35558c2ecf20Sopenharmony_ci } 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci if (best_val >= 0) { 35588c2ecf20Sopenharmony_ci unsigned long data = best_val; 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, 35618c2ecf20Sopenharmony_ci (void *)data); 35628c2ecf20Sopenharmony_ci } 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_ciout: 35658c2ecf20Sopenharmony_ci trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val); 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci return ret; 35688c2ecf20Sopenharmony_ci} 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_cistatic int _regulator_do_set_suspend_voltage(struct regulator_dev *rdev, 35718c2ecf20Sopenharmony_ci int min_uV, int max_uV, suspend_state_t state) 35728c2ecf20Sopenharmony_ci{ 35738c2ecf20Sopenharmony_ci struct regulator_state *rstate; 35748c2ecf20Sopenharmony_ci int uV, sel; 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 35778c2ecf20Sopenharmony_ci if (rstate == NULL) 35788c2ecf20Sopenharmony_ci return -EINVAL; 35798c2ecf20Sopenharmony_ci 35808c2ecf20Sopenharmony_ci if (min_uV < rstate->min_uV) 35818c2ecf20Sopenharmony_ci min_uV = rstate->min_uV; 35828c2ecf20Sopenharmony_ci if (max_uV > rstate->max_uV) 35838c2ecf20Sopenharmony_ci max_uV = rstate->max_uV; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci sel = regulator_map_voltage(rdev, min_uV, max_uV); 35868c2ecf20Sopenharmony_ci if (sel < 0) 35878c2ecf20Sopenharmony_ci return sel; 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_ci uV = rdev->desc->ops->list_voltage(rdev, sel); 35908c2ecf20Sopenharmony_ci if (uV >= min_uV && uV <= max_uV) 35918c2ecf20Sopenharmony_ci rstate->uV = uV; 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci return 0; 35948c2ecf20Sopenharmony_ci} 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_cistatic int regulator_set_voltage_unlocked(struct regulator *regulator, 35978c2ecf20Sopenharmony_ci int min_uV, int max_uV, 35988c2ecf20Sopenharmony_ci suspend_state_t state) 35998c2ecf20Sopenharmony_ci{ 36008c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 36018c2ecf20Sopenharmony_ci struct regulator_voltage *voltage = ®ulator->voltage[state]; 36028c2ecf20Sopenharmony_ci int ret = 0; 36038c2ecf20Sopenharmony_ci int old_min_uV, old_max_uV; 36048c2ecf20Sopenharmony_ci int current_uV; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci /* If we're setting the same range as last time the change 36078c2ecf20Sopenharmony_ci * should be a noop (some cpufreq implementations use the same 36088c2ecf20Sopenharmony_ci * voltage for multiple frequencies, for example). 36098c2ecf20Sopenharmony_ci */ 36108c2ecf20Sopenharmony_ci if (voltage->min_uV == min_uV && voltage->max_uV == max_uV) 36118c2ecf20Sopenharmony_ci goto out; 36128c2ecf20Sopenharmony_ci 36138c2ecf20Sopenharmony_ci /* If we're trying to set a range that overlaps the current voltage, 36148c2ecf20Sopenharmony_ci * return successfully even though the regulator does not support 36158c2ecf20Sopenharmony_ci * changing the voltage. 36168c2ecf20Sopenharmony_ci */ 36178c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { 36188c2ecf20Sopenharmony_ci current_uV = regulator_get_voltage_rdev(rdev); 36198c2ecf20Sopenharmony_ci if (min_uV <= current_uV && current_uV <= max_uV) { 36208c2ecf20Sopenharmony_ci voltage->min_uV = min_uV; 36218c2ecf20Sopenharmony_ci voltage->max_uV = max_uV; 36228c2ecf20Sopenharmony_ci goto out; 36238c2ecf20Sopenharmony_ci } 36248c2ecf20Sopenharmony_ci } 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci /* sanity check */ 36278c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_voltage && 36288c2ecf20Sopenharmony_ci !rdev->desc->ops->set_voltage_sel) { 36298c2ecf20Sopenharmony_ci ret = -EINVAL; 36308c2ecf20Sopenharmony_ci goto out; 36318c2ecf20Sopenharmony_ci } 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci /* constraints check */ 36348c2ecf20Sopenharmony_ci ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 36358c2ecf20Sopenharmony_ci if (ret < 0) 36368c2ecf20Sopenharmony_ci goto out; 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci /* restore original values in case of error */ 36398c2ecf20Sopenharmony_ci old_min_uV = voltage->min_uV; 36408c2ecf20Sopenharmony_ci old_max_uV = voltage->max_uV; 36418c2ecf20Sopenharmony_ci voltage->min_uV = min_uV; 36428c2ecf20Sopenharmony_ci voltage->max_uV = max_uV; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci /* for not coupled regulators this will just set the voltage */ 36458c2ecf20Sopenharmony_ci ret = regulator_balance_voltage(rdev, state); 36468c2ecf20Sopenharmony_ci if (ret < 0) { 36478c2ecf20Sopenharmony_ci voltage->min_uV = old_min_uV; 36488c2ecf20Sopenharmony_ci voltage->max_uV = old_max_uV; 36498c2ecf20Sopenharmony_ci } 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ciout: 36528c2ecf20Sopenharmony_ci return ret; 36538c2ecf20Sopenharmony_ci} 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ciint regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, 36568c2ecf20Sopenharmony_ci int max_uV, suspend_state_t state) 36578c2ecf20Sopenharmony_ci{ 36588c2ecf20Sopenharmony_ci int best_supply_uV = 0; 36598c2ecf20Sopenharmony_ci int supply_change_uV = 0; 36608c2ecf20Sopenharmony_ci int ret; 36618c2ecf20Sopenharmony_ci 36628c2ecf20Sopenharmony_ci if (rdev->supply && 36638c2ecf20Sopenharmony_ci regulator_ops_is_valid(rdev->supply->rdev, 36648c2ecf20Sopenharmony_ci REGULATOR_CHANGE_VOLTAGE) && 36658c2ecf20Sopenharmony_ci (rdev->desc->min_dropout_uV || !(rdev->desc->ops->get_voltage || 36668c2ecf20Sopenharmony_ci rdev->desc->ops->get_voltage_sel))) { 36678c2ecf20Sopenharmony_ci int current_supply_uV; 36688c2ecf20Sopenharmony_ci int selector; 36698c2ecf20Sopenharmony_ci 36708c2ecf20Sopenharmony_ci selector = regulator_map_voltage(rdev, min_uV, max_uV); 36718c2ecf20Sopenharmony_ci if (selector < 0) { 36728c2ecf20Sopenharmony_ci ret = selector; 36738c2ecf20Sopenharmony_ci goto out; 36748c2ecf20Sopenharmony_ci } 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci best_supply_uV = _regulator_list_voltage(rdev, selector, 0); 36778c2ecf20Sopenharmony_ci if (best_supply_uV < 0) { 36788c2ecf20Sopenharmony_ci ret = best_supply_uV; 36798c2ecf20Sopenharmony_ci goto out; 36808c2ecf20Sopenharmony_ci } 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_ci best_supply_uV += rdev->desc->min_dropout_uV; 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); 36858c2ecf20Sopenharmony_ci if (current_supply_uV < 0) { 36868c2ecf20Sopenharmony_ci ret = current_supply_uV; 36878c2ecf20Sopenharmony_ci goto out; 36888c2ecf20Sopenharmony_ci } 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_ci supply_change_uV = best_supply_uV - current_supply_uV; 36918c2ecf20Sopenharmony_ci } 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci if (supply_change_uV > 0) { 36948c2ecf20Sopenharmony_ci ret = regulator_set_voltage_unlocked(rdev->supply, 36958c2ecf20Sopenharmony_ci best_supply_uV, INT_MAX, state); 36968c2ecf20Sopenharmony_ci if (ret) { 36978c2ecf20Sopenharmony_ci dev_err(&rdev->dev, "Failed to increase supply voltage: %pe\n", 36988c2ecf20Sopenharmony_ci ERR_PTR(ret)); 36998c2ecf20Sopenharmony_ci goto out; 37008c2ecf20Sopenharmony_ci } 37018c2ecf20Sopenharmony_ci } 37028c2ecf20Sopenharmony_ci 37038c2ecf20Sopenharmony_ci if (state == PM_SUSPEND_ON) 37048c2ecf20Sopenharmony_ci ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 37058c2ecf20Sopenharmony_ci else 37068c2ecf20Sopenharmony_ci ret = _regulator_do_set_suspend_voltage(rdev, min_uV, 37078c2ecf20Sopenharmony_ci max_uV, state); 37088c2ecf20Sopenharmony_ci if (ret < 0) 37098c2ecf20Sopenharmony_ci goto out; 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci if (supply_change_uV < 0) { 37128c2ecf20Sopenharmony_ci ret = regulator_set_voltage_unlocked(rdev->supply, 37138c2ecf20Sopenharmony_ci best_supply_uV, INT_MAX, state); 37148c2ecf20Sopenharmony_ci if (ret) 37158c2ecf20Sopenharmony_ci dev_warn(&rdev->dev, "Failed to decrease supply voltage: %pe\n", 37168c2ecf20Sopenharmony_ci ERR_PTR(ret)); 37178c2ecf20Sopenharmony_ci /* No need to fail here */ 37188c2ecf20Sopenharmony_ci ret = 0; 37198c2ecf20Sopenharmony_ci } 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ciout: 37228c2ecf20Sopenharmony_ci return ret; 37238c2ecf20Sopenharmony_ci} 37248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_rdev); 37258c2ecf20Sopenharmony_ci 37268c2ecf20Sopenharmony_cistatic int regulator_limit_voltage_step(struct regulator_dev *rdev, 37278c2ecf20Sopenharmony_ci int *current_uV, int *min_uV) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci /* Limit voltage change only if necessary */ 37328c2ecf20Sopenharmony_ci if (!constraints->max_uV_step || !_regulator_is_enabled(rdev)) 37338c2ecf20Sopenharmony_ci return 1; 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci if (*current_uV < 0) { 37368c2ecf20Sopenharmony_ci *current_uV = regulator_get_voltage_rdev(rdev); 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci if (*current_uV < 0) 37398c2ecf20Sopenharmony_ci return *current_uV; 37408c2ecf20Sopenharmony_ci } 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_ci if (abs(*current_uV - *min_uV) <= constraints->max_uV_step) 37438c2ecf20Sopenharmony_ci return 1; 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci /* Clamp target voltage within the given step */ 37468c2ecf20Sopenharmony_ci if (*current_uV < *min_uV) 37478c2ecf20Sopenharmony_ci *min_uV = min(*current_uV + constraints->max_uV_step, 37488c2ecf20Sopenharmony_ci *min_uV); 37498c2ecf20Sopenharmony_ci else 37508c2ecf20Sopenharmony_ci *min_uV = max(*current_uV - constraints->max_uV_step, 37518c2ecf20Sopenharmony_ci *min_uV); 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci return 0; 37548c2ecf20Sopenharmony_ci} 37558c2ecf20Sopenharmony_ci 37568c2ecf20Sopenharmony_cistatic int regulator_get_optimal_voltage(struct regulator_dev *rdev, 37578c2ecf20Sopenharmony_ci int *current_uV, 37588c2ecf20Sopenharmony_ci int *min_uV, int *max_uV, 37598c2ecf20Sopenharmony_ci suspend_state_t state, 37608c2ecf20Sopenharmony_ci int n_coupled) 37618c2ecf20Sopenharmony_ci{ 37628c2ecf20Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 37638c2ecf20Sopenharmony_ci struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; 37648c2ecf20Sopenharmony_ci struct regulation_constraints *constraints = rdev->constraints; 37658c2ecf20Sopenharmony_ci int desired_min_uV = 0, desired_max_uV = INT_MAX; 37668c2ecf20Sopenharmony_ci int max_current_uV = 0, min_current_uV = INT_MAX; 37678c2ecf20Sopenharmony_ci int highest_min_uV = 0, target_uV, possible_uV; 37688c2ecf20Sopenharmony_ci int i, ret, max_spread; 37698c2ecf20Sopenharmony_ci bool done; 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci *current_uV = -1; 37728c2ecf20Sopenharmony_ci 37738c2ecf20Sopenharmony_ci /* 37748c2ecf20Sopenharmony_ci * If there are no coupled regulators, simply set the voltage 37758c2ecf20Sopenharmony_ci * demanded by consumers. 37768c2ecf20Sopenharmony_ci */ 37778c2ecf20Sopenharmony_ci if (n_coupled == 1) { 37788c2ecf20Sopenharmony_ci /* 37798c2ecf20Sopenharmony_ci * If consumers don't provide any demands, set voltage 37808c2ecf20Sopenharmony_ci * to min_uV 37818c2ecf20Sopenharmony_ci */ 37828c2ecf20Sopenharmony_ci desired_min_uV = constraints->min_uV; 37838c2ecf20Sopenharmony_ci desired_max_uV = constraints->max_uV; 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci ret = regulator_check_consumers(rdev, 37868c2ecf20Sopenharmony_ci &desired_min_uV, 37878c2ecf20Sopenharmony_ci &desired_max_uV, state); 37888c2ecf20Sopenharmony_ci if (ret < 0) 37898c2ecf20Sopenharmony_ci return ret; 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_ci possible_uV = desired_min_uV; 37928c2ecf20Sopenharmony_ci done = true; 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci goto finish; 37958c2ecf20Sopenharmony_ci } 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_ci /* Find highest min desired voltage */ 37988c2ecf20Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 37998c2ecf20Sopenharmony_ci int tmp_min = 0; 38008c2ecf20Sopenharmony_ci int tmp_max = INT_MAX; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci lockdep_assert_held_once(&c_rdevs[i]->mutex.base); 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci ret = regulator_check_consumers(c_rdevs[i], 38058c2ecf20Sopenharmony_ci &tmp_min, 38068c2ecf20Sopenharmony_ci &tmp_max, state); 38078c2ecf20Sopenharmony_ci if (ret < 0) 38088c2ecf20Sopenharmony_ci return ret; 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max); 38118c2ecf20Sopenharmony_ci if (ret < 0) 38128c2ecf20Sopenharmony_ci return ret; 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci highest_min_uV = max(highest_min_uV, tmp_min); 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci if (i == 0) { 38178c2ecf20Sopenharmony_ci desired_min_uV = tmp_min; 38188c2ecf20Sopenharmony_ci desired_max_uV = tmp_max; 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci } 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_ci max_spread = constraints->max_spread[0]; 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci /* 38258c2ecf20Sopenharmony_ci * Let target_uV be equal to the desired one if possible. 38268c2ecf20Sopenharmony_ci * If not, set it to minimum voltage, allowed by other coupled 38278c2ecf20Sopenharmony_ci * regulators. 38288c2ecf20Sopenharmony_ci */ 38298c2ecf20Sopenharmony_ci target_uV = max(desired_min_uV, highest_min_uV - max_spread); 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci /* 38328c2ecf20Sopenharmony_ci * Find min and max voltages, which currently aren't violating 38338c2ecf20Sopenharmony_ci * max_spread. 38348c2ecf20Sopenharmony_ci */ 38358c2ecf20Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 38368c2ecf20Sopenharmony_ci int tmp_act; 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci if (!_regulator_is_enabled(c_rdevs[i])) 38398c2ecf20Sopenharmony_ci continue; 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); 38428c2ecf20Sopenharmony_ci if (tmp_act < 0) 38438c2ecf20Sopenharmony_ci return tmp_act; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci min_current_uV = min(tmp_act, min_current_uV); 38468c2ecf20Sopenharmony_ci max_current_uV = max(tmp_act, max_current_uV); 38478c2ecf20Sopenharmony_ci } 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci /* There aren't any other regulators enabled */ 38508c2ecf20Sopenharmony_ci if (max_current_uV == 0) { 38518c2ecf20Sopenharmony_ci possible_uV = target_uV; 38528c2ecf20Sopenharmony_ci } else { 38538c2ecf20Sopenharmony_ci /* 38548c2ecf20Sopenharmony_ci * Correct target voltage, so as it currently isn't 38558c2ecf20Sopenharmony_ci * violating max_spread 38568c2ecf20Sopenharmony_ci */ 38578c2ecf20Sopenharmony_ci possible_uV = max(target_uV, max_current_uV - max_spread); 38588c2ecf20Sopenharmony_ci possible_uV = min(possible_uV, min_current_uV + max_spread); 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci if (possible_uV > desired_max_uV) 38628c2ecf20Sopenharmony_ci return -EINVAL; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci done = (possible_uV == target_uV); 38658c2ecf20Sopenharmony_ci desired_min_uV = possible_uV; 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_cifinish: 38688c2ecf20Sopenharmony_ci /* Apply max_uV_step constraint if necessary */ 38698c2ecf20Sopenharmony_ci if (state == PM_SUSPEND_ON) { 38708c2ecf20Sopenharmony_ci ret = regulator_limit_voltage_step(rdev, current_uV, 38718c2ecf20Sopenharmony_ci &desired_min_uV); 38728c2ecf20Sopenharmony_ci if (ret < 0) 38738c2ecf20Sopenharmony_ci return ret; 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_ci if (ret == 0) 38768c2ecf20Sopenharmony_ci done = false; 38778c2ecf20Sopenharmony_ci } 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci /* Set current_uV if wasn't done earlier in the code and if necessary */ 38808c2ecf20Sopenharmony_ci if (n_coupled > 1 && *current_uV == -1) { 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (_regulator_is_enabled(rdev)) { 38838c2ecf20Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev); 38848c2ecf20Sopenharmony_ci if (ret < 0) 38858c2ecf20Sopenharmony_ci return ret; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci *current_uV = ret; 38888c2ecf20Sopenharmony_ci } else { 38898c2ecf20Sopenharmony_ci *current_uV = desired_min_uV; 38908c2ecf20Sopenharmony_ci } 38918c2ecf20Sopenharmony_ci } 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci *min_uV = desired_min_uV; 38948c2ecf20Sopenharmony_ci *max_uV = desired_max_uV; 38958c2ecf20Sopenharmony_ci 38968c2ecf20Sopenharmony_ci return done; 38978c2ecf20Sopenharmony_ci} 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ciint regulator_do_balance_voltage(struct regulator_dev *rdev, 39008c2ecf20Sopenharmony_ci suspend_state_t state, bool skip_coupled) 39018c2ecf20Sopenharmony_ci{ 39028c2ecf20Sopenharmony_ci struct regulator_dev **c_rdevs; 39038c2ecf20Sopenharmony_ci struct regulator_dev *best_rdev; 39048c2ecf20Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 39058c2ecf20Sopenharmony_ci int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; 39068c2ecf20Sopenharmony_ci unsigned int delta, best_delta; 39078c2ecf20Sopenharmony_ci unsigned long c_rdev_done = 0; 39088c2ecf20Sopenharmony_ci bool best_c_rdev_done; 39098c2ecf20Sopenharmony_ci 39108c2ecf20Sopenharmony_ci c_rdevs = c_desc->coupled_rdevs; 39118c2ecf20Sopenharmony_ci n_coupled = skip_coupled ? 1 : c_desc->n_coupled; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci /* 39148c2ecf20Sopenharmony_ci * Find the best possible voltage change on each loop. Leave the loop 39158c2ecf20Sopenharmony_ci * if there isn't any possible change. 39168c2ecf20Sopenharmony_ci */ 39178c2ecf20Sopenharmony_ci do { 39188c2ecf20Sopenharmony_ci best_c_rdev_done = false; 39198c2ecf20Sopenharmony_ci best_delta = 0; 39208c2ecf20Sopenharmony_ci best_min_uV = 0; 39218c2ecf20Sopenharmony_ci best_max_uV = 0; 39228c2ecf20Sopenharmony_ci best_c_rdev = 0; 39238c2ecf20Sopenharmony_ci best_rdev = NULL; 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci /* 39268c2ecf20Sopenharmony_ci * Find highest difference between optimal voltage 39278c2ecf20Sopenharmony_ci * and current voltage. 39288c2ecf20Sopenharmony_ci */ 39298c2ecf20Sopenharmony_ci for (i = 0; i < n_coupled; i++) { 39308c2ecf20Sopenharmony_ci /* 39318c2ecf20Sopenharmony_ci * optimal_uV is the best voltage that can be set for 39328c2ecf20Sopenharmony_ci * i-th regulator at the moment without violating 39338c2ecf20Sopenharmony_ci * max_spread constraint in order to balance 39348c2ecf20Sopenharmony_ci * the coupled voltages. 39358c2ecf20Sopenharmony_ci */ 39368c2ecf20Sopenharmony_ci int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci if (test_bit(i, &c_rdev_done)) 39398c2ecf20Sopenharmony_ci continue; 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci ret = regulator_get_optimal_voltage(c_rdevs[i], 39428c2ecf20Sopenharmony_ci ¤t_uV, 39438c2ecf20Sopenharmony_ci &optimal_uV, 39448c2ecf20Sopenharmony_ci &optimal_max_uV, 39458c2ecf20Sopenharmony_ci state, n_coupled); 39468c2ecf20Sopenharmony_ci if (ret < 0) 39478c2ecf20Sopenharmony_ci goto out; 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci delta = abs(optimal_uV - current_uV); 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci if (delta && best_delta <= delta) { 39528c2ecf20Sopenharmony_ci best_c_rdev_done = ret; 39538c2ecf20Sopenharmony_ci best_delta = delta; 39548c2ecf20Sopenharmony_ci best_rdev = c_rdevs[i]; 39558c2ecf20Sopenharmony_ci best_min_uV = optimal_uV; 39568c2ecf20Sopenharmony_ci best_max_uV = optimal_max_uV; 39578c2ecf20Sopenharmony_ci best_c_rdev = i; 39588c2ecf20Sopenharmony_ci } 39598c2ecf20Sopenharmony_ci } 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci /* Nothing to change, return successfully */ 39628c2ecf20Sopenharmony_ci if (!best_rdev) { 39638c2ecf20Sopenharmony_ci ret = 0; 39648c2ecf20Sopenharmony_ci goto out; 39658c2ecf20Sopenharmony_ci } 39668c2ecf20Sopenharmony_ci 39678c2ecf20Sopenharmony_ci ret = regulator_set_voltage_rdev(best_rdev, best_min_uV, 39688c2ecf20Sopenharmony_ci best_max_uV, state); 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci if (ret < 0) 39718c2ecf20Sopenharmony_ci goto out; 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci if (best_c_rdev_done) 39748c2ecf20Sopenharmony_ci set_bit(best_c_rdev, &c_rdev_done); 39758c2ecf20Sopenharmony_ci 39768c2ecf20Sopenharmony_ci } while (n_coupled > 1); 39778c2ecf20Sopenharmony_ci 39788c2ecf20Sopenharmony_ciout: 39798c2ecf20Sopenharmony_ci return ret; 39808c2ecf20Sopenharmony_ci} 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_cistatic int regulator_balance_voltage(struct regulator_dev *rdev, 39838c2ecf20Sopenharmony_ci suspend_state_t state) 39848c2ecf20Sopenharmony_ci{ 39858c2ecf20Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 39868c2ecf20Sopenharmony_ci struct regulator_coupler *coupler = c_desc->coupler; 39878c2ecf20Sopenharmony_ci bool skip_coupled = false; 39888c2ecf20Sopenharmony_ci 39898c2ecf20Sopenharmony_ci /* 39908c2ecf20Sopenharmony_ci * If system is in a state other than PM_SUSPEND_ON, don't check 39918c2ecf20Sopenharmony_ci * other coupled regulators. 39928c2ecf20Sopenharmony_ci */ 39938c2ecf20Sopenharmony_ci if (state != PM_SUSPEND_ON) 39948c2ecf20Sopenharmony_ci skip_coupled = true; 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci if (c_desc->n_resolved < c_desc->n_coupled) { 39978c2ecf20Sopenharmony_ci rdev_err(rdev, "Not all coupled regulators registered\n"); 39988c2ecf20Sopenharmony_ci return -EPERM; 39998c2ecf20Sopenharmony_ci } 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci /* Invoke custom balancer for customized couplers */ 40028c2ecf20Sopenharmony_ci if (coupler && coupler->balance_voltage) 40038c2ecf20Sopenharmony_ci return coupler->balance_voltage(coupler, rdev, state); 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci return regulator_do_balance_voltage(rdev, state, skip_coupled); 40068c2ecf20Sopenharmony_ci} 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_ci/** 40098c2ecf20Sopenharmony_ci * regulator_set_voltage - set regulator output voltage 40108c2ecf20Sopenharmony_ci * @regulator: regulator source 40118c2ecf20Sopenharmony_ci * @min_uV: Minimum required voltage in uV 40128c2ecf20Sopenharmony_ci * @max_uV: Maximum acceptable voltage in uV 40138c2ecf20Sopenharmony_ci * 40148c2ecf20Sopenharmony_ci * Sets a voltage regulator to the desired output voltage. This can be set 40158c2ecf20Sopenharmony_ci * during any regulator state. IOW, regulator can be disabled or enabled. 40168c2ecf20Sopenharmony_ci * 40178c2ecf20Sopenharmony_ci * If the regulator is enabled then the voltage will change to the new value 40188c2ecf20Sopenharmony_ci * immediately otherwise if the regulator is disabled the regulator will 40198c2ecf20Sopenharmony_ci * output at the new voltage when enabled. 40208c2ecf20Sopenharmony_ci * 40218c2ecf20Sopenharmony_ci * NOTE: If the regulator is shared between several devices then the lowest 40228c2ecf20Sopenharmony_ci * request voltage that meets the system constraints will be used. 40238c2ecf20Sopenharmony_ci * Regulator system constraints must be set for this regulator before 40248c2ecf20Sopenharmony_ci * calling this function otherwise this call will fail. 40258c2ecf20Sopenharmony_ci */ 40268c2ecf20Sopenharmony_ciint regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) 40278c2ecf20Sopenharmony_ci{ 40288c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 40298c2ecf20Sopenharmony_ci int ret; 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV, 40348c2ecf20Sopenharmony_ci PM_SUSPEND_ON); 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_ci return ret; 40398c2ecf20Sopenharmony_ci} 40408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage); 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_cistatic inline int regulator_suspend_toggle(struct regulator_dev *rdev, 40438c2ecf20Sopenharmony_ci suspend_state_t state, bool en) 40448c2ecf20Sopenharmony_ci{ 40458c2ecf20Sopenharmony_ci struct regulator_state *rstate; 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 40488c2ecf20Sopenharmony_ci if (rstate == NULL) 40498c2ecf20Sopenharmony_ci return -EINVAL; 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci if (!rstate->changeable) 40528c2ecf20Sopenharmony_ci return -EPERM; 40538c2ecf20Sopenharmony_ci 40548c2ecf20Sopenharmony_ci rstate->enabled = (en) ? ENABLE_IN_SUSPEND : DISABLE_IN_SUSPEND; 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci return 0; 40578c2ecf20Sopenharmony_ci} 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ciint regulator_suspend_enable(struct regulator_dev *rdev, 40608c2ecf20Sopenharmony_ci suspend_state_t state) 40618c2ecf20Sopenharmony_ci{ 40628c2ecf20Sopenharmony_ci return regulator_suspend_toggle(rdev, state, true); 40638c2ecf20Sopenharmony_ci} 40648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_suspend_enable); 40658c2ecf20Sopenharmony_ci 40668c2ecf20Sopenharmony_ciint regulator_suspend_disable(struct regulator_dev *rdev, 40678c2ecf20Sopenharmony_ci suspend_state_t state) 40688c2ecf20Sopenharmony_ci{ 40698c2ecf20Sopenharmony_ci struct regulator *regulator; 40708c2ecf20Sopenharmony_ci struct regulator_voltage *voltage; 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci /* 40738c2ecf20Sopenharmony_ci * if any consumer wants this regulator device keeping on in 40748c2ecf20Sopenharmony_ci * suspend states, don't set it as disabled. 40758c2ecf20Sopenharmony_ci */ 40768c2ecf20Sopenharmony_ci list_for_each_entry(regulator, &rdev->consumer_list, list) { 40778c2ecf20Sopenharmony_ci voltage = ®ulator->voltage[state]; 40788c2ecf20Sopenharmony_ci if (voltage->min_uV || voltage->max_uV) 40798c2ecf20Sopenharmony_ci return 0; 40808c2ecf20Sopenharmony_ci } 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci return regulator_suspend_toggle(rdev, state, false); 40838c2ecf20Sopenharmony_ci} 40848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_suspend_disable); 40858c2ecf20Sopenharmony_ci 40868c2ecf20Sopenharmony_cistatic int _regulator_set_suspend_voltage(struct regulator *regulator, 40878c2ecf20Sopenharmony_ci int min_uV, int max_uV, 40888c2ecf20Sopenharmony_ci suspend_state_t state) 40898c2ecf20Sopenharmony_ci{ 40908c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 40918c2ecf20Sopenharmony_ci struct regulator_state *rstate; 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 40948c2ecf20Sopenharmony_ci if (rstate == NULL) 40958c2ecf20Sopenharmony_ci return -EINVAL; 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci if (rstate->min_uV == rstate->max_uV) { 40988c2ecf20Sopenharmony_ci rdev_err(rdev, "The suspend voltage can't be changed!\n"); 40998c2ecf20Sopenharmony_ci return -EPERM; 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci return regulator_set_voltage_unlocked(regulator, min_uV, max_uV, state); 41038c2ecf20Sopenharmony_ci} 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_ciint regulator_set_suspend_voltage(struct regulator *regulator, int min_uV, 41068c2ecf20Sopenharmony_ci int max_uV, suspend_state_t state) 41078c2ecf20Sopenharmony_ci{ 41088c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 41098c2ecf20Sopenharmony_ci int ret; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci /* PM_SUSPEND_ON is handled by regulator_set_voltage() */ 41128c2ecf20Sopenharmony_ci if (regulator_check_states(state) || state == PM_SUSPEND_ON) 41138c2ecf20Sopenharmony_ci return -EINVAL; 41148c2ecf20Sopenharmony_ci 41158c2ecf20Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci ret = _regulator_set_suspend_voltage(regulator, min_uV, 41188c2ecf20Sopenharmony_ci max_uV, state); 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 41218c2ecf20Sopenharmony_ci 41228c2ecf20Sopenharmony_ci return ret; 41238c2ecf20Sopenharmony_ci} 41248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_suspend_voltage); 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci/** 41278c2ecf20Sopenharmony_ci * regulator_set_voltage_time - get raise/fall time 41288c2ecf20Sopenharmony_ci * @regulator: regulator source 41298c2ecf20Sopenharmony_ci * @old_uV: starting voltage in microvolts 41308c2ecf20Sopenharmony_ci * @new_uV: target voltage in microvolts 41318c2ecf20Sopenharmony_ci * 41328c2ecf20Sopenharmony_ci * Provided with the starting and ending voltage, this function attempts to 41338c2ecf20Sopenharmony_ci * calculate the time in microseconds required to rise or fall to this new 41348c2ecf20Sopenharmony_ci * voltage. 41358c2ecf20Sopenharmony_ci */ 41368c2ecf20Sopenharmony_ciint regulator_set_voltage_time(struct regulator *regulator, 41378c2ecf20Sopenharmony_ci int old_uV, int new_uV) 41388c2ecf20Sopenharmony_ci{ 41398c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 41408c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 41418c2ecf20Sopenharmony_ci int old_sel = -1; 41428c2ecf20Sopenharmony_ci int new_sel = -1; 41438c2ecf20Sopenharmony_ci int voltage; 41448c2ecf20Sopenharmony_ci int i; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci if (ops->set_voltage_time) 41478c2ecf20Sopenharmony_ci return ops->set_voltage_time(rdev, old_uV, new_uV); 41488c2ecf20Sopenharmony_ci else if (!ops->set_voltage_time_sel) 41498c2ecf20Sopenharmony_ci return _regulator_set_voltage_time(rdev, old_uV, new_uV); 41508c2ecf20Sopenharmony_ci 41518c2ecf20Sopenharmony_ci /* Currently requires operations to do this */ 41528c2ecf20Sopenharmony_ci if (!ops->list_voltage || !rdev->desc->n_voltages) 41538c2ecf20Sopenharmony_ci return -EINVAL; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci for (i = 0; i < rdev->desc->n_voltages; i++) { 41568c2ecf20Sopenharmony_ci /* We only look for exact voltage matches here */ 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci if (old_sel >= 0 && new_sel >= 0) 41598c2ecf20Sopenharmony_ci break; 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci voltage = regulator_list_voltage(regulator, i); 41628c2ecf20Sopenharmony_ci if (voltage < 0) 41638c2ecf20Sopenharmony_ci return -EINVAL; 41648c2ecf20Sopenharmony_ci if (voltage == 0) 41658c2ecf20Sopenharmony_ci continue; 41668c2ecf20Sopenharmony_ci if (voltage == old_uV) 41678c2ecf20Sopenharmony_ci old_sel = i; 41688c2ecf20Sopenharmony_ci if (voltage == new_uV) 41698c2ecf20Sopenharmony_ci new_sel = i; 41708c2ecf20Sopenharmony_ci } 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci if (old_sel < 0 || new_sel < 0) 41738c2ecf20Sopenharmony_ci return -EINVAL; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci return ops->set_voltage_time_sel(rdev, old_sel, new_sel); 41768c2ecf20Sopenharmony_ci} 41778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_time); 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci/** 41808c2ecf20Sopenharmony_ci * regulator_set_voltage_time_sel - get raise/fall time 41818c2ecf20Sopenharmony_ci * @rdev: regulator source device 41828c2ecf20Sopenharmony_ci * @old_selector: selector for starting voltage 41838c2ecf20Sopenharmony_ci * @new_selector: selector for target voltage 41848c2ecf20Sopenharmony_ci * 41858c2ecf20Sopenharmony_ci * Provided with the starting and target voltage selectors, this function 41868c2ecf20Sopenharmony_ci * returns time in microseconds required to rise or fall to this new voltage 41878c2ecf20Sopenharmony_ci * 41888c2ecf20Sopenharmony_ci * Drivers providing ramp_delay in regulation_constraints can use this as their 41898c2ecf20Sopenharmony_ci * set_voltage_time_sel() operation. 41908c2ecf20Sopenharmony_ci */ 41918c2ecf20Sopenharmony_ciint regulator_set_voltage_time_sel(struct regulator_dev *rdev, 41928c2ecf20Sopenharmony_ci unsigned int old_selector, 41938c2ecf20Sopenharmony_ci unsigned int new_selector) 41948c2ecf20Sopenharmony_ci{ 41958c2ecf20Sopenharmony_ci int old_volt, new_volt; 41968c2ecf20Sopenharmony_ci 41978c2ecf20Sopenharmony_ci /* sanity check */ 41988c2ecf20Sopenharmony_ci if (!rdev->desc->ops->list_voltage) 41998c2ecf20Sopenharmony_ci return -EINVAL; 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_ci old_volt = rdev->desc->ops->list_voltage(rdev, old_selector); 42028c2ecf20Sopenharmony_ci new_volt = rdev->desc->ops->list_voltage(rdev, new_selector); 42038c2ecf20Sopenharmony_ci 42048c2ecf20Sopenharmony_ci if (rdev->desc->ops->set_voltage_time) 42058c2ecf20Sopenharmony_ci return rdev->desc->ops->set_voltage_time(rdev, old_volt, 42068c2ecf20Sopenharmony_ci new_volt); 42078c2ecf20Sopenharmony_ci else 42088c2ecf20Sopenharmony_ci return _regulator_set_voltage_time(rdev, old_volt, new_volt); 42098c2ecf20Sopenharmony_ci} 42108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_voltage_time_sel); 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci/** 42138c2ecf20Sopenharmony_ci * regulator_sync_voltage - re-apply last regulator output voltage 42148c2ecf20Sopenharmony_ci * @regulator: regulator source 42158c2ecf20Sopenharmony_ci * 42168c2ecf20Sopenharmony_ci * Re-apply the last configured voltage. This is intended to be used 42178c2ecf20Sopenharmony_ci * where some external control source the consumer is cooperating with 42188c2ecf20Sopenharmony_ci * has caused the configured voltage to change. 42198c2ecf20Sopenharmony_ci */ 42208c2ecf20Sopenharmony_ciint regulator_sync_voltage(struct regulator *regulator) 42218c2ecf20Sopenharmony_ci{ 42228c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 42238c2ecf20Sopenharmony_ci struct regulator_voltage *voltage = ®ulator->voltage[PM_SUSPEND_ON]; 42248c2ecf20Sopenharmony_ci int ret, min_uV, max_uV; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci regulator_lock(rdev); 42278c2ecf20Sopenharmony_ci 42288c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_voltage && 42298c2ecf20Sopenharmony_ci !rdev->desc->ops->set_voltage_sel) { 42308c2ecf20Sopenharmony_ci ret = -EINVAL; 42318c2ecf20Sopenharmony_ci goto out; 42328c2ecf20Sopenharmony_ci } 42338c2ecf20Sopenharmony_ci 42348c2ecf20Sopenharmony_ci /* This is only going to work if we've had a voltage configured. */ 42358c2ecf20Sopenharmony_ci if (!voltage->min_uV && !voltage->max_uV) { 42368c2ecf20Sopenharmony_ci ret = -EINVAL; 42378c2ecf20Sopenharmony_ci goto out; 42388c2ecf20Sopenharmony_ci } 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci min_uV = voltage->min_uV; 42418c2ecf20Sopenharmony_ci max_uV = voltage->max_uV; 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_ci /* This should be a paranoia check... */ 42448c2ecf20Sopenharmony_ci ret = regulator_check_voltage(rdev, &min_uV, &max_uV); 42458c2ecf20Sopenharmony_ci if (ret < 0) 42468c2ecf20Sopenharmony_ci goto out; 42478c2ecf20Sopenharmony_ci 42488c2ecf20Sopenharmony_ci ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0); 42498c2ecf20Sopenharmony_ci if (ret < 0) 42508c2ecf20Sopenharmony_ci goto out; 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ciout: 42558c2ecf20Sopenharmony_ci regulator_unlock(rdev); 42568c2ecf20Sopenharmony_ci return ret; 42578c2ecf20Sopenharmony_ci} 42588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_sync_voltage); 42598c2ecf20Sopenharmony_ci 42608c2ecf20Sopenharmony_ciint regulator_get_voltage_rdev(struct regulator_dev *rdev) 42618c2ecf20Sopenharmony_ci{ 42628c2ecf20Sopenharmony_ci int sel, ret; 42638c2ecf20Sopenharmony_ci bool bypassed; 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci if (rdev->desc->ops->get_bypass) { 42668c2ecf20Sopenharmony_ci ret = rdev->desc->ops->get_bypass(rdev, &bypassed); 42678c2ecf20Sopenharmony_ci if (ret < 0) 42688c2ecf20Sopenharmony_ci return ret; 42698c2ecf20Sopenharmony_ci if (bypassed) { 42708c2ecf20Sopenharmony_ci /* if bypassed the regulator must have a supply */ 42718c2ecf20Sopenharmony_ci if (!rdev->supply) { 42728c2ecf20Sopenharmony_ci rdev_err(rdev, 42738c2ecf20Sopenharmony_ci "bypassed regulator has no supply!\n"); 42748c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 42758c2ecf20Sopenharmony_ci } 42768c2ecf20Sopenharmony_ci 42778c2ecf20Sopenharmony_ci return regulator_get_voltage_rdev(rdev->supply->rdev); 42788c2ecf20Sopenharmony_ci } 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci if (rdev->desc->ops->get_voltage_sel) { 42828c2ecf20Sopenharmony_ci sel = rdev->desc->ops->get_voltage_sel(rdev); 42838c2ecf20Sopenharmony_ci if (sel < 0) 42848c2ecf20Sopenharmony_ci return sel; 42858c2ecf20Sopenharmony_ci ret = rdev->desc->ops->list_voltage(rdev, sel); 42868c2ecf20Sopenharmony_ci } else if (rdev->desc->ops->get_voltage) { 42878c2ecf20Sopenharmony_ci ret = rdev->desc->ops->get_voltage(rdev); 42888c2ecf20Sopenharmony_ci } else if (rdev->desc->ops->list_voltage) { 42898c2ecf20Sopenharmony_ci ret = rdev->desc->ops->list_voltage(rdev, 0); 42908c2ecf20Sopenharmony_ci } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { 42918c2ecf20Sopenharmony_ci ret = rdev->desc->fixed_uV; 42928c2ecf20Sopenharmony_ci } else if (rdev->supply) { 42938c2ecf20Sopenharmony_ci ret = regulator_get_voltage_rdev(rdev->supply->rdev); 42948c2ecf20Sopenharmony_ci } else if (rdev->supply_name) { 42958c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 42968c2ecf20Sopenharmony_ci } else { 42978c2ecf20Sopenharmony_ci return -EINVAL; 42988c2ecf20Sopenharmony_ci } 42998c2ecf20Sopenharmony_ci 43008c2ecf20Sopenharmony_ci if (ret < 0) 43018c2ecf20Sopenharmony_ci return ret; 43028c2ecf20Sopenharmony_ci return ret - rdev->constraints->uV_offset; 43038c2ecf20Sopenharmony_ci} 43048c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_voltage_rdev); 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci/** 43078c2ecf20Sopenharmony_ci * regulator_get_voltage - get regulator output voltage 43088c2ecf20Sopenharmony_ci * @regulator: regulator source 43098c2ecf20Sopenharmony_ci * 43108c2ecf20Sopenharmony_ci * This returns the current regulator voltage in uV. 43118c2ecf20Sopenharmony_ci * 43128c2ecf20Sopenharmony_ci * NOTE: If the regulator is disabled it will return the voltage value. This 43138c2ecf20Sopenharmony_ci * function should not be used to determine regulator state. 43148c2ecf20Sopenharmony_ci */ 43158c2ecf20Sopenharmony_ciint regulator_get_voltage(struct regulator *regulator) 43168c2ecf20Sopenharmony_ci{ 43178c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 43188c2ecf20Sopenharmony_ci int ret; 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci regulator_lock_dependent(regulator->rdev, &ww_ctx); 43218c2ecf20Sopenharmony_ci ret = regulator_get_voltage_rdev(regulator->rdev); 43228c2ecf20Sopenharmony_ci regulator_unlock_dependent(regulator->rdev, &ww_ctx); 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci return ret; 43258c2ecf20Sopenharmony_ci} 43268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_voltage); 43278c2ecf20Sopenharmony_ci 43288c2ecf20Sopenharmony_ci/** 43298c2ecf20Sopenharmony_ci * regulator_set_current_limit - set regulator output current limit 43308c2ecf20Sopenharmony_ci * @regulator: regulator source 43318c2ecf20Sopenharmony_ci * @min_uA: Minimum supported current in uA 43328c2ecf20Sopenharmony_ci * @max_uA: Maximum supported current in uA 43338c2ecf20Sopenharmony_ci * 43348c2ecf20Sopenharmony_ci * Sets current sink to the desired output current. This can be set during 43358c2ecf20Sopenharmony_ci * any regulator state. IOW, regulator can be disabled or enabled. 43368c2ecf20Sopenharmony_ci * 43378c2ecf20Sopenharmony_ci * If the regulator is enabled then the current will change to the new value 43388c2ecf20Sopenharmony_ci * immediately otherwise if the regulator is disabled the regulator will 43398c2ecf20Sopenharmony_ci * output at the new current when enabled. 43408c2ecf20Sopenharmony_ci * 43418c2ecf20Sopenharmony_ci * NOTE: Regulator system constraints must be set for this regulator before 43428c2ecf20Sopenharmony_ci * calling this function otherwise this call will fail. 43438c2ecf20Sopenharmony_ci */ 43448c2ecf20Sopenharmony_ciint regulator_set_current_limit(struct regulator *regulator, 43458c2ecf20Sopenharmony_ci int min_uA, int max_uA) 43468c2ecf20Sopenharmony_ci{ 43478c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 43488c2ecf20Sopenharmony_ci int ret; 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci regulator_lock(rdev); 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci /* sanity check */ 43538c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_current_limit) { 43548c2ecf20Sopenharmony_ci ret = -EINVAL; 43558c2ecf20Sopenharmony_ci goto out; 43568c2ecf20Sopenharmony_ci } 43578c2ecf20Sopenharmony_ci 43588c2ecf20Sopenharmony_ci /* constraints check */ 43598c2ecf20Sopenharmony_ci ret = regulator_check_current_limit(rdev, &min_uA, &max_uA); 43608c2ecf20Sopenharmony_ci if (ret < 0) 43618c2ecf20Sopenharmony_ci goto out; 43628c2ecf20Sopenharmony_ci 43638c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_current_limit(rdev, min_uA, max_uA); 43648c2ecf20Sopenharmony_ciout: 43658c2ecf20Sopenharmony_ci regulator_unlock(rdev); 43668c2ecf20Sopenharmony_ci return ret; 43678c2ecf20Sopenharmony_ci} 43688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_current_limit); 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_cistatic int _regulator_get_current_limit_unlocked(struct regulator_dev *rdev) 43718c2ecf20Sopenharmony_ci{ 43728c2ecf20Sopenharmony_ci /* sanity check */ 43738c2ecf20Sopenharmony_ci if (!rdev->desc->ops->get_current_limit) 43748c2ecf20Sopenharmony_ci return -EINVAL; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci return rdev->desc->ops->get_current_limit(rdev); 43778c2ecf20Sopenharmony_ci} 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_cistatic int _regulator_get_current_limit(struct regulator_dev *rdev) 43808c2ecf20Sopenharmony_ci{ 43818c2ecf20Sopenharmony_ci int ret; 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci regulator_lock(rdev); 43848c2ecf20Sopenharmony_ci ret = _regulator_get_current_limit_unlocked(rdev); 43858c2ecf20Sopenharmony_ci regulator_unlock(rdev); 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci return ret; 43888c2ecf20Sopenharmony_ci} 43898c2ecf20Sopenharmony_ci 43908c2ecf20Sopenharmony_ci/** 43918c2ecf20Sopenharmony_ci * regulator_get_current_limit - get regulator output current 43928c2ecf20Sopenharmony_ci * @regulator: regulator source 43938c2ecf20Sopenharmony_ci * 43948c2ecf20Sopenharmony_ci * This returns the current supplied by the specified current sink in uA. 43958c2ecf20Sopenharmony_ci * 43968c2ecf20Sopenharmony_ci * NOTE: If the regulator is disabled it will return the current value. This 43978c2ecf20Sopenharmony_ci * function should not be used to determine regulator state. 43988c2ecf20Sopenharmony_ci */ 43998c2ecf20Sopenharmony_ciint regulator_get_current_limit(struct regulator *regulator) 44008c2ecf20Sopenharmony_ci{ 44018c2ecf20Sopenharmony_ci return _regulator_get_current_limit(regulator->rdev); 44028c2ecf20Sopenharmony_ci} 44038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_current_limit); 44048c2ecf20Sopenharmony_ci 44058c2ecf20Sopenharmony_ci/** 44068c2ecf20Sopenharmony_ci * regulator_set_mode - set regulator operating mode 44078c2ecf20Sopenharmony_ci * @regulator: regulator source 44088c2ecf20Sopenharmony_ci * @mode: operating mode - one of the REGULATOR_MODE constants 44098c2ecf20Sopenharmony_ci * 44108c2ecf20Sopenharmony_ci * Set regulator operating mode to increase regulator efficiency or improve 44118c2ecf20Sopenharmony_ci * regulation performance. 44128c2ecf20Sopenharmony_ci * 44138c2ecf20Sopenharmony_ci * NOTE: Regulator system constraints must be set for this regulator before 44148c2ecf20Sopenharmony_ci * calling this function otherwise this call will fail. 44158c2ecf20Sopenharmony_ci */ 44168c2ecf20Sopenharmony_ciint regulator_set_mode(struct regulator *regulator, unsigned int mode) 44178c2ecf20Sopenharmony_ci{ 44188c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 44198c2ecf20Sopenharmony_ci int ret; 44208c2ecf20Sopenharmony_ci int regulator_curr_mode; 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci regulator_lock(rdev); 44238c2ecf20Sopenharmony_ci 44248c2ecf20Sopenharmony_ci /* sanity check */ 44258c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_mode) { 44268c2ecf20Sopenharmony_ci ret = -EINVAL; 44278c2ecf20Sopenharmony_ci goto out; 44288c2ecf20Sopenharmony_ci } 44298c2ecf20Sopenharmony_ci 44308c2ecf20Sopenharmony_ci /* return if the same mode is requested */ 44318c2ecf20Sopenharmony_ci if (rdev->desc->ops->get_mode) { 44328c2ecf20Sopenharmony_ci regulator_curr_mode = rdev->desc->ops->get_mode(rdev); 44338c2ecf20Sopenharmony_ci if (regulator_curr_mode == mode) { 44348c2ecf20Sopenharmony_ci ret = 0; 44358c2ecf20Sopenharmony_ci goto out; 44368c2ecf20Sopenharmony_ci } 44378c2ecf20Sopenharmony_ci } 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ci /* constraints check */ 44408c2ecf20Sopenharmony_ci ret = regulator_mode_constrain(rdev, &mode); 44418c2ecf20Sopenharmony_ci if (ret < 0) 44428c2ecf20Sopenharmony_ci goto out; 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_mode(rdev, mode); 44458c2ecf20Sopenharmony_ciout: 44468c2ecf20Sopenharmony_ci regulator_unlock(rdev); 44478c2ecf20Sopenharmony_ci return ret; 44488c2ecf20Sopenharmony_ci} 44498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_mode); 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_cistatic unsigned int _regulator_get_mode_unlocked(struct regulator_dev *rdev) 44528c2ecf20Sopenharmony_ci{ 44538c2ecf20Sopenharmony_ci /* sanity check */ 44548c2ecf20Sopenharmony_ci if (!rdev->desc->ops->get_mode) 44558c2ecf20Sopenharmony_ci return -EINVAL; 44568c2ecf20Sopenharmony_ci 44578c2ecf20Sopenharmony_ci return rdev->desc->ops->get_mode(rdev); 44588c2ecf20Sopenharmony_ci} 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_cistatic unsigned int _regulator_get_mode(struct regulator_dev *rdev) 44618c2ecf20Sopenharmony_ci{ 44628c2ecf20Sopenharmony_ci int ret; 44638c2ecf20Sopenharmony_ci 44648c2ecf20Sopenharmony_ci regulator_lock(rdev); 44658c2ecf20Sopenharmony_ci ret = _regulator_get_mode_unlocked(rdev); 44668c2ecf20Sopenharmony_ci regulator_unlock(rdev); 44678c2ecf20Sopenharmony_ci 44688c2ecf20Sopenharmony_ci return ret; 44698c2ecf20Sopenharmony_ci} 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci/** 44728c2ecf20Sopenharmony_ci * regulator_get_mode - get regulator operating mode 44738c2ecf20Sopenharmony_ci * @regulator: regulator source 44748c2ecf20Sopenharmony_ci * 44758c2ecf20Sopenharmony_ci * Get the current regulator operating mode. 44768c2ecf20Sopenharmony_ci */ 44778c2ecf20Sopenharmony_ciunsigned int regulator_get_mode(struct regulator *regulator) 44788c2ecf20Sopenharmony_ci{ 44798c2ecf20Sopenharmony_ci return _regulator_get_mode(regulator->rdev); 44808c2ecf20Sopenharmony_ci} 44818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_mode); 44828c2ecf20Sopenharmony_ci 44838c2ecf20Sopenharmony_cistatic int _regulator_get_error_flags(struct regulator_dev *rdev, 44848c2ecf20Sopenharmony_ci unsigned int *flags) 44858c2ecf20Sopenharmony_ci{ 44868c2ecf20Sopenharmony_ci int ret; 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci regulator_lock(rdev); 44898c2ecf20Sopenharmony_ci 44908c2ecf20Sopenharmony_ci /* sanity check */ 44918c2ecf20Sopenharmony_ci if (!rdev->desc->ops->get_error_flags) { 44928c2ecf20Sopenharmony_ci ret = -EINVAL; 44938c2ecf20Sopenharmony_ci goto out; 44948c2ecf20Sopenharmony_ci } 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci ret = rdev->desc->ops->get_error_flags(rdev, flags); 44978c2ecf20Sopenharmony_ciout: 44988c2ecf20Sopenharmony_ci regulator_unlock(rdev); 44998c2ecf20Sopenharmony_ci return ret; 45008c2ecf20Sopenharmony_ci} 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci/** 45038c2ecf20Sopenharmony_ci * regulator_get_error_flags - get regulator error information 45048c2ecf20Sopenharmony_ci * @regulator: regulator source 45058c2ecf20Sopenharmony_ci * @flags: pointer to store error flags 45068c2ecf20Sopenharmony_ci * 45078c2ecf20Sopenharmony_ci * Get the current regulator error information. 45088c2ecf20Sopenharmony_ci */ 45098c2ecf20Sopenharmony_ciint regulator_get_error_flags(struct regulator *regulator, 45108c2ecf20Sopenharmony_ci unsigned int *flags) 45118c2ecf20Sopenharmony_ci{ 45128c2ecf20Sopenharmony_ci return _regulator_get_error_flags(regulator->rdev, flags); 45138c2ecf20Sopenharmony_ci} 45148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_error_flags); 45158c2ecf20Sopenharmony_ci 45168c2ecf20Sopenharmony_ci/** 45178c2ecf20Sopenharmony_ci * regulator_set_load - set regulator load 45188c2ecf20Sopenharmony_ci * @regulator: regulator source 45198c2ecf20Sopenharmony_ci * @uA_load: load current 45208c2ecf20Sopenharmony_ci * 45218c2ecf20Sopenharmony_ci * Notifies the regulator core of a new device load. This is then used by 45228c2ecf20Sopenharmony_ci * DRMS (if enabled by constraints) to set the most efficient regulator 45238c2ecf20Sopenharmony_ci * operating mode for the new regulator loading. 45248c2ecf20Sopenharmony_ci * 45258c2ecf20Sopenharmony_ci * Consumer devices notify their supply regulator of the maximum power 45268c2ecf20Sopenharmony_ci * they will require (can be taken from device datasheet in the power 45278c2ecf20Sopenharmony_ci * consumption tables) when they change operational status and hence power 45288c2ecf20Sopenharmony_ci * state. Examples of operational state changes that can affect power 45298c2ecf20Sopenharmony_ci * consumption are :- 45308c2ecf20Sopenharmony_ci * 45318c2ecf20Sopenharmony_ci * o Device is opened / closed. 45328c2ecf20Sopenharmony_ci * o Device I/O is about to begin or has just finished. 45338c2ecf20Sopenharmony_ci * o Device is idling in between work. 45348c2ecf20Sopenharmony_ci * 45358c2ecf20Sopenharmony_ci * This information is also exported via sysfs to userspace. 45368c2ecf20Sopenharmony_ci * 45378c2ecf20Sopenharmony_ci * DRMS will sum the total requested load on the regulator and change 45388c2ecf20Sopenharmony_ci * to the most efficient operating mode if platform constraints allow. 45398c2ecf20Sopenharmony_ci * 45408c2ecf20Sopenharmony_ci * NOTE: when a regulator consumer requests to have a regulator 45418c2ecf20Sopenharmony_ci * disabled then any load that consumer requested no longer counts 45428c2ecf20Sopenharmony_ci * toward the total requested load. If the regulator is re-enabled 45438c2ecf20Sopenharmony_ci * then the previously requested load will start counting again. 45448c2ecf20Sopenharmony_ci * 45458c2ecf20Sopenharmony_ci * If a regulator is an always-on regulator then an individual consumer's 45468c2ecf20Sopenharmony_ci * load will still be removed if that consumer is fully disabled. 45478c2ecf20Sopenharmony_ci * 45488c2ecf20Sopenharmony_ci * On error a negative errno is returned. 45498c2ecf20Sopenharmony_ci */ 45508c2ecf20Sopenharmony_ciint regulator_set_load(struct regulator *regulator, int uA_load) 45518c2ecf20Sopenharmony_ci{ 45528c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 45538c2ecf20Sopenharmony_ci int old_uA_load; 45548c2ecf20Sopenharmony_ci int ret = 0; 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci regulator_lock(rdev); 45578c2ecf20Sopenharmony_ci old_uA_load = regulator->uA_load; 45588c2ecf20Sopenharmony_ci regulator->uA_load = uA_load; 45598c2ecf20Sopenharmony_ci if (regulator->enable_count && old_uA_load != uA_load) { 45608c2ecf20Sopenharmony_ci ret = drms_uA_update(rdev); 45618c2ecf20Sopenharmony_ci if (ret < 0) 45628c2ecf20Sopenharmony_ci regulator->uA_load = old_uA_load; 45638c2ecf20Sopenharmony_ci } 45648c2ecf20Sopenharmony_ci regulator_unlock(rdev); 45658c2ecf20Sopenharmony_ci 45668c2ecf20Sopenharmony_ci return ret; 45678c2ecf20Sopenharmony_ci} 45688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_load); 45698c2ecf20Sopenharmony_ci 45708c2ecf20Sopenharmony_ci/** 45718c2ecf20Sopenharmony_ci * regulator_allow_bypass - allow the regulator to go into bypass mode 45728c2ecf20Sopenharmony_ci * 45738c2ecf20Sopenharmony_ci * @regulator: Regulator to configure 45748c2ecf20Sopenharmony_ci * @enable: enable or disable bypass mode 45758c2ecf20Sopenharmony_ci * 45768c2ecf20Sopenharmony_ci * Allow the regulator to go into bypass mode if all other consumers 45778c2ecf20Sopenharmony_ci * for the regulator also enable bypass mode and the machine 45788c2ecf20Sopenharmony_ci * constraints allow this. Bypass mode means that the regulator is 45798c2ecf20Sopenharmony_ci * simply passing the input directly to the output with no regulation. 45808c2ecf20Sopenharmony_ci */ 45818c2ecf20Sopenharmony_ciint regulator_allow_bypass(struct regulator *regulator, bool enable) 45828c2ecf20Sopenharmony_ci{ 45838c2ecf20Sopenharmony_ci struct regulator_dev *rdev = regulator->rdev; 45848c2ecf20Sopenharmony_ci const char *name = rdev_get_name(rdev); 45858c2ecf20Sopenharmony_ci int ret = 0; 45868c2ecf20Sopenharmony_ci 45878c2ecf20Sopenharmony_ci if (!rdev->desc->ops->set_bypass) 45888c2ecf20Sopenharmony_ci return 0; 45898c2ecf20Sopenharmony_ci 45908c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_BYPASS)) 45918c2ecf20Sopenharmony_ci return 0; 45928c2ecf20Sopenharmony_ci 45938c2ecf20Sopenharmony_ci regulator_lock(rdev); 45948c2ecf20Sopenharmony_ci 45958c2ecf20Sopenharmony_ci if (enable && !regulator->bypass) { 45968c2ecf20Sopenharmony_ci rdev->bypass_count++; 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci if (rdev->bypass_count == rdev->open_count) { 45998c2ecf20Sopenharmony_ci trace_regulator_bypass_enable(name); 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_bypass(rdev, enable); 46028c2ecf20Sopenharmony_ci if (ret != 0) 46038c2ecf20Sopenharmony_ci rdev->bypass_count--; 46048c2ecf20Sopenharmony_ci else 46058c2ecf20Sopenharmony_ci trace_regulator_bypass_enable_complete(name); 46068c2ecf20Sopenharmony_ci } 46078c2ecf20Sopenharmony_ci 46088c2ecf20Sopenharmony_ci } else if (!enable && regulator->bypass) { 46098c2ecf20Sopenharmony_ci rdev->bypass_count--; 46108c2ecf20Sopenharmony_ci 46118c2ecf20Sopenharmony_ci if (rdev->bypass_count != rdev->open_count) { 46128c2ecf20Sopenharmony_ci trace_regulator_bypass_disable(name); 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci ret = rdev->desc->ops->set_bypass(rdev, enable); 46158c2ecf20Sopenharmony_ci if (ret != 0) 46168c2ecf20Sopenharmony_ci rdev->bypass_count++; 46178c2ecf20Sopenharmony_ci else 46188c2ecf20Sopenharmony_ci trace_regulator_bypass_disable_complete(name); 46198c2ecf20Sopenharmony_ci } 46208c2ecf20Sopenharmony_ci } 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci if (ret == 0) 46238c2ecf20Sopenharmony_ci regulator->bypass = enable; 46248c2ecf20Sopenharmony_ci 46258c2ecf20Sopenharmony_ci regulator_unlock(rdev); 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci return ret; 46288c2ecf20Sopenharmony_ci} 46298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_allow_bypass); 46308c2ecf20Sopenharmony_ci 46318c2ecf20Sopenharmony_ci/** 46328c2ecf20Sopenharmony_ci * regulator_register_notifier - register regulator event notifier 46338c2ecf20Sopenharmony_ci * @regulator: regulator source 46348c2ecf20Sopenharmony_ci * @nb: notifier block 46358c2ecf20Sopenharmony_ci * 46368c2ecf20Sopenharmony_ci * Register notifier block to receive regulator events. 46378c2ecf20Sopenharmony_ci */ 46388c2ecf20Sopenharmony_ciint regulator_register_notifier(struct regulator *regulator, 46398c2ecf20Sopenharmony_ci struct notifier_block *nb) 46408c2ecf20Sopenharmony_ci{ 46418c2ecf20Sopenharmony_ci return blocking_notifier_chain_register(®ulator->rdev->notifier, 46428c2ecf20Sopenharmony_ci nb); 46438c2ecf20Sopenharmony_ci} 46448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register_notifier); 46458c2ecf20Sopenharmony_ci 46468c2ecf20Sopenharmony_ci/** 46478c2ecf20Sopenharmony_ci * regulator_unregister_notifier - unregister regulator event notifier 46488c2ecf20Sopenharmony_ci * @regulator: regulator source 46498c2ecf20Sopenharmony_ci * @nb: notifier block 46508c2ecf20Sopenharmony_ci * 46518c2ecf20Sopenharmony_ci * Unregister regulator event notifier block. 46528c2ecf20Sopenharmony_ci */ 46538c2ecf20Sopenharmony_ciint regulator_unregister_notifier(struct regulator *regulator, 46548c2ecf20Sopenharmony_ci struct notifier_block *nb) 46558c2ecf20Sopenharmony_ci{ 46568c2ecf20Sopenharmony_ci return blocking_notifier_chain_unregister(®ulator->rdev->notifier, 46578c2ecf20Sopenharmony_ci nb); 46588c2ecf20Sopenharmony_ci} 46598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister_notifier); 46608c2ecf20Sopenharmony_ci 46618c2ecf20Sopenharmony_ci/* notify regulator consumers and downstream regulator consumers. 46628c2ecf20Sopenharmony_ci * Note mutex must be held by caller. 46638c2ecf20Sopenharmony_ci */ 46648c2ecf20Sopenharmony_cistatic int _notifier_call_chain(struct regulator_dev *rdev, 46658c2ecf20Sopenharmony_ci unsigned long event, void *data) 46668c2ecf20Sopenharmony_ci{ 46678c2ecf20Sopenharmony_ci /* call rdev chain first */ 46688c2ecf20Sopenharmony_ci return blocking_notifier_call_chain(&rdev->notifier, event, data); 46698c2ecf20Sopenharmony_ci} 46708c2ecf20Sopenharmony_ci 46718c2ecf20Sopenharmony_ci/** 46728c2ecf20Sopenharmony_ci * regulator_bulk_get - get multiple regulator consumers 46738c2ecf20Sopenharmony_ci * 46748c2ecf20Sopenharmony_ci * @dev: Device to supply 46758c2ecf20Sopenharmony_ci * @num_consumers: Number of consumers to register 46768c2ecf20Sopenharmony_ci * @consumers: Configuration of consumers; clients are stored here. 46778c2ecf20Sopenharmony_ci * 46788c2ecf20Sopenharmony_ci * @return 0 on success, an errno on failure. 46798c2ecf20Sopenharmony_ci * 46808c2ecf20Sopenharmony_ci * This helper function allows drivers to get several regulator 46818c2ecf20Sopenharmony_ci * consumers in one operation. If any of the regulators cannot be 46828c2ecf20Sopenharmony_ci * acquired then any regulators that were allocated will be freed 46838c2ecf20Sopenharmony_ci * before returning to the caller. 46848c2ecf20Sopenharmony_ci */ 46858c2ecf20Sopenharmony_ciint regulator_bulk_get(struct device *dev, int num_consumers, 46868c2ecf20Sopenharmony_ci struct regulator_bulk_data *consumers) 46878c2ecf20Sopenharmony_ci{ 46888c2ecf20Sopenharmony_ci int i; 46898c2ecf20Sopenharmony_ci int ret; 46908c2ecf20Sopenharmony_ci 46918c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) 46928c2ecf20Sopenharmony_ci consumers[i].consumer = NULL; 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 46958c2ecf20Sopenharmony_ci consumers[i].consumer = regulator_get(dev, 46968c2ecf20Sopenharmony_ci consumers[i].supply); 46978c2ecf20Sopenharmony_ci if (IS_ERR(consumers[i].consumer)) { 46988c2ecf20Sopenharmony_ci ret = PTR_ERR(consumers[i].consumer); 46998c2ecf20Sopenharmony_ci consumers[i].consumer = NULL; 47008c2ecf20Sopenharmony_ci goto err; 47018c2ecf20Sopenharmony_ci } 47028c2ecf20Sopenharmony_ci } 47038c2ecf20Sopenharmony_ci 47048c2ecf20Sopenharmony_ci return 0; 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_cierr: 47078c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 47088c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get supply '%s': %pe\n", 47098c2ecf20Sopenharmony_ci consumers[i].supply, ERR_PTR(ret)); 47108c2ecf20Sopenharmony_ci else 47118c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to get supply '%s', deferring\n", 47128c2ecf20Sopenharmony_ci consumers[i].supply); 47138c2ecf20Sopenharmony_ci 47148c2ecf20Sopenharmony_ci while (--i >= 0) 47158c2ecf20Sopenharmony_ci regulator_put(consumers[i].consumer); 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci return ret; 47188c2ecf20Sopenharmony_ci} 47198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_get); 47208c2ecf20Sopenharmony_ci 47218c2ecf20Sopenharmony_cistatic void regulator_bulk_enable_async(void *data, async_cookie_t cookie) 47228c2ecf20Sopenharmony_ci{ 47238c2ecf20Sopenharmony_ci struct regulator_bulk_data *bulk = data; 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_ci bulk->ret = regulator_enable(bulk->consumer); 47268c2ecf20Sopenharmony_ci} 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci/** 47298c2ecf20Sopenharmony_ci * regulator_bulk_enable - enable multiple regulator consumers 47308c2ecf20Sopenharmony_ci * 47318c2ecf20Sopenharmony_ci * @num_consumers: Number of consumers 47328c2ecf20Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 47338c2ecf20Sopenharmony_ci * @return 0 on success, an errno on failure 47348c2ecf20Sopenharmony_ci * 47358c2ecf20Sopenharmony_ci * This convenience API allows consumers to enable multiple regulator 47368c2ecf20Sopenharmony_ci * clients in a single API call. If any consumers cannot be enabled 47378c2ecf20Sopenharmony_ci * then any others that were enabled will be disabled again prior to 47388c2ecf20Sopenharmony_ci * return. 47398c2ecf20Sopenharmony_ci */ 47408c2ecf20Sopenharmony_ciint regulator_bulk_enable(int num_consumers, 47418c2ecf20Sopenharmony_ci struct regulator_bulk_data *consumers) 47428c2ecf20Sopenharmony_ci{ 47438c2ecf20Sopenharmony_ci ASYNC_DOMAIN_EXCLUSIVE(async_domain); 47448c2ecf20Sopenharmony_ci int i; 47458c2ecf20Sopenharmony_ci int ret = 0; 47468c2ecf20Sopenharmony_ci 47478c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 47488c2ecf20Sopenharmony_ci async_schedule_domain(regulator_bulk_enable_async, 47498c2ecf20Sopenharmony_ci &consumers[i], &async_domain); 47508c2ecf20Sopenharmony_ci } 47518c2ecf20Sopenharmony_ci 47528c2ecf20Sopenharmony_ci async_synchronize_full_domain(&async_domain); 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_ci /* If any consumer failed we need to unwind any that succeeded */ 47558c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 47568c2ecf20Sopenharmony_ci if (consumers[i].ret != 0) { 47578c2ecf20Sopenharmony_ci ret = consumers[i].ret; 47588c2ecf20Sopenharmony_ci goto err; 47598c2ecf20Sopenharmony_ci } 47608c2ecf20Sopenharmony_ci } 47618c2ecf20Sopenharmony_ci 47628c2ecf20Sopenharmony_ci return 0; 47638c2ecf20Sopenharmony_ci 47648c2ecf20Sopenharmony_cierr: 47658c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 47668c2ecf20Sopenharmony_ci if (consumers[i].ret < 0) 47678c2ecf20Sopenharmony_ci pr_err("Failed to enable %s: %pe\n", consumers[i].supply, 47688c2ecf20Sopenharmony_ci ERR_PTR(consumers[i].ret)); 47698c2ecf20Sopenharmony_ci else 47708c2ecf20Sopenharmony_ci regulator_disable(consumers[i].consumer); 47718c2ecf20Sopenharmony_ci } 47728c2ecf20Sopenharmony_ci 47738c2ecf20Sopenharmony_ci return ret; 47748c2ecf20Sopenharmony_ci} 47758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_enable); 47768c2ecf20Sopenharmony_ci 47778c2ecf20Sopenharmony_ci/** 47788c2ecf20Sopenharmony_ci * regulator_bulk_disable - disable multiple regulator consumers 47798c2ecf20Sopenharmony_ci * 47808c2ecf20Sopenharmony_ci * @num_consumers: Number of consumers 47818c2ecf20Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 47828c2ecf20Sopenharmony_ci * @return 0 on success, an errno on failure 47838c2ecf20Sopenharmony_ci * 47848c2ecf20Sopenharmony_ci * This convenience API allows consumers to disable multiple regulator 47858c2ecf20Sopenharmony_ci * clients in a single API call. If any consumers cannot be disabled 47868c2ecf20Sopenharmony_ci * then any others that were disabled will be enabled again prior to 47878c2ecf20Sopenharmony_ci * return. 47888c2ecf20Sopenharmony_ci */ 47898c2ecf20Sopenharmony_ciint regulator_bulk_disable(int num_consumers, 47908c2ecf20Sopenharmony_ci struct regulator_bulk_data *consumers) 47918c2ecf20Sopenharmony_ci{ 47928c2ecf20Sopenharmony_ci int i; 47938c2ecf20Sopenharmony_ci int ret, r; 47948c2ecf20Sopenharmony_ci 47958c2ecf20Sopenharmony_ci for (i = num_consumers - 1; i >= 0; --i) { 47968c2ecf20Sopenharmony_ci ret = regulator_disable(consumers[i].consumer); 47978c2ecf20Sopenharmony_ci if (ret != 0) 47988c2ecf20Sopenharmony_ci goto err; 47998c2ecf20Sopenharmony_ci } 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci return 0; 48028c2ecf20Sopenharmony_ci 48038c2ecf20Sopenharmony_cierr: 48048c2ecf20Sopenharmony_ci pr_err("Failed to disable %s: %pe\n", consumers[i].supply, ERR_PTR(ret)); 48058c2ecf20Sopenharmony_ci for (++i; i < num_consumers; ++i) { 48068c2ecf20Sopenharmony_ci r = regulator_enable(consumers[i].consumer); 48078c2ecf20Sopenharmony_ci if (r != 0) 48088c2ecf20Sopenharmony_ci pr_err("Failed to re-enable %s: %pe\n", 48098c2ecf20Sopenharmony_ci consumers[i].supply, ERR_PTR(r)); 48108c2ecf20Sopenharmony_ci } 48118c2ecf20Sopenharmony_ci 48128c2ecf20Sopenharmony_ci return ret; 48138c2ecf20Sopenharmony_ci} 48148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_disable); 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_ci/** 48178c2ecf20Sopenharmony_ci * regulator_bulk_force_disable - force disable multiple regulator consumers 48188c2ecf20Sopenharmony_ci * 48198c2ecf20Sopenharmony_ci * @num_consumers: Number of consumers 48208c2ecf20Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 48218c2ecf20Sopenharmony_ci * @return 0 on success, an errno on failure 48228c2ecf20Sopenharmony_ci * 48238c2ecf20Sopenharmony_ci * This convenience API allows consumers to forcibly disable multiple regulator 48248c2ecf20Sopenharmony_ci * clients in a single API call. 48258c2ecf20Sopenharmony_ci * NOTE: This should be used for situations when device damage will 48268c2ecf20Sopenharmony_ci * likely occur if the regulators are not disabled (e.g. over temp). 48278c2ecf20Sopenharmony_ci * Although regulator_force_disable function call for some consumers can 48288c2ecf20Sopenharmony_ci * return error numbers, the function is called for all consumers. 48298c2ecf20Sopenharmony_ci */ 48308c2ecf20Sopenharmony_ciint regulator_bulk_force_disable(int num_consumers, 48318c2ecf20Sopenharmony_ci struct regulator_bulk_data *consumers) 48328c2ecf20Sopenharmony_ci{ 48338c2ecf20Sopenharmony_ci int i; 48348c2ecf20Sopenharmony_ci int ret = 0; 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 48378c2ecf20Sopenharmony_ci consumers[i].ret = 48388c2ecf20Sopenharmony_ci regulator_force_disable(consumers[i].consumer); 48398c2ecf20Sopenharmony_ci 48408c2ecf20Sopenharmony_ci /* Store first error for reporting */ 48418c2ecf20Sopenharmony_ci if (consumers[i].ret && !ret) 48428c2ecf20Sopenharmony_ci ret = consumers[i].ret; 48438c2ecf20Sopenharmony_ci } 48448c2ecf20Sopenharmony_ci 48458c2ecf20Sopenharmony_ci return ret; 48468c2ecf20Sopenharmony_ci} 48478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_force_disable); 48488c2ecf20Sopenharmony_ci 48498c2ecf20Sopenharmony_ci/** 48508c2ecf20Sopenharmony_ci * regulator_bulk_free - free multiple regulator consumers 48518c2ecf20Sopenharmony_ci * 48528c2ecf20Sopenharmony_ci * @num_consumers: Number of consumers 48538c2ecf20Sopenharmony_ci * @consumers: Consumer data; clients are stored here. 48548c2ecf20Sopenharmony_ci * 48558c2ecf20Sopenharmony_ci * This convenience API allows consumers to free multiple regulator 48568c2ecf20Sopenharmony_ci * clients in a single API call. 48578c2ecf20Sopenharmony_ci */ 48588c2ecf20Sopenharmony_civoid regulator_bulk_free(int num_consumers, 48598c2ecf20Sopenharmony_ci struct regulator_bulk_data *consumers) 48608c2ecf20Sopenharmony_ci{ 48618c2ecf20Sopenharmony_ci int i; 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_ci for (i = 0; i < num_consumers; i++) { 48648c2ecf20Sopenharmony_ci regulator_put(consumers[i].consumer); 48658c2ecf20Sopenharmony_ci consumers[i].consumer = NULL; 48668c2ecf20Sopenharmony_ci } 48678c2ecf20Sopenharmony_ci} 48688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_bulk_free); 48698c2ecf20Sopenharmony_ci 48708c2ecf20Sopenharmony_ci/** 48718c2ecf20Sopenharmony_ci * regulator_notifier_call_chain - call regulator event notifier 48728c2ecf20Sopenharmony_ci * @rdev: regulator source 48738c2ecf20Sopenharmony_ci * @event: notifier block 48748c2ecf20Sopenharmony_ci * @data: callback-specific data. 48758c2ecf20Sopenharmony_ci * 48768c2ecf20Sopenharmony_ci * Called by regulator drivers to notify clients a regulator event has 48778c2ecf20Sopenharmony_ci * occurred. 48788c2ecf20Sopenharmony_ci */ 48798c2ecf20Sopenharmony_ciint regulator_notifier_call_chain(struct regulator_dev *rdev, 48808c2ecf20Sopenharmony_ci unsigned long event, void *data) 48818c2ecf20Sopenharmony_ci{ 48828c2ecf20Sopenharmony_ci _notifier_call_chain(rdev, event, data); 48838c2ecf20Sopenharmony_ci return NOTIFY_DONE; 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci} 48868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_notifier_call_chain); 48878c2ecf20Sopenharmony_ci 48888c2ecf20Sopenharmony_ci/** 48898c2ecf20Sopenharmony_ci * regulator_mode_to_status - convert a regulator mode into a status 48908c2ecf20Sopenharmony_ci * 48918c2ecf20Sopenharmony_ci * @mode: Mode to convert 48928c2ecf20Sopenharmony_ci * 48938c2ecf20Sopenharmony_ci * Convert a regulator mode into a status. 48948c2ecf20Sopenharmony_ci */ 48958c2ecf20Sopenharmony_ciint regulator_mode_to_status(unsigned int mode) 48968c2ecf20Sopenharmony_ci{ 48978c2ecf20Sopenharmony_ci switch (mode) { 48988c2ecf20Sopenharmony_ci case REGULATOR_MODE_FAST: 48998c2ecf20Sopenharmony_ci return REGULATOR_STATUS_FAST; 49008c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: 49018c2ecf20Sopenharmony_ci return REGULATOR_STATUS_NORMAL; 49028c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: 49038c2ecf20Sopenharmony_ci return REGULATOR_STATUS_IDLE; 49048c2ecf20Sopenharmony_ci case REGULATOR_MODE_STANDBY: 49058c2ecf20Sopenharmony_ci return REGULATOR_STATUS_STANDBY; 49068c2ecf20Sopenharmony_ci default: 49078c2ecf20Sopenharmony_ci return REGULATOR_STATUS_UNDEFINED; 49088c2ecf20Sopenharmony_ci } 49098c2ecf20Sopenharmony_ci} 49108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_mode_to_status); 49118c2ecf20Sopenharmony_ci 49128c2ecf20Sopenharmony_cistatic struct attribute *regulator_dev_attrs[] = { 49138c2ecf20Sopenharmony_ci &dev_attr_name.attr, 49148c2ecf20Sopenharmony_ci &dev_attr_num_users.attr, 49158c2ecf20Sopenharmony_ci &dev_attr_type.attr, 49168c2ecf20Sopenharmony_ci &dev_attr_microvolts.attr, 49178c2ecf20Sopenharmony_ci &dev_attr_microamps.attr, 49188c2ecf20Sopenharmony_ci &dev_attr_opmode.attr, 49198c2ecf20Sopenharmony_ci &dev_attr_state.attr, 49208c2ecf20Sopenharmony_ci &dev_attr_status.attr, 49218c2ecf20Sopenharmony_ci &dev_attr_bypass.attr, 49228c2ecf20Sopenharmony_ci &dev_attr_requested_microamps.attr, 49238c2ecf20Sopenharmony_ci &dev_attr_min_microvolts.attr, 49248c2ecf20Sopenharmony_ci &dev_attr_max_microvolts.attr, 49258c2ecf20Sopenharmony_ci &dev_attr_min_microamps.attr, 49268c2ecf20Sopenharmony_ci &dev_attr_max_microamps.attr, 49278c2ecf20Sopenharmony_ci &dev_attr_suspend_standby_state.attr, 49288c2ecf20Sopenharmony_ci &dev_attr_suspend_mem_state.attr, 49298c2ecf20Sopenharmony_ci &dev_attr_suspend_disk_state.attr, 49308c2ecf20Sopenharmony_ci &dev_attr_suspend_standby_microvolts.attr, 49318c2ecf20Sopenharmony_ci &dev_attr_suspend_mem_microvolts.attr, 49328c2ecf20Sopenharmony_ci &dev_attr_suspend_disk_microvolts.attr, 49338c2ecf20Sopenharmony_ci &dev_attr_suspend_standby_mode.attr, 49348c2ecf20Sopenharmony_ci &dev_attr_suspend_mem_mode.attr, 49358c2ecf20Sopenharmony_ci &dev_attr_suspend_disk_mode.attr, 49368c2ecf20Sopenharmony_ci NULL 49378c2ecf20Sopenharmony_ci}; 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci/* 49408c2ecf20Sopenharmony_ci * To avoid cluttering sysfs (and memory) with useless state, only 49418c2ecf20Sopenharmony_ci * create attributes that can be meaningfully displayed. 49428c2ecf20Sopenharmony_ci */ 49438c2ecf20Sopenharmony_cistatic umode_t regulator_attr_is_visible(struct kobject *kobj, 49448c2ecf20Sopenharmony_ci struct attribute *attr, int idx) 49458c2ecf20Sopenharmony_ci{ 49468c2ecf20Sopenharmony_ci struct device *dev = kobj_to_dev(kobj); 49478c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 49488c2ecf20Sopenharmony_ci const struct regulator_ops *ops = rdev->desc->ops; 49498c2ecf20Sopenharmony_ci umode_t mode = attr->mode; 49508c2ecf20Sopenharmony_ci 49518c2ecf20Sopenharmony_ci /* these three are always present */ 49528c2ecf20Sopenharmony_ci if (attr == &dev_attr_name.attr || 49538c2ecf20Sopenharmony_ci attr == &dev_attr_num_users.attr || 49548c2ecf20Sopenharmony_ci attr == &dev_attr_type.attr) 49558c2ecf20Sopenharmony_ci return mode; 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci /* some attributes need specific methods to be displayed */ 49588c2ecf20Sopenharmony_ci if (attr == &dev_attr_microvolts.attr) { 49598c2ecf20Sopenharmony_ci if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) || 49608c2ecf20Sopenharmony_ci (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) || 49618c2ecf20Sopenharmony_ci (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) || 49628c2ecf20Sopenharmony_ci (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1)) 49638c2ecf20Sopenharmony_ci return mode; 49648c2ecf20Sopenharmony_ci return 0; 49658c2ecf20Sopenharmony_ci } 49668c2ecf20Sopenharmony_ci 49678c2ecf20Sopenharmony_ci if (attr == &dev_attr_microamps.attr) 49688c2ecf20Sopenharmony_ci return ops->get_current_limit ? mode : 0; 49698c2ecf20Sopenharmony_ci 49708c2ecf20Sopenharmony_ci if (attr == &dev_attr_opmode.attr) 49718c2ecf20Sopenharmony_ci return ops->get_mode ? mode : 0; 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci if (attr == &dev_attr_state.attr) 49748c2ecf20Sopenharmony_ci return (rdev->ena_pin || ops->is_enabled) ? mode : 0; 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci if (attr == &dev_attr_status.attr) 49778c2ecf20Sopenharmony_ci return ops->get_status ? mode : 0; 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci if (attr == &dev_attr_bypass.attr) 49808c2ecf20Sopenharmony_ci return ops->get_bypass ? mode : 0; 49818c2ecf20Sopenharmony_ci 49828c2ecf20Sopenharmony_ci /* constraints need specific supporting methods */ 49838c2ecf20Sopenharmony_ci if (attr == &dev_attr_min_microvolts.attr || 49848c2ecf20Sopenharmony_ci attr == &dev_attr_max_microvolts.attr) 49858c2ecf20Sopenharmony_ci return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (attr == &dev_attr_min_microamps.attr || 49888c2ecf20Sopenharmony_ci attr == &dev_attr_max_microamps.attr) 49898c2ecf20Sopenharmony_ci return ops->set_current_limit ? mode : 0; 49908c2ecf20Sopenharmony_ci 49918c2ecf20Sopenharmony_ci if (attr == &dev_attr_suspend_standby_state.attr || 49928c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_mem_state.attr || 49938c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_disk_state.attr) 49948c2ecf20Sopenharmony_ci return mode; 49958c2ecf20Sopenharmony_ci 49968c2ecf20Sopenharmony_ci if (attr == &dev_attr_suspend_standby_microvolts.attr || 49978c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_mem_microvolts.attr || 49988c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_disk_microvolts.attr) 49998c2ecf20Sopenharmony_ci return ops->set_suspend_voltage ? mode : 0; 50008c2ecf20Sopenharmony_ci 50018c2ecf20Sopenharmony_ci if (attr == &dev_attr_suspend_standby_mode.attr || 50028c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_mem_mode.attr || 50038c2ecf20Sopenharmony_ci attr == &dev_attr_suspend_disk_mode.attr) 50048c2ecf20Sopenharmony_ci return ops->set_suspend_mode ? mode : 0; 50058c2ecf20Sopenharmony_ci 50068c2ecf20Sopenharmony_ci return mode; 50078c2ecf20Sopenharmony_ci} 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_cistatic const struct attribute_group regulator_dev_group = { 50108c2ecf20Sopenharmony_ci .attrs = regulator_dev_attrs, 50118c2ecf20Sopenharmony_ci .is_visible = regulator_attr_is_visible, 50128c2ecf20Sopenharmony_ci}; 50138c2ecf20Sopenharmony_ci 50148c2ecf20Sopenharmony_cistatic const struct attribute_group *regulator_dev_groups[] = { 50158c2ecf20Sopenharmony_ci ®ulator_dev_group, 50168c2ecf20Sopenharmony_ci NULL 50178c2ecf20Sopenharmony_ci}; 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_cistatic void regulator_dev_release(struct device *dev) 50208c2ecf20Sopenharmony_ci{ 50218c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_get_drvdata(dev); 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci debugfs_remove_recursive(rdev->debugfs); 50248c2ecf20Sopenharmony_ci kfree(rdev->constraints); 50258c2ecf20Sopenharmony_ci of_node_put(rdev->dev.of_node); 50268c2ecf20Sopenharmony_ci kfree(rdev); 50278c2ecf20Sopenharmony_ci} 50288c2ecf20Sopenharmony_ci 50298c2ecf20Sopenharmony_cistatic void rdev_init_debugfs(struct regulator_dev *rdev) 50308c2ecf20Sopenharmony_ci{ 50318c2ecf20Sopenharmony_ci struct device *parent = rdev->dev.parent; 50328c2ecf20Sopenharmony_ci const char *rname = rdev_get_name(rdev); 50338c2ecf20Sopenharmony_ci char name[NAME_MAX]; 50348c2ecf20Sopenharmony_ci 50358c2ecf20Sopenharmony_ci /* Avoid duplicate debugfs directory names */ 50368c2ecf20Sopenharmony_ci if (parent && rname == rdev->desc->name) { 50378c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s-%s", dev_name(parent), 50388c2ecf20Sopenharmony_ci rname); 50398c2ecf20Sopenharmony_ci rname = name; 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci 50428c2ecf20Sopenharmony_ci rdev->debugfs = debugfs_create_dir(rname, debugfs_root); 50438c2ecf20Sopenharmony_ci if (IS_ERR(rdev->debugfs)) 50448c2ecf20Sopenharmony_ci rdev_dbg(rdev, "Failed to create debugfs directory\n"); 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci debugfs_create_u32("use_count", 0444, rdev->debugfs, 50478c2ecf20Sopenharmony_ci &rdev->use_count); 50488c2ecf20Sopenharmony_ci debugfs_create_u32("open_count", 0444, rdev->debugfs, 50498c2ecf20Sopenharmony_ci &rdev->open_count); 50508c2ecf20Sopenharmony_ci debugfs_create_u32("bypass_count", 0444, rdev->debugfs, 50518c2ecf20Sopenharmony_ci &rdev->bypass_count); 50528c2ecf20Sopenharmony_ci} 50538c2ecf20Sopenharmony_ci 50548c2ecf20Sopenharmony_cistatic int regulator_register_resolve_supply(struct device *dev, void *data) 50558c2ecf20Sopenharmony_ci{ 50568c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 50578c2ecf20Sopenharmony_ci 50588c2ecf20Sopenharmony_ci if (regulator_resolve_supply(rdev)) 50598c2ecf20Sopenharmony_ci rdev_dbg(rdev, "unable to resolve supply\n"); 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ci return 0; 50628c2ecf20Sopenharmony_ci} 50638c2ecf20Sopenharmony_ci 50648c2ecf20Sopenharmony_ciint regulator_coupler_register(struct regulator_coupler *coupler) 50658c2ecf20Sopenharmony_ci{ 50668c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 50678c2ecf20Sopenharmony_ci list_add_tail(&coupler->list, ®ulator_coupler_list); 50688c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 50698c2ecf20Sopenharmony_ci 50708c2ecf20Sopenharmony_ci return 0; 50718c2ecf20Sopenharmony_ci} 50728c2ecf20Sopenharmony_ci 50738c2ecf20Sopenharmony_cistatic struct regulator_coupler * 50748c2ecf20Sopenharmony_ciregulator_find_coupler(struct regulator_dev *rdev) 50758c2ecf20Sopenharmony_ci{ 50768c2ecf20Sopenharmony_ci struct regulator_coupler *coupler; 50778c2ecf20Sopenharmony_ci int err; 50788c2ecf20Sopenharmony_ci 50798c2ecf20Sopenharmony_ci /* 50808c2ecf20Sopenharmony_ci * Note that regulators are appended to the list and the generic 50818c2ecf20Sopenharmony_ci * coupler is registered first, hence it will be attached at last 50828c2ecf20Sopenharmony_ci * if nobody cared. 50838c2ecf20Sopenharmony_ci */ 50848c2ecf20Sopenharmony_ci list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { 50858c2ecf20Sopenharmony_ci err = coupler->attach_regulator(coupler, rdev); 50868c2ecf20Sopenharmony_ci if (!err) { 50878c2ecf20Sopenharmony_ci if (!coupler->balance_voltage && 50888c2ecf20Sopenharmony_ci rdev->coupling_desc.n_coupled > 2) 50898c2ecf20Sopenharmony_ci goto err_unsupported; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci return coupler; 50928c2ecf20Sopenharmony_ci } 50938c2ecf20Sopenharmony_ci 50948c2ecf20Sopenharmony_ci if (err < 0) 50958c2ecf20Sopenharmony_ci return ERR_PTR(err); 50968c2ecf20Sopenharmony_ci 50978c2ecf20Sopenharmony_ci if (err == 1) 50988c2ecf20Sopenharmony_ci continue; 50998c2ecf20Sopenharmony_ci 51008c2ecf20Sopenharmony_ci break; 51018c2ecf20Sopenharmony_ci } 51028c2ecf20Sopenharmony_ci 51038c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 51048c2ecf20Sopenharmony_ci 51058c2ecf20Sopenharmony_cierr_unsupported: 51068c2ecf20Sopenharmony_ci if (coupler->detach_regulator) 51078c2ecf20Sopenharmony_ci coupler->detach_regulator(coupler, rdev); 51088c2ecf20Sopenharmony_ci 51098c2ecf20Sopenharmony_ci rdev_err(rdev, 51108c2ecf20Sopenharmony_ci "Voltage balancing for multiple regulator couples is unimplemented\n"); 51118c2ecf20Sopenharmony_ci 51128c2ecf20Sopenharmony_ci return ERR_PTR(-EPERM); 51138c2ecf20Sopenharmony_ci} 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_cistatic void regulator_resolve_coupling(struct regulator_dev *rdev) 51168c2ecf20Sopenharmony_ci{ 51178c2ecf20Sopenharmony_ci struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 51188c2ecf20Sopenharmony_ci struct coupling_desc *c_desc = &rdev->coupling_desc; 51198c2ecf20Sopenharmony_ci int n_coupled = c_desc->n_coupled; 51208c2ecf20Sopenharmony_ci struct regulator_dev *c_rdev; 51218c2ecf20Sopenharmony_ci int i; 51228c2ecf20Sopenharmony_ci 51238c2ecf20Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 51248c2ecf20Sopenharmony_ci /* already resolved */ 51258c2ecf20Sopenharmony_ci if (c_desc->coupled_rdevs[i]) 51268c2ecf20Sopenharmony_ci continue; 51278c2ecf20Sopenharmony_ci 51288c2ecf20Sopenharmony_ci c_rdev = of_parse_coupled_regulator(rdev, i - 1); 51298c2ecf20Sopenharmony_ci 51308c2ecf20Sopenharmony_ci if (!c_rdev) 51318c2ecf20Sopenharmony_ci continue; 51328c2ecf20Sopenharmony_ci 51338c2ecf20Sopenharmony_ci if (c_rdev->coupling_desc.coupler != coupler) { 51348c2ecf20Sopenharmony_ci rdev_err(rdev, "coupler mismatch with %s\n", 51358c2ecf20Sopenharmony_ci rdev_get_name(c_rdev)); 51368c2ecf20Sopenharmony_ci return; 51378c2ecf20Sopenharmony_ci } 51388c2ecf20Sopenharmony_ci 51398c2ecf20Sopenharmony_ci c_desc->coupled_rdevs[i] = c_rdev; 51408c2ecf20Sopenharmony_ci c_desc->n_resolved++; 51418c2ecf20Sopenharmony_ci 51428c2ecf20Sopenharmony_ci regulator_resolve_coupling(c_rdev); 51438c2ecf20Sopenharmony_ci } 51448c2ecf20Sopenharmony_ci} 51458c2ecf20Sopenharmony_ci 51468c2ecf20Sopenharmony_cistatic void regulator_remove_coupling(struct regulator_dev *rdev) 51478c2ecf20Sopenharmony_ci{ 51488c2ecf20Sopenharmony_ci struct regulator_coupler *coupler = rdev->coupling_desc.coupler; 51498c2ecf20Sopenharmony_ci struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; 51508c2ecf20Sopenharmony_ci struct regulator_dev *__c_rdev, *c_rdev; 51518c2ecf20Sopenharmony_ci unsigned int __n_coupled, n_coupled; 51528c2ecf20Sopenharmony_ci int i, k; 51538c2ecf20Sopenharmony_ci int err; 51548c2ecf20Sopenharmony_ci 51558c2ecf20Sopenharmony_ci n_coupled = c_desc->n_coupled; 51568c2ecf20Sopenharmony_ci 51578c2ecf20Sopenharmony_ci for (i = 1; i < n_coupled; i++) { 51588c2ecf20Sopenharmony_ci c_rdev = c_desc->coupled_rdevs[i]; 51598c2ecf20Sopenharmony_ci 51608c2ecf20Sopenharmony_ci if (!c_rdev) 51618c2ecf20Sopenharmony_ci continue; 51628c2ecf20Sopenharmony_ci 51638c2ecf20Sopenharmony_ci regulator_lock(c_rdev); 51648c2ecf20Sopenharmony_ci 51658c2ecf20Sopenharmony_ci __c_desc = &c_rdev->coupling_desc; 51668c2ecf20Sopenharmony_ci __n_coupled = __c_desc->n_coupled; 51678c2ecf20Sopenharmony_ci 51688c2ecf20Sopenharmony_ci for (k = 1; k < __n_coupled; k++) { 51698c2ecf20Sopenharmony_ci __c_rdev = __c_desc->coupled_rdevs[k]; 51708c2ecf20Sopenharmony_ci 51718c2ecf20Sopenharmony_ci if (__c_rdev == rdev) { 51728c2ecf20Sopenharmony_ci __c_desc->coupled_rdevs[k] = NULL; 51738c2ecf20Sopenharmony_ci __c_desc->n_resolved--; 51748c2ecf20Sopenharmony_ci break; 51758c2ecf20Sopenharmony_ci } 51768c2ecf20Sopenharmony_ci } 51778c2ecf20Sopenharmony_ci 51788c2ecf20Sopenharmony_ci regulator_unlock(c_rdev); 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci c_desc->coupled_rdevs[i] = NULL; 51818c2ecf20Sopenharmony_ci c_desc->n_resolved--; 51828c2ecf20Sopenharmony_ci } 51838c2ecf20Sopenharmony_ci 51848c2ecf20Sopenharmony_ci if (coupler && coupler->detach_regulator) { 51858c2ecf20Sopenharmony_ci err = coupler->detach_regulator(coupler, rdev); 51868c2ecf20Sopenharmony_ci if (err) 51878c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to detach from coupler: %pe\n", 51888c2ecf20Sopenharmony_ci ERR_PTR(err)); 51898c2ecf20Sopenharmony_ci } 51908c2ecf20Sopenharmony_ci 51918c2ecf20Sopenharmony_ci kfree(rdev->coupling_desc.coupled_rdevs); 51928c2ecf20Sopenharmony_ci rdev->coupling_desc.coupled_rdevs = NULL; 51938c2ecf20Sopenharmony_ci} 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_cistatic int regulator_init_coupling(struct regulator_dev *rdev) 51968c2ecf20Sopenharmony_ci{ 51978c2ecf20Sopenharmony_ci struct regulator_dev **coupled; 51988c2ecf20Sopenharmony_ci int err, n_phandles; 51998c2ecf20Sopenharmony_ci 52008c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_OF)) 52018c2ecf20Sopenharmony_ci n_phandles = 0; 52028c2ecf20Sopenharmony_ci else 52038c2ecf20Sopenharmony_ci n_phandles = of_get_n_coupled(rdev); 52048c2ecf20Sopenharmony_ci 52058c2ecf20Sopenharmony_ci coupled = kcalloc(n_phandles + 1, sizeof(*coupled), GFP_KERNEL); 52068c2ecf20Sopenharmony_ci if (!coupled) 52078c2ecf20Sopenharmony_ci return -ENOMEM; 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci rdev->coupling_desc.coupled_rdevs = coupled; 52108c2ecf20Sopenharmony_ci 52118c2ecf20Sopenharmony_ci /* 52128c2ecf20Sopenharmony_ci * Every regulator should always have coupling descriptor filled with 52138c2ecf20Sopenharmony_ci * at least pointer to itself. 52148c2ecf20Sopenharmony_ci */ 52158c2ecf20Sopenharmony_ci rdev->coupling_desc.coupled_rdevs[0] = rdev; 52168c2ecf20Sopenharmony_ci rdev->coupling_desc.n_coupled = n_phandles + 1; 52178c2ecf20Sopenharmony_ci rdev->coupling_desc.n_resolved++; 52188c2ecf20Sopenharmony_ci 52198c2ecf20Sopenharmony_ci /* regulator isn't coupled */ 52208c2ecf20Sopenharmony_ci if (n_phandles == 0) 52218c2ecf20Sopenharmony_ci return 0; 52228c2ecf20Sopenharmony_ci 52238c2ecf20Sopenharmony_ci if (!of_check_coupling_data(rdev)) 52248c2ecf20Sopenharmony_ci return -EPERM; 52258c2ecf20Sopenharmony_ci 52268c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 52278c2ecf20Sopenharmony_ci rdev->coupling_desc.coupler = regulator_find_coupler(rdev); 52288c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 52298c2ecf20Sopenharmony_ci 52308c2ecf20Sopenharmony_ci if (IS_ERR(rdev->coupling_desc.coupler)) { 52318c2ecf20Sopenharmony_ci err = PTR_ERR(rdev->coupling_desc.coupler); 52328c2ecf20Sopenharmony_ci rdev_err(rdev, "failed to get coupler: %pe\n", ERR_PTR(err)); 52338c2ecf20Sopenharmony_ci return err; 52348c2ecf20Sopenharmony_ci } 52358c2ecf20Sopenharmony_ci 52368c2ecf20Sopenharmony_ci return 0; 52378c2ecf20Sopenharmony_ci} 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_cistatic int generic_coupler_attach(struct regulator_coupler *coupler, 52408c2ecf20Sopenharmony_ci struct regulator_dev *rdev) 52418c2ecf20Sopenharmony_ci{ 52428c2ecf20Sopenharmony_ci if (rdev->coupling_desc.n_coupled > 2) { 52438c2ecf20Sopenharmony_ci rdev_err(rdev, 52448c2ecf20Sopenharmony_ci "Voltage balancing for multiple regulator couples is unimplemented\n"); 52458c2ecf20Sopenharmony_ci return -EPERM; 52468c2ecf20Sopenharmony_ci } 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_ci if (!rdev->constraints->always_on) { 52498c2ecf20Sopenharmony_ci rdev_err(rdev, 52508c2ecf20Sopenharmony_ci "Coupling of a non always-on regulator is unimplemented\n"); 52518c2ecf20Sopenharmony_ci return -ENOTSUPP; 52528c2ecf20Sopenharmony_ci } 52538c2ecf20Sopenharmony_ci 52548c2ecf20Sopenharmony_ci return 0; 52558c2ecf20Sopenharmony_ci} 52568c2ecf20Sopenharmony_ci 52578c2ecf20Sopenharmony_cistatic struct regulator_coupler generic_regulator_coupler = { 52588c2ecf20Sopenharmony_ci .attach_regulator = generic_coupler_attach, 52598c2ecf20Sopenharmony_ci}; 52608c2ecf20Sopenharmony_ci 52618c2ecf20Sopenharmony_ci/** 52628c2ecf20Sopenharmony_ci * regulator_register - register regulator 52638c2ecf20Sopenharmony_ci * @regulator_desc: regulator to register 52648c2ecf20Sopenharmony_ci * @cfg: runtime configuration for regulator 52658c2ecf20Sopenharmony_ci * 52668c2ecf20Sopenharmony_ci * Called by regulator drivers to register a regulator. 52678c2ecf20Sopenharmony_ci * Returns a valid pointer to struct regulator_dev on success 52688c2ecf20Sopenharmony_ci * or an ERR_PTR() on error. 52698c2ecf20Sopenharmony_ci */ 52708c2ecf20Sopenharmony_cistruct regulator_dev * 52718c2ecf20Sopenharmony_ciregulator_register(const struct regulator_desc *regulator_desc, 52728c2ecf20Sopenharmony_ci const struct regulator_config *cfg) 52738c2ecf20Sopenharmony_ci{ 52748c2ecf20Sopenharmony_ci const struct regulator_init_data *init_data; 52758c2ecf20Sopenharmony_ci struct regulator_config *config = NULL; 52768c2ecf20Sopenharmony_ci static atomic_t regulator_no = ATOMIC_INIT(-1); 52778c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 52788c2ecf20Sopenharmony_ci bool dangling_cfg_gpiod = false; 52798c2ecf20Sopenharmony_ci bool dangling_of_gpiod = false; 52808c2ecf20Sopenharmony_ci struct device *dev; 52818c2ecf20Sopenharmony_ci int ret, i; 52828c2ecf20Sopenharmony_ci 52838c2ecf20Sopenharmony_ci if (cfg == NULL) 52848c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 52858c2ecf20Sopenharmony_ci if (cfg->ena_gpiod) 52868c2ecf20Sopenharmony_ci dangling_cfg_gpiod = true; 52878c2ecf20Sopenharmony_ci if (regulator_desc == NULL) { 52888c2ecf20Sopenharmony_ci ret = -EINVAL; 52898c2ecf20Sopenharmony_ci goto rinse; 52908c2ecf20Sopenharmony_ci } 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_ci dev = cfg->dev; 52938c2ecf20Sopenharmony_ci WARN_ON(!dev); 52948c2ecf20Sopenharmony_ci 52958c2ecf20Sopenharmony_ci if (regulator_desc->name == NULL || regulator_desc->ops == NULL) { 52968c2ecf20Sopenharmony_ci ret = -EINVAL; 52978c2ecf20Sopenharmony_ci goto rinse; 52988c2ecf20Sopenharmony_ci } 52998c2ecf20Sopenharmony_ci 53008c2ecf20Sopenharmony_ci if (regulator_desc->type != REGULATOR_VOLTAGE && 53018c2ecf20Sopenharmony_ci regulator_desc->type != REGULATOR_CURRENT) { 53028c2ecf20Sopenharmony_ci ret = -EINVAL; 53038c2ecf20Sopenharmony_ci goto rinse; 53048c2ecf20Sopenharmony_ci } 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci /* Only one of each should be implemented */ 53078c2ecf20Sopenharmony_ci WARN_ON(regulator_desc->ops->get_voltage && 53088c2ecf20Sopenharmony_ci regulator_desc->ops->get_voltage_sel); 53098c2ecf20Sopenharmony_ci WARN_ON(regulator_desc->ops->set_voltage && 53108c2ecf20Sopenharmony_ci regulator_desc->ops->set_voltage_sel); 53118c2ecf20Sopenharmony_ci 53128c2ecf20Sopenharmony_ci /* If we're using selectors we must implement list_voltage. */ 53138c2ecf20Sopenharmony_ci if (regulator_desc->ops->get_voltage_sel && 53148c2ecf20Sopenharmony_ci !regulator_desc->ops->list_voltage) { 53158c2ecf20Sopenharmony_ci ret = -EINVAL; 53168c2ecf20Sopenharmony_ci goto rinse; 53178c2ecf20Sopenharmony_ci } 53188c2ecf20Sopenharmony_ci if (regulator_desc->ops->set_voltage_sel && 53198c2ecf20Sopenharmony_ci !regulator_desc->ops->list_voltage) { 53208c2ecf20Sopenharmony_ci ret = -EINVAL; 53218c2ecf20Sopenharmony_ci goto rinse; 53228c2ecf20Sopenharmony_ci } 53238c2ecf20Sopenharmony_ci 53248c2ecf20Sopenharmony_ci rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); 53258c2ecf20Sopenharmony_ci if (rdev == NULL) { 53268c2ecf20Sopenharmony_ci ret = -ENOMEM; 53278c2ecf20Sopenharmony_ci goto rinse; 53288c2ecf20Sopenharmony_ci } 53298c2ecf20Sopenharmony_ci device_initialize(&rdev->dev); 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci /* 53328c2ecf20Sopenharmony_ci * Duplicate the config so the driver could override it after 53338c2ecf20Sopenharmony_ci * parsing init data. 53348c2ecf20Sopenharmony_ci */ 53358c2ecf20Sopenharmony_ci config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL); 53368c2ecf20Sopenharmony_ci if (config == NULL) { 53378c2ecf20Sopenharmony_ci ret = -ENOMEM; 53388c2ecf20Sopenharmony_ci goto clean; 53398c2ecf20Sopenharmony_ci } 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci init_data = regulator_of_get_init_data(dev, regulator_desc, config, 53428c2ecf20Sopenharmony_ci &rdev->dev.of_node); 53438c2ecf20Sopenharmony_ci 53448c2ecf20Sopenharmony_ci /* 53458c2ecf20Sopenharmony_ci * Sometimes not all resources are probed already so we need to take 53468c2ecf20Sopenharmony_ci * that into account. This happens most the time if the ena_gpiod comes 53478c2ecf20Sopenharmony_ci * from a gpio extender or something else. 53488c2ecf20Sopenharmony_ci */ 53498c2ecf20Sopenharmony_ci if (PTR_ERR(init_data) == -EPROBE_DEFER) { 53508c2ecf20Sopenharmony_ci ret = -EPROBE_DEFER; 53518c2ecf20Sopenharmony_ci goto clean; 53528c2ecf20Sopenharmony_ci } 53538c2ecf20Sopenharmony_ci 53548c2ecf20Sopenharmony_ci /* 53558c2ecf20Sopenharmony_ci * We need to keep track of any GPIO descriptor coming from the 53568c2ecf20Sopenharmony_ci * device tree until we have handled it over to the core. If the 53578c2ecf20Sopenharmony_ci * config that was passed in to this function DOES NOT contain 53588c2ecf20Sopenharmony_ci * a descriptor, and the config after this call DOES contain 53598c2ecf20Sopenharmony_ci * a descriptor, we definitely got one from parsing the device 53608c2ecf20Sopenharmony_ci * tree. 53618c2ecf20Sopenharmony_ci */ 53628c2ecf20Sopenharmony_ci if (!cfg->ena_gpiod && config->ena_gpiod) 53638c2ecf20Sopenharmony_ci dangling_of_gpiod = true; 53648c2ecf20Sopenharmony_ci if (!init_data) { 53658c2ecf20Sopenharmony_ci init_data = config->init_data; 53668c2ecf20Sopenharmony_ci rdev->dev.of_node = of_node_get(config->of_node); 53678c2ecf20Sopenharmony_ci } 53688c2ecf20Sopenharmony_ci 53698c2ecf20Sopenharmony_ci ww_mutex_init(&rdev->mutex, ®ulator_ww_class); 53708c2ecf20Sopenharmony_ci rdev->reg_data = config->driver_data; 53718c2ecf20Sopenharmony_ci rdev->owner = regulator_desc->owner; 53728c2ecf20Sopenharmony_ci rdev->desc = regulator_desc; 53738c2ecf20Sopenharmony_ci if (config->regmap) 53748c2ecf20Sopenharmony_ci rdev->regmap = config->regmap; 53758c2ecf20Sopenharmony_ci else if (dev_get_regmap(dev, NULL)) 53768c2ecf20Sopenharmony_ci rdev->regmap = dev_get_regmap(dev, NULL); 53778c2ecf20Sopenharmony_ci else if (dev->parent) 53788c2ecf20Sopenharmony_ci rdev->regmap = dev_get_regmap(dev->parent, NULL); 53798c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rdev->consumer_list); 53808c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&rdev->list); 53818c2ecf20Sopenharmony_ci BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier); 53828c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work); 53838c2ecf20Sopenharmony_ci 53848c2ecf20Sopenharmony_ci /* preform any regulator specific init */ 53858c2ecf20Sopenharmony_ci if (init_data && init_data->regulator_init) { 53868c2ecf20Sopenharmony_ci ret = init_data->regulator_init(rdev->reg_data); 53878c2ecf20Sopenharmony_ci if (ret < 0) 53888c2ecf20Sopenharmony_ci goto clean; 53898c2ecf20Sopenharmony_ci } 53908c2ecf20Sopenharmony_ci 53918c2ecf20Sopenharmony_ci if (config->ena_gpiod) { 53928c2ecf20Sopenharmony_ci ret = regulator_ena_gpio_request(rdev, config); 53938c2ecf20Sopenharmony_ci if (ret != 0) { 53948c2ecf20Sopenharmony_ci rdev_err(rdev, "Failed to request enable GPIO: %pe\n", 53958c2ecf20Sopenharmony_ci ERR_PTR(ret)); 53968c2ecf20Sopenharmony_ci goto clean; 53978c2ecf20Sopenharmony_ci } 53988c2ecf20Sopenharmony_ci /* The regulator core took over the GPIO descriptor */ 53998c2ecf20Sopenharmony_ci dangling_cfg_gpiod = false; 54008c2ecf20Sopenharmony_ci dangling_of_gpiod = false; 54018c2ecf20Sopenharmony_ci } 54028c2ecf20Sopenharmony_ci 54038c2ecf20Sopenharmony_ci /* register with sysfs */ 54048c2ecf20Sopenharmony_ci rdev->dev.class = ®ulator_class; 54058c2ecf20Sopenharmony_ci rdev->dev.parent = dev; 54068c2ecf20Sopenharmony_ci dev_set_name(&rdev->dev, "regulator.%lu", 54078c2ecf20Sopenharmony_ci (unsigned long) atomic_inc_return(®ulator_no)); 54088c2ecf20Sopenharmony_ci dev_set_drvdata(&rdev->dev, rdev); 54098c2ecf20Sopenharmony_ci 54108c2ecf20Sopenharmony_ci /* set regulator constraints */ 54118c2ecf20Sopenharmony_ci if (init_data) 54128c2ecf20Sopenharmony_ci rdev->constraints = kmemdup(&init_data->constraints, 54138c2ecf20Sopenharmony_ci sizeof(*rdev->constraints), 54148c2ecf20Sopenharmony_ci GFP_KERNEL); 54158c2ecf20Sopenharmony_ci else 54168c2ecf20Sopenharmony_ci rdev->constraints = kzalloc(sizeof(*rdev->constraints), 54178c2ecf20Sopenharmony_ci GFP_KERNEL); 54188c2ecf20Sopenharmony_ci if (!rdev->constraints) { 54198c2ecf20Sopenharmony_ci ret = -ENOMEM; 54208c2ecf20Sopenharmony_ci goto wash; 54218c2ecf20Sopenharmony_ci } 54228c2ecf20Sopenharmony_ci 54238c2ecf20Sopenharmony_ci if (init_data && init_data->supply_regulator) 54248c2ecf20Sopenharmony_ci rdev->supply_name = init_data->supply_regulator; 54258c2ecf20Sopenharmony_ci else if (regulator_desc->supply_name) 54268c2ecf20Sopenharmony_ci rdev->supply_name = regulator_desc->supply_name; 54278c2ecf20Sopenharmony_ci 54288c2ecf20Sopenharmony_ci ret = set_machine_constraints(rdev); 54298c2ecf20Sopenharmony_ci if (ret == -EPROBE_DEFER) { 54308c2ecf20Sopenharmony_ci /* Regulator might be in bypass mode and so needs its supply 54318c2ecf20Sopenharmony_ci * to set the constraints */ 54328c2ecf20Sopenharmony_ci /* FIXME: this currently triggers a chicken-and-egg problem 54338c2ecf20Sopenharmony_ci * when creating -SUPPLY symlink in sysfs to a regulator 54348c2ecf20Sopenharmony_ci * that is just being created */ 54358c2ecf20Sopenharmony_ci ret = regulator_resolve_supply(rdev); 54368c2ecf20Sopenharmony_ci if (!ret) 54378c2ecf20Sopenharmony_ci ret = set_machine_constraints(rdev); 54388c2ecf20Sopenharmony_ci else 54398c2ecf20Sopenharmony_ci rdev_dbg(rdev, "unable to resolve supply early: %pe\n", 54408c2ecf20Sopenharmony_ci ERR_PTR(ret)); 54418c2ecf20Sopenharmony_ci } 54428c2ecf20Sopenharmony_ci if (ret < 0) 54438c2ecf20Sopenharmony_ci goto wash; 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_ci ret = regulator_init_coupling(rdev); 54468c2ecf20Sopenharmony_ci if (ret < 0) 54478c2ecf20Sopenharmony_ci goto wash; 54488c2ecf20Sopenharmony_ci 54498c2ecf20Sopenharmony_ci /* add consumers devices */ 54508c2ecf20Sopenharmony_ci if (init_data) { 54518c2ecf20Sopenharmony_ci for (i = 0; i < init_data->num_consumer_supplies; i++) { 54528c2ecf20Sopenharmony_ci ret = set_consumer_device_supply(rdev, 54538c2ecf20Sopenharmony_ci init_data->consumer_supplies[i].dev_name, 54548c2ecf20Sopenharmony_ci init_data->consumer_supplies[i].supply); 54558c2ecf20Sopenharmony_ci if (ret < 0) { 54568c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set supply %s\n", 54578c2ecf20Sopenharmony_ci init_data->consumer_supplies[i].supply); 54588c2ecf20Sopenharmony_ci goto unset_supplies; 54598c2ecf20Sopenharmony_ci } 54608c2ecf20Sopenharmony_ci } 54618c2ecf20Sopenharmony_ci } 54628c2ecf20Sopenharmony_ci 54638c2ecf20Sopenharmony_ci if (!rdev->desc->ops->get_voltage && 54648c2ecf20Sopenharmony_ci !rdev->desc->ops->list_voltage && 54658c2ecf20Sopenharmony_ci !rdev->desc->fixed_uV) 54668c2ecf20Sopenharmony_ci rdev->is_switch = true; 54678c2ecf20Sopenharmony_ci 54688c2ecf20Sopenharmony_ci ret = device_add(&rdev->dev); 54698c2ecf20Sopenharmony_ci if (ret != 0) 54708c2ecf20Sopenharmony_ci goto unset_supplies; 54718c2ecf20Sopenharmony_ci 54728c2ecf20Sopenharmony_ci rdev_init_debugfs(rdev); 54738c2ecf20Sopenharmony_ci 54748c2ecf20Sopenharmony_ci /* try to resolve regulators coupling since a new one was registered */ 54758c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 54768c2ecf20Sopenharmony_ci regulator_resolve_coupling(rdev); 54778c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 54788c2ecf20Sopenharmony_ci 54798c2ecf20Sopenharmony_ci /* try to resolve regulators supply since a new one was registered */ 54808c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 54818c2ecf20Sopenharmony_ci regulator_register_resolve_supply); 54828c2ecf20Sopenharmony_ci kfree(config); 54838c2ecf20Sopenharmony_ci return rdev; 54848c2ecf20Sopenharmony_ci 54858c2ecf20Sopenharmony_ciunset_supplies: 54868c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 54878c2ecf20Sopenharmony_ci unset_regulator_supplies(rdev); 54888c2ecf20Sopenharmony_ci regulator_remove_coupling(rdev); 54898c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 54908c2ecf20Sopenharmony_ciwash: 54918c2ecf20Sopenharmony_ci regulator_put(rdev->supply); 54928c2ecf20Sopenharmony_ci kfree(rdev->coupling_desc.coupled_rdevs); 54938c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 54948c2ecf20Sopenharmony_ci regulator_ena_gpio_free(rdev); 54958c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 54968c2ecf20Sopenharmony_ciclean: 54978c2ecf20Sopenharmony_ci if (dangling_of_gpiod) 54988c2ecf20Sopenharmony_ci gpiod_put(config->ena_gpiod); 54998c2ecf20Sopenharmony_ci kfree(config); 55008c2ecf20Sopenharmony_ci put_device(&rdev->dev); 55018c2ecf20Sopenharmony_cirinse: 55028c2ecf20Sopenharmony_ci if (dangling_cfg_gpiod) 55038c2ecf20Sopenharmony_ci gpiod_put(cfg->ena_gpiod); 55048c2ecf20Sopenharmony_ci return ERR_PTR(ret); 55058c2ecf20Sopenharmony_ci} 55068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_register); 55078c2ecf20Sopenharmony_ci 55088c2ecf20Sopenharmony_ci/** 55098c2ecf20Sopenharmony_ci * regulator_unregister - unregister regulator 55108c2ecf20Sopenharmony_ci * @rdev: regulator to unregister 55118c2ecf20Sopenharmony_ci * 55128c2ecf20Sopenharmony_ci * Called by regulator drivers to unregister a regulator. 55138c2ecf20Sopenharmony_ci */ 55148c2ecf20Sopenharmony_civoid regulator_unregister(struct regulator_dev *rdev) 55158c2ecf20Sopenharmony_ci{ 55168c2ecf20Sopenharmony_ci if (rdev == NULL) 55178c2ecf20Sopenharmony_ci return; 55188c2ecf20Sopenharmony_ci 55198c2ecf20Sopenharmony_ci if (rdev->supply) { 55208c2ecf20Sopenharmony_ci while (rdev->use_count--) 55218c2ecf20Sopenharmony_ci regulator_disable(rdev->supply); 55228c2ecf20Sopenharmony_ci regulator_put(rdev->supply); 55238c2ecf20Sopenharmony_ci } 55248c2ecf20Sopenharmony_ci 55258c2ecf20Sopenharmony_ci flush_work(&rdev->disable_work.work); 55268c2ecf20Sopenharmony_ci 55278c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 55288c2ecf20Sopenharmony_ci 55298c2ecf20Sopenharmony_ci WARN_ON(rdev->open_count); 55308c2ecf20Sopenharmony_ci regulator_remove_coupling(rdev); 55318c2ecf20Sopenharmony_ci unset_regulator_supplies(rdev); 55328c2ecf20Sopenharmony_ci list_del(&rdev->list); 55338c2ecf20Sopenharmony_ci regulator_ena_gpio_free(rdev); 55348c2ecf20Sopenharmony_ci device_unregister(&rdev->dev); 55358c2ecf20Sopenharmony_ci 55368c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 55378c2ecf20Sopenharmony_ci} 55388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_unregister); 55398c2ecf20Sopenharmony_ci 55408c2ecf20Sopenharmony_ci#ifdef CONFIG_SUSPEND 55418c2ecf20Sopenharmony_ci/** 55428c2ecf20Sopenharmony_ci * regulator_suspend - prepare regulators for system wide suspend 55438c2ecf20Sopenharmony_ci * @dev: ``&struct device`` pointer that is passed to _regulator_suspend() 55448c2ecf20Sopenharmony_ci * 55458c2ecf20Sopenharmony_ci * Configure each regulator with it's suspend operating parameters for state. 55468c2ecf20Sopenharmony_ci */ 55478c2ecf20Sopenharmony_cistatic int regulator_suspend(struct device *dev) 55488c2ecf20Sopenharmony_ci{ 55498c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 55508c2ecf20Sopenharmony_ci suspend_state_t state = pm_suspend_target_state; 55518c2ecf20Sopenharmony_ci int ret; 55528c2ecf20Sopenharmony_ci const struct regulator_state *rstate; 55538c2ecf20Sopenharmony_ci 55548c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state_check(rdev, state); 55558c2ecf20Sopenharmony_ci if (!rstate) 55568c2ecf20Sopenharmony_ci return 0; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci regulator_lock(rdev); 55598c2ecf20Sopenharmony_ci ret = __suspend_set_state(rdev, rstate); 55608c2ecf20Sopenharmony_ci regulator_unlock(rdev); 55618c2ecf20Sopenharmony_ci 55628c2ecf20Sopenharmony_ci return ret; 55638c2ecf20Sopenharmony_ci} 55648c2ecf20Sopenharmony_ci 55658c2ecf20Sopenharmony_cistatic int regulator_resume(struct device *dev) 55668c2ecf20Sopenharmony_ci{ 55678c2ecf20Sopenharmony_ci suspend_state_t state = pm_suspend_target_state; 55688c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 55698c2ecf20Sopenharmony_ci struct regulator_state *rstate; 55708c2ecf20Sopenharmony_ci int ret = 0; 55718c2ecf20Sopenharmony_ci 55728c2ecf20Sopenharmony_ci rstate = regulator_get_suspend_state(rdev, state); 55738c2ecf20Sopenharmony_ci if (rstate == NULL) 55748c2ecf20Sopenharmony_ci return 0; 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_ci /* Avoid grabbing the lock if we don't need to */ 55778c2ecf20Sopenharmony_ci if (!rdev->desc->ops->resume) 55788c2ecf20Sopenharmony_ci return 0; 55798c2ecf20Sopenharmony_ci 55808c2ecf20Sopenharmony_ci regulator_lock(rdev); 55818c2ecf20Sopenharmony_ci 55828c2ecf20Sopenharmony_ci if (rstate->enabled == ENABLE_IN_SUSPEND || 55838c2ecf20Sopenharmony_ci rstate->enabled == DISABLE_IN_SUSPEND) 55848c2ecf20Sopenharmony_ci ret = rdev->desc->ops->resume(rdev); 55858c2ecf20Sopenharmony_ci 55868c2ecf20Sopenharmony_ci regulator_unlock(rdev); 55878c2ecf20Sopenharmony_ci 55888c2ecf20Sopenharmony_ci return ret; 55898c2ecf20Sopenharmony_ci} 55908c2ecf20Sopenharmony_ci#else /* !CONFIG_SUSPEND */ 55918c2ecf20Sopenharmony_ci 55928c2ecf20Sopenharmony_ci#define regulator_suspend NULL 55938c2ecf20Sopenharmony_ci#define regulator_resume NULL 55948c2ecf20Sopenharmony_ci 55958c2ecf20Sopenharmony_ci#endif /* !CONFIG_SUSPEND */ 55968c2ecf20Sopenharmony_ci 55978c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 55988c2ecf20Sopenharmony_cistatic const struct dev_pm_ops __maybe_unused regulator_pm_ops = { 55998c2ecf20Sopenharmony_ci .suspend = regulator_suspend, 56008c2ecf20Sopenharmony_ci .resume = regulator_resume, 56018c2ecf20Sopenharmony_ci}; 56028c2ecf20Sopenharmony_ci#endif 56038c2ecf20Sopenharmony_ci 56048c2ecf20Sopenharmony_cistruct class regulator_class = { 56058c2ecf20Sopenharmony_ci .name = "regulator", 56068c2ecf20Sopenharmony_ci .dev_release = regulator_dev_release, 56078c2ecf20Sopenharmony_ci .dev_groups = regulator_dev_groups, 56088c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 56098c2ecf20Sopenharmony_ci .pm = ®ulator_pm_ops, 56108c2ecf20Sopenharmony_ci#endif 56118c2ecf20Sopenharmony_ci}; 56128c2ecf20Sopenharmony_ci/** 56138c2ecf20Sopenharmony_ci * regulator_has_full_constraints - the system has fully specified constraints 56148c2ecf20Sopenharmony_ci * 56158c2ecf20Sopenharmony_ci * Calling this function will cause the regulator API to disable all 56168c2ecf20Sopenharmony_ci * regulators which have a zero use count and don't have an always_on 56178c2ecf20Sopenharmony_ci * constraint in a late_initcall. 56188c2ecf20Sopenharmony_ci * 56198c2ecf20Sopenharmony_ci * The intention is that this will become the default behaviour in a 56208c2ecf20Sopenharmony_ci * future kernel release so users are encouraged to use this facility 56218c2ecf20Sopenharmony_ci * now. 56228c2ecf20Sopenharmony_ci */ 56238c2ecf20Sopenharmony_civoid regulator_has_full_constraints(void) 56248c2ecf20Sopenharmony_ci{ 56258c2ecf20Sopenharmony_ci has_full_constraints = 1; 56268c2ecf20Sopenharmony_ci} 56278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_has_full_constraints); 56288c2ecf20Sopenharmony_ci 56298c2ecf20Sopenharmony_ci/** 56308c2ecf20Sopenharmony_ci * rdev_get_drvdata - get rdev regulator driver data 56318c2ecf20Sopenharmony_ci * @rdev: regulator 56328c2ecf20Sopenharmony_ci * 56338c2ecf20Sopenharmony_ci * Get rdev regulator driver private data. This call can be used in the 56348c2ecf20Sopenharmony_ci * regulator driver context. 56358c2ecf20Sopenharmony_ci */ 56368c2ecf20Sopenharmony_civoid *rdev_get_drvdata(struct regulator_dev *rdev) 56378c2ecf20Sopenharmony_ci{ 56388c2ecf20Sopenharmony_ci return rdev->reg_data; 56398c2ecf20Sopenharmony_ci} 56408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_drvdata); 56418c2ecf20Sopenharmony_ci 56428c2ecf20Sopenharmony_ci/** 56438c2ecf20Sopenharmony_ci * regulator_get_drvdata - get regulator driver data 56448c2ecf20Sopenharmony_ci * @regulator: regulator 56458c2ecf20Sopenharmony_ci * 56468c2ecf20Sopenharmony_ci * Get regulator driver private data. This call can be used in the consumer 56478c2ecf20Sopenharmony_ci * driver context when non API regulator specific functions need to be called. 56488c2ecf20Sopenharmony_ci */ 56498c2ecf20Sopenharmony_civoid *regulator_get_drvdata(struct regulator *regulator) 56508c2ecf20Sopenharmony_ci{ 56518c2ecf20Sopenharmony_ci return regulator->rdev->reg_data; 56528c2ecf20Sopenharmony_ci} 56538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_drvdata); 56548c2ecf20Sopenharmony_ci 56558c2ecf20Sopenharmony_ci/** 56568c2ecf20Sopenharmony_ci * regulator_set_drvdata - set regulator driver data 56578c2ecf20Sopenharmony_ci * @regulator: regulator 56588c2ecf20Sopenharmony_ci * @data: data 56598c2ecf20Sopenharmony_ci */ 56608c2ecf20Sopenharmony_civoid regulator_set_drvdata(struct regulator *regulator, void *data) 56618c2ecf20Sopenharmony_ci{ 56628c2ecf20Sopenharmony_ci regulator->rdev->reg_data = data; 56638c2ecf20Sopenharmony_ci} 56648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_set_drvdata); 56658c2ecf20Sopenharmony_ci 56668c2ecf20Sopenharmony_ci/** 56678c2ecf20Sopenharmony_ci * regulator_get_id - get regulator ID 56688c2ecf20Sopenharmony_ci * @rdev: regulator 56698c2ecf20Sopenharmony_ci */ 56708c2ecf20Sopenharmony_ciint rdev_get_id(struct regulator_dev *rdev) 56718c2ecf20Sopenharmony_ci{ 56728c2ecf20Sopenharmony_ci return rdev->desc->id; 56738c2ecf20Sopenharmony_ci} 56748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_id); 56758c2ecf20Sopenharmony_ci 56768c2ecf20Sopenharmony_cistruct device *rdev_get_dev(struct regulator_dev *rdev) 56778c2ecf20Sopenharmony_ci{ 56788c2ecf20Sopenharmony_ci return &rdev->dev; 56798c2ecf20Sopenharmony_ci} 56808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_dev); 56818c2ecf20Sopenharmony_ci 56828c2ecf20Sopenharmony_cistruct regmap *rdev_get_regmap(struct regulator_dev *rdev) 56838c2ecf20Sopenharmony_ci{ 56848c2ecf20Sopenharmony_ci return rdev->regmap; 56858c2ecf20Sopenharmony_ci} 56868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rdev_get_regmap); 56878c2ecf20Sopenharmony_ci 56888c2ecf20Sopenharmony_civoid *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data) 56898c2ecf20Sopenharmony_ci{ 56908c2ecf20Sopenharmony_ci return reg_init_data->driver_data; 56918c2ecf20Sopenharmony_ci} 56928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(regulator_get_init_drvdata); 56938c2ecf20Sopenharmony_ci 56948c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 56958c2ecf20Sopenharmony_cistatic int supply_map_show(struct seq_file *sf, void *data) 56968c2ecf20Sopenharmony_ci{ 56978c2ecf20Sopenharmony_ci struct regulator_map *map; 56988c2ecf20Sopenharmony_ci 56998c2ecf20Sopenharmony_ci list_for_each_entry(map, ®ulator_map_list, list) { 57008c2ecf20Sopenharmony_ci seq_printf(sf, "%s -> %s.%s\n", 57018c2ecf20Sopenharmony_ci rdev_get_name(map->regulator), map->dev_name, 57028c2ecf20Sopenharmony_ci map->supply); 57038c2ecf20Sopenharmony_ci } 57048c2ecf20Sopenharmony_ci 57058c2ecf20Sopenharmony_ci return 0; 57068c2ecf20Sopenharmony_ci} 57078c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(supply_map); 57088c2ecf20Sopenharmony_ci 57098c2ecf20Sopenharmony_cistruct summary_data { 57108c2ecf20Sopenharmony_ci struct seq_file *s; 57118c2ecf20Sopenharmony_ci struct regulator_dev *parent; 57128c2ecf20Sopenharmony_ci int level; 57138c2ecf20Sopenharmony_ci}; 57148c2ecf20Sopenharmony_ci 57158c2ecf20Sopenharmony_cistatic void regulator_summary_show_subtree(struct seq_file *s, 57168c2ecf20Sopenharmony_ci struct regulator_dev *rdev, 57178c2ecf20Sopenharmony_ci int level); 57188c2ecf20Sopenharmony_ci 57198c2ecf20Sopenharmony_cistatic int regulator_summary_show_children(struct device *dev, void *data) 57208c2ecf20Sopenharmony_ci{ 57218c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 57228c2ecf20Sopenharmony_ci struct summary_data *summary_data = data; 57238c2ecf20Sopenharmony_ci 57248c2ecf20Sopenharmony_ci if (rdev->supply && rdev->supply->rdev == summary_data->parent) 57258c2ecf20Sopenharmony_ci regulator_summary_show_subtree(summary_data->s, rdev, 57268c2ecf20Sopenharmony_ci summary_data->level + 1); 57278c2ecf20Sopenharmony_ci 57288c2ecf20Sopenharmony_ci return 0; 57298c2ecf20Sopenharmony_ci} 57308c2ecf20Sopenharmony_ci 57318c2ecf20Sopenharmony_cistatic void regulator_summary_show_subtree(struct seq_file *s, 57328c2ecf20Sopenharmony_ci struct regulator_dev *rdev, 57338c2ecf20Sopenharmony_ci int level) 57348c2ecf20Sopenharmony_ci{ 57358c2ecf20Sopenharmony_ci struct regulation_constraints *c; 57368c2ecf20Sopenharmony_ci struct regulator *consumer; 57378c2ecf20Sopenharmony_ci struct summary_data summary_data; 57388c2ecf20Sopenharmony_ci unsigned int opmode; 57398c2ecf20Sopenharmony_ci 57408c2ecf20Sopenharmony_ci if (!rdev) 57418c2ecf20Sopenharmony_ci return; 57428c2ecf20Sopenharmony_ci 57438c2ecf20Sopenharmony_ci opmode = _regulator_get_mode_unlocked(rdev); 57448c2ecf20Sopenharmony_ci seq_printf(s, "%*s%-*s %3d %4d %6d %7s ", 57458c2ecf20Sopenharmony_ci level * 3 + 1, "", 57468c2ecf20Sopenharmony_ci 30 - level * 3, rdev_get_name(rdev), 57478c2ecf20Sopenharmony_ci rdev->use_count, rdev->open_count, rdev->bypass_count, 57488c2ecf20Sopenharmony_ci regulator_opmode_to_str(opmode)); 57498c2ecf20Sopenharmony_ci 57508c2ecf20Sopenharmony_ci seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); 57518c2ecf20Sopenharmony_ci seq_printf(s, "%5dmA ", 57528c2ecf20Sopenharmony_ci _regulator_get_current_limit_unlocked(rdev) / 1000); 57538c2ecf20Sopenharmony_ci 57548c2ecf20Sopenharmony_ci c = rdev->constraints; 57558c2ecf20Sopenharmony_ci if (c) { 57568c2ecf20Sopenharmony_ci switch (rdev->desc->type) { 57578c2ecf20Sopenharmony_ci case REGULATOR_VOLTAGE: 57588c2ecf20Sopenharmony_ci seq_printf(s, "%5dmV %5dmV ", 57598c2ecf20Sopenharmony_ci c->min_uV / 1000, c->max_uV / 1000); 57608c2ecf20Sopenharmony_ci break; 57618c2ecf20Sopenharmony_ci case REGULATOR_CURRENT: 57628c2ecf20Sopenharmony_ci seq_printf(s, "%5dmA %5dmA ", 57638c2ecf20Sopenharmony_ci c->min_uA / 1000, c->max_uA / 1000); 57648c2ecf20Sopenharmony_ci break; 57658c2ecf20Sopenharmony_ci } 57668c2ecf20Sopenharmony_ci } 57678c2ecf20Sopenharmony_ci 57688c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 57698c2ecf20Sopenharmony_ci 57708c2ecf20Sopenharmony_ci list_for_each_entry(consumer, &rdev->consumer_list, list) { 57718c2ecf20Sopenharmony_ci if (consumer->dev && consumer->dev->class == ®ulator_class) 57728c2ecf20Sopenharmony_ci continue; 57738c2ecf20Sopenharmony_ci 57748c2ecf20Sopenharmony_ci seq_printf(s, "%*s%-*s ", 57758c2ecf20Sopenharmony_ci (level + 1) * 3 + 1, "", 57768c2ecf20Sopenharmony_ci 30 - (level + 1) * 3, 57778c2ecf20Sopenharmony_ci consumer->supply_name ? consumer->supply_name : 57788c2ecf20Sopenharmony_ci consumer->dev ? dev_name(consumer->dev) : "deviceless"); 57798c2ecf20Sopenharmony_ci 57808c2ecf20Sopenharmony_ci switch (rdev->desc->type) { 57818c2ecf20Sopenharmony_ci case REGULATOR_VOLTAGE: 57828c2ecf20Sopenharmony_ci seq_printf(s, "%3d %33dmA%c%5dmV %5dmV", 57838c2ecf20Sopenharmony_ci consumer->enable_count, 57848c2ecf20Sopenharmony_ci consumer->uA_load / 1000, 57858c2ecf20Sopenharmony_ci consumer->uA_load && !consumer->enable_count ? 57868c2ecf20Sopenharmony_ci '*' : ' ', 57878c2ecf20Sopenharmony_ci consumer->voltage[PM_SUSPEND_ON].min_uV / 1000, 57888c2ecf20Sopenharmony_ci consumer->voltage[PM_SUSPEND_ON].max_uV / 1000); 57898c2ecf20Sopenharmony_ci break; 57908c2ecf20Sopenharmony_ci case REGULATOR_CURRENT: 57918c2ecf20Sopenharmony_ci break; 57928c2ecf20Sopenharmony_ci } 57938c2ecf20Sopenharmony_ci 57948c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 57958c2ecf20Sopenharmony_ci } 57968c2ecf20Sopenharmony_ci 57978c2ecf20Sopenharmony_ci summary_data.s = s; 57988c2ecf20Sopenharmony_ci summary_data.level = level; 57998c2ecf20Sopenharmony_ci summary_data.parent = rdev; 58008c2ecf20Sopenharmony_ci 58018c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, &summary_data, 58028c2ecf20Sopenharmony_ci regulator_summary_show_children); 58038c2ecf20Sopenharmony_ci} 58048c2ecf20Sopenharmony_ci 58058c2ecf20Sopenharmony_cistruct summary_lock_data { 58068c2ecf20Sopenharmony_ci struct ww_acquire_ctx *ww_ctx; 58078c2ecf20Sopenharmony_ci struct regulator_dev **new_contended_rdev; 58088c2ecf20Sopenharmony_ci struct regulator_dev **old_contended_rdev; 58098c2ecf20Sopenharmony_ci}; 58108c2ecf20Sopenharmony_ci 58118c2ecf20Sopenharmony_cistatic int regulator_summary_lock_one(struct device *dev, void *data) 58128c2ecf20Sopenharmony_ci{ 58138c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 58148c2ecf20Sopenharmony_ci struct summary_lock_data *lock_data = data; 58158c2ecf20Sopenharmony_ci int ret = 0; 58168c2ecf20Sopenharmony_ci 58178c2ecf20Sopenharmony_ci if (rdev != *lock_data->old_contended_rdev) { 58188c2ecf20Sopenharmony_ci ret = regulator_lock_nested(rdev, lock_data->ww_ctx); 58198c2ecf20Sopenharmony_ci 58208c2ecf20Sopenharmony_ci if (ret == -EDEADLK) 58218c2ecf20Sopenharmony_ci *lock_data->new_contended_rdev = rdev; 58228c2ecf20Sopenharmony_ci else 58238c2ecf20Sopenharmony_ci WARN_ON_ONCE(ret); 58248c2ecf20Sopenharmony_ci } else { 58258c2ecf20Sopenharmony_ci *lock_data->old_contended_rdev = NULL; 58268c2ecf20Sopenharmony_ci } 58278c2ecf20Sopenharmony_ci 58288c2ecf20Sopenharmony_ci return ret; 58298c2ecf20Sopenharmony_ci} 58308c2ecf20Sopenharmony_ci 58318c2ecf20Sopenharmony_cistatic int regulator_summary_unlock_one(struct device *dev, void *data) 58328c2ecf20Sopenharmony_ci{ 58338c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 58348c2ecf20Sopenharmony_ci struct summary_lock_data *lock_data = data; 58358c2ecf20Sopenharmony_ci 58368c2ecf20Sopenharmony_ci if (lock_data) { 58378c2ecf20Sopenharmony_ci if (rdev == *lock_data->new_contended_rdev) 58388c2ecf20Sopenharmony_ci return -EDEADLK; 58398c2ecf20Sopenharmony_ci } 58408c2ecf20Sopenharmony_ci 58418c2ecf20Sopenharmony_ci regulator_unlock(rdev); 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_ci return 0; 58448c2ecf20Sopenharmony_ci} 58458c2ecf20Sopenharmony_ci 58468c2ecf20Sopenharmony_cistatic int regulator_summary_lock_all(struct ww_acquire_ctx *ww_ctx, 58478c2ecf20Sopenharmony_ci struct regulator_dev **new_contended_rdev, 58488c2ecf20Sopenharmony_ci struct regulator_dev **old_contended_rdev) 58498c2ecf20Sopenharmony_ci{ 58508c2ecf20Sopenharmony_ci struct summary_lock_data lock_data; 58518c2ecf20Sopenharmony_ci int ret; 58528c2ecf20Sopenharmony_ci 58538c2ecf20Sopenharmony_ci lock_data.ww_ctx = ww_ctx; 58548c2ecf20Sopenharmony_ci lock_data.new_contended_rdev = new_contended_rdev; 58558c2ecf20Sopenharmony_ci lock_data.old_contended_rdev = old_contended_rdev; 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci ret = class_for_each_device(®ulator_class, NULL, &lock_data, 58588c2ecf20Sopenharmony_ci regulator_summary_lock_one); 58598c2ecf20Sopenharmony_ci if (ret) 58608c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, &lock_data, 58618c2ecf20Sopenharmony_ci regulator_summary_unlock_one); 58628c2ecf20Sopenharmony_ci 58638c2ecf20Sopenharmony_ci return ret; 58648c2ecf20Sopenharmony_ci} 58658c2ecf20Sopenharmony_ci 58668c2ecf20Sopenharmony_cistatic void regulator_summary_lock(struct ww_acquire_ctx *ww_ctx) 58678c2ecf20Sopenharmony_ci{ 58688c2ecf20Sopenharmony_ci struct regulator_dev *new_contended_rdev = NULL; 58698c2ecf20Sopenharmony_ci struct regulator_dev *old_contended_rdev = NULL; 58708c2ecf20Sopenharmony_ci int err; 58718c2ecf20Sopenharmony_ci 58728c2ecf20Sopenharmony_ci mutex_lock(®ulator_list_mutex); 58738c2ecf20Sopenharmony_ci 58748c2ecf20Sopenharmony_ci ww_acquire_init(ww_ctx, ®ulator_ww_class); 58758c2ecf20Sopenharmony_ci 58768c2ecf20Sopenharmony_ci do { 58778c2ecf20Sopenharmony_ci if (new_contended_rdev) { 58788c2ecf20Sopenharmony_ci ww_mutex_lock_slow(&new_contended_rdev->mutex, ww_ctx); 58798c2ecf20Sopenharmony_ci old_contended_rdev = new_contended_rdev; 58808c2ecf20Sopenharmony_ci old_contended_rdev->ref_cnt++; 58818c2ecf20Sopenharmony_ci old_contended_rdev->mutex_owner = current; 58828c2ecf20Sopenharmony_ci } 58838c2ecf20Sopenharmony_ci 58848c2ecf20Sopenharmony_ci err = regulator_summary_lock_all(ww_ctx, 58858c2ecf20Sopenharmony_ci &new_contended_rdev, 58868c2ecf20Sopenharmony_ci &old_contended_rdev); 58878c2ecf20Sopenharmony_ci 58888c2ecf20Sopenharmony_ci if (old_contended_rdev) 58898c2ecf20Sopenharmony_ci regulator_unlock(old_contended_rdev); 58908c2ecf20Sopenharmony_ci 58918c2ecf20Sopenharmony_ci } while (err == -EDEADLK); 58928c2ecf20Sopenharmony_ci 58938c2ecf20Sopenharmony_ci ww_acquire_done(ww_ctx); 58948c2ecf20Sopenharmony_ci} 58958c2ecf20Sopenharmony_ci 58968c2ecf20Sopenharmony_cistatic void regulator_summary_unlock(struct ww_acquire_ctx *ww_ctx) 58978c2ecf20Sopenharmony_ci{ 58988c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 58998c2ecf20Sopenharmony_ci regulator_summary_unlock_one); 59008c2ecf20Sopenharmony_ci ww_acquire_fini(ww_ctx); 59018c2ecf20Sopenharmony_ci 59028c2ecf20Sopenharmony_ci mutex_unlock(®ulator_list_mutex); 59038c2ecf20Sopenharmony_ci} 59048c2ecf20Sopenharmony_ci 59058c2ecf20Sopenharmony_cistatic int regulator_summary_show_roots(struct device *dev, void *data) 59068c2ecf20Sopenharmony_ci{ 59078c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 59088c2ecf20Sopenharmony_ci struct seq_file *s = data; 59098c2ecf20Sopenharmony_ci 59108c2ecf20Sopenharmony_ci if (!rdev->supply) 59118c2ecf20Sopenharmony_ci regulator_summary_show_subtree(s, rdev, 0); 59128c2ecf20Sopenharmony_ci 59138c2ecf20Sopenharmony_ci return 0; 59148c2ecf20Sopenharmony_ci} 59158c2ecf20Sopenharmony_ci 59168c2ecf20Sopenharmony_cistatic int regulator_summary_show(struct seq_file *s, void *data) 59178c2ecf20Sopenharmony_ci{ 59188c2ecf20Sopenharmony_ci struct ww_acquire_ctx ww_ctx; 59198c2ecf20Sopenharmony_ci 59208c2ecf20Sopenharmony_ci seq_puts(s, " regulator use open bypass opmode voltage current min max\n"); 59218c2ecf20Sopenharmony_ci seq_puts(s, "---------------------------------------------------------------------------------------\n"); 59228c2ecf20Sopenharmony_ci 59238c2ecf20Sopenharmony_ci regulator_summary_lock(&ww_ctx); 59248c2ecf20Sopenharmony_ci 59258c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, s, 59268c2ecf20Sopenharmony_ci regulator_summary_show_roots); 59278c2ecf20Sopenharmony_ci 59288c2ecf20Sopenharmony_ci regulator_summary_unlock(&ww_ctx); 59298c2ecf20Sopenharmony_ci 59308c2ecf20Sopenharmony_ci return 0; 59318c2ecf20Sopenharmony_ci} 59328c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(regulator_summary); 59338c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 59348c2ecf20Sopenharmony_ci 59358c2ecf20Sopenharmony_cistatic int __init regulator_init(void) 59368c2ecf20Sopenharmony_ci{ 59378c2ecf20Sopenharmony_ci int ret; 59388c2ecf20Sopenharmony_ci 59398c2ecf20Sopenharmony_ci ret = class_register(®ulator_class); 59408c2ecf20Sopenharmony_ci 59418c2ecf20Sopenharmony_ci debugfs_root = debugfs_create_dir("regulator", NULL); 59428c2ecf20Sopenharmony_ci if (IS_ERR(debugfs_root)) 59438c2ecf20Sopenharmony_ci pr_debug("regulator: Failed to create debugfs directory\n"); 59448c2ecf20Sopenharmony_ci 59458c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 59468c2ecf20Sopenharmony_ci debugfs_create_file("supply_map", 0444, debugfs_root, NULL, 59478c2ecf20Sopenharmony_ci &supply_map_fops); 59488c2ecf20Sopenharmony_ci 59498c2ecf20Sopenharmony_ci debugfs_create_file("regulator_summary", 0444, debugfs_root, 59508c2ecf20Sopenharmony_ci NULL, ®ulator_summary_fops); 59518c2ecf20Sopenharmony_ci#endif 59528c2ecf20Sopenharmony_ci regulator_dummy_init(); 59538c2ecf20Sopenharmony_ci 59548c2ecf20Sopenharmony_ci regulator_coupler_register(&generic_regulator_coupler); 59558c2ecf20Sopenharmony_ci 59568c2ecf20Sopenharmony_ci return ret; 59578c2ecf20Sopenharmony_ci} 59588c2ecf20Sopenharmony_ci 59598c2ecf20Sopenharmony_ci/* init early to allow our consumers to complete system booting */ 59608c2ecf20Sopenharmony_cicore_initcall(regulator_init); 59618c2ecf20Sopenharmony_ci 59628c2ecf20Sopenharmony_cistatic int regulator_late_cleanup(struct device *dev, void *data) 59638c2ecf20Sopenharmony_ci{ 59648c2ecf20Sopenharmony_ci struct regulator_dev *rdev = dev_to_rdev(dev); 59658c2ecf20Sopenharmony_ci struct regulation_constraints *c = rdev->constraints; 59668c2ecf20Sopenharmony_ci int ret; 59678c2ecf20Sopenharmony_ci 59688c2ecf20Sopenharmony_ci if (c && c->always_on) 59698c2ecf20Sopenharmony_ci return 0; 59708c2ecf20Sopenharmony_ci 59718c2ecf20Sopenharmony_ci if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) 59728c2ecf20Sopenharmony_ci return 0; 59738c2ecf20Sopenharmony_ci 59748c2ecf20Sopenharmony_ci regulator_lock(rdev); 59758c2ecf20Sopenharmony_ci 59768c2ecf20Sopenharmony_ci if (rdev->use_count) 59778c2ecf20Sopenharmony_ci goto unlock; 59788c2ecf20Sopenharmony_ci 59798c2ecf20Sopenharmony_ci /* If reading the status failed, assume that it's off. */ 59808c2ecf20Sopenharmony_ci if (_regulator_is_enabled(rdev) <= 0) 59818c2ecf20Sopenharmony_ci goto unlock; 59828c2ecf20Sopenharmony_ci 59838c2ecf20Sopenharmony_ci if (have_full_constraints()) { 59848c2ecf20Sopenharmony_ci /* We log since this may kill the system if it goes 59858c2ecf20Sopenharmony_ci * wrong. */ 59868c2ecf20Sopenharmony_ci rdev_info(rdev, "disabling\n"); 59878c2ecf20Sopenharmony_ci ret = _regulator_do_disable(rdev); 59888c2ecf20Sopenharmony_ci if (ret != 0) 59898c2ecf20Sopenharmony_ci rdev_err(rdev, "couldn't disable: %pe\n", ERR_PTR(ret)); 59908c2ecf20Sopenharmony_ci } else { 59918c2ecf20Sopenharmony_ci /* The intention is that in future we will 59928c2ecf20Sopenharmony_ci * assume that full constraints are provided 59938c2ecf20Sopenharmony_ci * so warn even if we aren't going to do 59948c2ecf20Sopenharmony_ci * anything here. 59958c2ecf20Sopenharmony_ci */ 59968c2ecf20Sopenharmony_ci rdev_warn(rdev, "incomplete constraints, leaving on\n"); 59978c2ecf20Sopenharmony_ci } 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ciunlock: 60008c2ecf20Sopenharmony_ci regulator_unlock(rdev); 60018c2ecf20Sopenharmony_ci 60028c2ecf20Sopenharmony_ci return 0; 60038c2ecf20Sopenharmony_ci} 60048c2ecf20Sopenharmony_ci 60058c2ecf20Sopenharmony_cistatic void regulator_init_complete_work_function(struct work_struct *work) 60068c2ecf20Sopenharmony_ci{ 60078c2ecf20Sopenharmony_ci /* 60088c2ecf20Sopenharmony_ci * Regulators may had failed to resolve their input supplies 60098c2ecf20Sopenharmony_ci * when were registered, either because the input supply was 60108c2ecf20Sopenharmony_ci * not registered yet or because its parent device was not 60118c2ecf20Sopenharmony_ci * bound yet. So attempt to resolve the input supplies for 60128c2ecf20Sopenharmony_ci * pending regulators before trying to disable unused ones. 60138c2ecf20Sopenharmony_ci */ 60148c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 60158c2ecf20Sopenharmony_ci regulator_register_resolve_supply); 60168c2ecf20Sopenharmony_ci 60178c2ecf20Sopenharmony_ci /* If we have a full configuration then disable any regulators 60188c2ecf20Sopenharmony_ci * we have permission to change the status for and which are 60198c2ecf20Sopenharmony_ci * not in use or always_on. This is effectively the default 60208c2ecf20Sopenharmony_ci * for DT and ACPI as they have full constraints. 60218c2ecf20Sopenharmony_ci */ 60228c2ecf20Sopenharmony_ci class_for_each_device(®ulator_class, NULL, NULL, 60238c2ecf20Sopenharmony_ci regulator_late_cleanup); 60248c2ecf20Sopenharmony_ci} 60258c2ecf20Sopenharmony_ci 60268c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(regulator_init_complete_work, 60278c2ecf20Sopenharmony_ci regulator_init_complete_work_function); 60288c2ecf20Sopenharmony_ci 60298c2ecf20Sopenharmony_cistatic int __init regulator_init_complete(void) 60308c2ecf20Sopenharmony_ci{ 60318c2ecf20Sopenharmony_ci /* 60328c2ecf20Sopenharmony_ci * Since DT doesn't provide an idiomatic mechanism for 60338c2ecf20Sopenharmony_ci * enabling full constraints and since it's much more natural 60348c2ecf20Sopenharmony_ci * with DT to provide them just assume that a DT enabled 60358c2ecf20Sopenharmony_ci * system has full constraints. 60368c2ecf20Sopenharmony_ci */ 60378c2ecf20Sopenharmony_ci if (of_have_populated_dt()) 60388c2ecf20Sopenharmony_ci has_full_constraints = true; 60398c2ecf20Sopenharmony_ci 60408c2ecf20Sopenharmony_ci /* 60418c2ecf20Sopenharmony_ci * We punt completion for an arbitrary amount of time since 60428c2ecf20Sopenharmony_ci * systems like distros will load many drivers from userspace 60438c2ecf20Sopenharmony_ci * so consumers might not always be ready yet, this is 60448c2ecf20Sopenharmony_ci * particularly an issue with laptops where this might bounce 60458c2ecf20Sopenharmony_ci * the display off then on. Ideally we'd get a notification 60468c2ecf20Sopenharmony_ci * from userspace when this happens but we don't so just wait 60478c2ecf20Sopenharmony_ci * a bit and hope we waited long enough. It'd be better if 60488c2ecf20Sopenharmony_ci * we'd only do this on systems that need it, and a kernel 60498c2ecf20Sopenharmony_ci * command line option might be useful. 60508c2ecf20Sopenharmony_ci */ 60518c2ecf20Sopenharmony_ci schedule_delayed_work(®ulator_init_complete_work, 60528c2ecf20Sopenharmony_ci msecs_to_jiffies(30000)); 60538c2ecf20Sopenharmony_ci 60548c2ecf20Sopenharmony_ci return 0; 60558c2ecf20Sopenharmony_ci} 60568c2ecf20Sopenharmony_cilate_initcall_sync(regulator_init_complete); 6057